{"openapi":"3.1.0","info":{"title":"MergeWiFi Partner API","version":"1.0.0","contact":{"name":"MergeWiFi Support","email":"support@mergewifi.com"},"description":"Server-to-server API for MergeWiFi partners. **Early beta.**\n\nEndpoints marked available are implemented, tested and safe to build against. We will not remove or rename a field on an available endpoint without telling you first.\n\nCoverage is still growing and response times are not yet under an SLA. Please tell us what you need next — it genuinely changes the order we build in.\n\n**Authentication.** Every request needs `Authorization: Bearer <key>`. Keys are\nprefixed `mwf_live_` or `mwf_test_`. They are shown once at creation and stored\nonly as a hash, so a lost key is replaced rather than recovered. Keys must never\nbe used from browser code — this API sets no CORS headers by design.\n\n**Errors.** Every non-2xx response uses one envelope and carries a `request_id`,\nalso returned in the `x-request-id` header. Quote it in support requests.\n\n**Rate limits.** Per key, reported on every response via `X-RateLimit-Limit`,\n`X-RateLimit-Remaining`, and `X-RateLimit-Reset`. A 429 includes `Retry-After`."},"servers":[{"url":"https://api.mergewifi.com","description":"Production"}],"security":[{"bearerAuth":[]}],"tags":[{"name":"Authentication"},{"name":"Catalog"},{"name":"Orders"},{"name":"Devices"},{"name":"Device networking"},{"name":"Device diagnostics"},{"name":"Quotes"},{"name":"Customers"},{"name":"Checkout"}],"paths":{"/v1/me":{"get":{"operationId":"getApiKeyContext","summary":"Describe the current API key","description":"Returns the organization, environment, and scopes the presented key carries. Requires no scopes of its own, so a misconfigured key still gets a useful answer instead of a 403.","tags":["Authentication"],"security":[{"bearerAuth":[]}],"parameters":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"object":{"type":"string","const":"api_key_context"},"organization_id":{"type":"string"},"environment":{"type":"string","enum":["live","test"]},"scopes":{"type":"array","items":{"type":"string"}}},"required":["object","organization_id","environment","scopes"],"additionalProperties":false,"id":"ApiKeyContext"},"example":{"object":"api_key_context","organization_id":"org_2xK9fLmQpR4sT7vW","environment":"live","scopes":["catalog:read","orders:read","orders:write"]}}}},"400":{"description":"Malformed request — see `error.param`.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"401":{"description":"Missing, invalid, revoked, or expired API key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"403":{"description":"The key lacks a required scope, or the organization is not entitled.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"429":{"description":"Rate limit exceeded. Honour the `Retry-After` header.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"500":{"description":"Unexpected error. Quote `request_id` when reporting it.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}}}}},"/v1/products":{"get":{"operationId":"listProducts","summary":"List orderable products","description":"The hardware available to your organization, with your pricing. Returned in full rather than paginated, so one request gives you everything you need to build a product picker. Use a product `id` from here when placing an order.","tags":["Catalog"],"security":[{"bearerAuth":["catalog:read"]}],"parameters":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"object":{"type":"string","const":"list"},"data":{"type":"array","items":{"$ref":"#/$defs/Product"}},"has_more":{"type":"boolean"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Pass as `starting_after` for the next page."}},"required":["object","data","has_more","next_cursor"],"additionalProperties":false,"id":"ProductList","$defs":{"Product":{"type":"object","properties":{"object":{"type":"string","const":"product"},"id":{"type":"string","description":"Stable string id, even where the source is numeric."},"sku":{"type":"string"},"name":{"type":"string"},"price":{"type":"string","description":"Decimal string, not a float.","example":"199.99"},"category":{"anyOf":[{"type":"string"},{"type":"null"}]},"product_type":{"anyOf":[{"type":"string"},{"type":"null"}]},"image_url":{"anyOf":[{"type":"string"},{"type":"null"}]},"thumbnail_url":{"anyOf":[{"type":"string"},{"type":"null"}]},"attributes":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string"},"value":{"type":"string"}},"required":["title","value"],"additionalProperties":false}},"equipment_as_a_service":{"type":"boolean","description":"No upfront charge; must be sold with a plan."},"lease":{"type":"boolean","description":"Leased equipment: `price` is charged every month with the plan, not once. Must be sold with a plan; the package always ships hot."},"variants":{"description":"Billing/condition versions of the same hardware. Absent when none.","type":"array","items":{"$ref":"#/$defs/ProductVariant"}}},"required":["object","id","sku","name","price","category","product_type","image_url","thumbnail_url","attributes","equipment_as_a_service","lease"],"additionalProperties":false,"id":"Product"},"ProductVariant":{"type":"object","properties":{"object":{"type":"string","const":"product"},"id":{"type":"string","description":"Stable string id, even where the source is numeric."},"sku":{"type":"string"},"name":{"type":"string"},"price":{"type":"string","description":"Decimal string, not a float.","example":"199.99"},"category":{"anyOf":[{"type":"string"},{"type":"null"}]},"product_type":{"anyOf":[{"type":"string"},{"type":"null"}]},"image_url":{"anyOf":[{"type":"string"},{"type":"null"}]},"thumbnail_url":{"anyOf":[{"type":"string"},{"type":"null"}]},"attributes":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string"},"value":{"type":"string"}},"required":["title","value"],"additionalProperties":false}},"equipment_as_a_service":{"type":"boolean","description":"No upfront charge; must be sold with a plan."},"lease":{"type":"boolean","description":"Leased equipment: `price` is charged every month with the plan, not once. Must be sold with a plan; the package always ships hot."}},"required":["object","id","sku","name","price","category","product_type","image_url","thumbnail_url","attributes","equipment_as_a_service","lease"],"additionalProperties":false,"id":"ProductVariant"}}},"example":{"object":"list","data":[{"object":"product","id":"1","sku":"M-11","name":"MergeWiFi Mini","price":"199.99","category":"physical","product_type":"Router","image_url":"https://images.mergewifi.com/products/m-11-medium.png","thumbnail_url":"https://images.mergewifi.com/products/m-11-thumb.png","attributes":[{"title":"Connectivity","value":"LTE Cat 4"},{"title":"Ethernet ports","value":"1"}],"equipment_as_a_service":false,"lease":false,"variants":[{"object":"product","id":"42","sku":"EAAS-M11","name":"MergeWiFi Mini","price":"0.00","category":"physical","product_type":"Router","image_url":"https://images.mergewifi.com/products/m-11-medium.png","thumbnail_url":"https://images.mergewifi.com/products/m-11-thumb.png","attributes":[{"title":"Connectivity","value":"LTE Cat 4"},{"title":"Ethernet ports","value":"1"}],"equipment_as_a_service":true,"lease":false}]}],"has_more":false,"next_cursor":null}}}},"400":{"description":"Malformed request — see `error.param`.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"401":{"description":"Missing, invalid, revoked, or expired API key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"403":{"description":"The key lacks a required scope, or the organization is not entitled.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"429":{"description":"Rate limit exceeded. Honour the `Retry-After` header.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"500":{"description":"Unexpected error. Quote `request_id` when reporting it.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"503":{"description":"An upstream dependency is unavailable. Retry shortly.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}}}}},"/v1/orders":{"get":{"operationId":"listOrders","summary":"List orders","description":"Your organization's orders, newest first. Line items are omitted to keep responses small — fetch a single order to see them.","tags":["Orders"],"security":[{"bearerAuth":["orders:read"]}],"parameters":[{"name":"limit","in":"query","required":false,"description":"Rows to return, 1–100. Defaults to 25. Out-of-range values are rejected rather than clamped, so a client cannot silently receive fewer rows than it asked for.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","default":25,"type":"integer","minimum":1,"maximum":100}},{"name":"starting_after","in":"query","required":false,"description":"Opaque cursor from a previous response's `next_cursor`. Cursors rather than page numbers: rows inserted between requests would shift an offset and silently skip records.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}},{"name":"status","in":"query","required":false,"description":"Exact match on order status, e.g. `pending`, `processing`, `cancelled`.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}},{"name":"order_type","in":"query","required":false,"description":"Exact match, e.g. `residential`, `business`, `iot`, `wholesale`. Orders placed in the Partner Portal may carry other values, so this is matched literally rather than restricted to a fixed list — a value with no matches returns an empty list rather than an error.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"object":{"type":"string","const":"list"},"data":{"type":"array","items":{"$ref":"#/$defs/Order"}},"has_more":{"type":"boolean"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Pass as `starting_after` for the next page."}},"required":["object","data","has_more","next_cursor"],"additionalProperties":false,"id":"OrderList","$defs":{"Order":{"type":"object","properties":{"object":{"type":"string","const":"order"},"id":{"type":"string"},"order_type":{"type":"string","description":"The order's category, e.g. `residential`, `business`, `iot`, `wholesale`. Orders created in the Partner Portal may carry other values, so treat this as a label rather than a fixed set."},"order_mode":{"type":"string","description":"`bulk` for hardware orders like those placed through this API; `pos` for point-of-sale orders taken in the Partner Portal."},"status":{"type":"string"},"payment_status":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Where a card-paid order sits in payment. Null for invoiced orders, which carry no payment record."},"customer":{"type":"object","properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"anyOf":[{"type":"string"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["name","email","phone"],"additionalProperties":false},"shipping_address":{"description":"Address object as captured at order time."},"fulfillment_type":{"anyOf":[{"type":"string"},{"type":"null"}]},"subtotal":{"anyOf":[{"type":"number"},{"type":"null"}]},"tax":{"anyOf":[{"type":"number"},{"type":"null"}]},"tax_basis":{"anyOf":[{"type":"string","enum":["destination","flat_rate"]},{"type":"null"}],"description":"How `tax` was worked out. `destination` means calculated for the shipping address. `flat_rate` means a flat 8.25% was applied and does NOT vary by destination — check this before reconciling tax against your own records."},"total":{"anyOf":[{"type":"number"},{"type":"null"}]},"total_due_upfront":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"The amount actually charged at checkout, for card-paid orders."},"payment_method":{"anyOf":[{"type":"object","properties":{"brand":{"anyOf":[{"type":"string"},{"type":"null"}]},"last4":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["brand","last4"],"additionalProperties":false},{"type":"null"}]},"notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"billing_reference":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Our fulfillment reference for this order, when one exists. Worth quoting when you contact support about an order."},"billing_status":{"anyOf":[{"type":"string"},{"type":"null"}]},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}]},"submitted_at":{"anyOf":[{"type":"string"},{"type":"null"}]},"completed_at":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["object","id","order_type","order_mode","status","payment_status","customer","shipping_address","fulfillment_type","subtotal","tax","tax_basis","total","total_due_upfront","payment_method","notes","billing_reference","billing_status","created_at","submitted_at","completed_at"],"additionalProperties":false,"id":"Order"}}},"example":{"object":"list","data":[{"object":"order","id":"8f14e45f-ceea-4a0b-9c1f-2d3b4a5c6d7e","order_type":"iot","order_mode":"bulk","status":"pending","payment_status":null,"customer":{"name":"Acme Logistics","email":"ops@acme.example","phone":"5125550100"},"shipping_address":{"line1":"100 Congress Ave","city":"Austin","state":"TX","postal_code":"78701"},"fulfillment_type":"dropship","subtotal":399.98,"tax":33,"tax_basis":"flat_rate","total":432.98,"total_due_upfront":null,"payment_method":null,"notes":null,"billing_reference":null,"billing_status":null,"created_at":"2026-07-30T17:12:04.000Z","submitted_at":"2026-07-30T17:12:04.000Z","completed_at":null}],"has_more":true,"next_cursor":"eyJpZCI6IjhmMTRlNDVmIiwidHMiOjE3ODU0MzIwMDAwMDB9"}}}},"400":{"description":"Malformed request — see `error.param`.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"401":{"description":"Missing, invalid, revoked, or expired API key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"403":{"description":"The key lacks a required scope, or the organization is not entitled.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"429":{"description":"Rate limit exceeded. Honour the `Retry-After` header.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"500":{"description":"Unexpected error. Quote `request_id` when reporting it.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}}}}},"/v1/orders/{id}":{"get":{"operationId":"getOrder","summary":"Retrieve an order","description":"A single order with its line items, including any devices and plans on it. Orders are scoped to your organization — an id you do not own returns a 404.","tags":["Orders"],"security":[{"bearerAuth":["orders:read"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"The order id.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"object":{"type":"string","const":"order"},"id":{"type":"string"},"order_type":{"type":"string","description":"The order's category, e.g. `residential`, `business`, `iot`, `wholesale`. Orders created in the Partner Portal may carry other values, so treat this as a label rather than a fixed set."},"order_mode":{"type":"string","description":"`bulk` for hardware orders like those placed through this API; `pos` for point-of-sale orders taken in the Partner Portal."},"status":{"type":"string"},"payment_status":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Where a card-paid order sits in payment. Null for invoiced orders, which carry no payment record."},"customer":{"type":"object","properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"anyOf":[{"type":"string"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["name","email","phone"],"additionalProperties":false},"shipping_address":{"description":"Address object as captured at order time."},"fulfillment_type":{"anyOf":[{"type":"string"},{"type":"null"}]},"subtotal":{"anyOf":[{"type":"number"},{"type":"null"}]},"tax":{"anyOf":[{"type":"number"},{"type":"null"}]},"tax_basis":{"anyOf":[{"type":"string","enum":["destination","flat_rate"]},{"type":"null"}],"description":"How `tax` was worked out. `destination` means calculated for the shipping address. `flat_rate` means a flat 8.25% was applied and does NOT vary by destination — check this before reconciling tax against your own records."},"total":{"anyOf":[{"type":"number"},{"type":"null"}]},"total_due_upfront":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"The amount actually charged at checkout, for card-paid orders."},"payment_method":{"anyOf":[{"type":"object","properties":{"brand":{"anyOf":[{"type":"string"},{"type":"null"}]},"last4":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["brand","last4"],"additionalProperties":false},{"type":"null"}]},"notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"billing_reference":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Our fulfillment reference for this order, when one exists. Worth quoting when you contact support about an order."},"billing_status":{"anyOf":[{"type":"string"},{"type":"null"}]},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}]},"submitted_at":{"anyOf":[{"type":"string"},{"type":"null"}]},"completed_at":{"anyOf":[{"type":"string"},{"type":"null"}]},"line_items":{"type":"array","items":{"$ref":"#/$defs/OrderItem"}}},"required":["object","id","order_type","order_mode","status","payment_status","customer","shipping_address","fulfillment_type","subtotal","tax","tax_basis","total","total_due_upfront","payment_method","notes","billing_reference","billing_status","created_at","submitted_at","completed_at","line_items"],"additionalProperties":false,"id":"OrderDetail","$defs":{"OrderItem":{"type":"object","properties":{"kind":{"type":"string","enum":["device","plan","addon","item"],"description":"`device`, `plan` and `addon` appear on point-of-sale orders; `item` on hardware orders placed through this API."},"sku":{"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"type":"string"},"quantity":{"type":"number"},"unit_price":{"type":"number"},"serial":{"type":"string"},"iccid":{"type":"string"}},"required":["kind","sku","name","quantity","unit_price"],"additionalProperties":false,"id":"OrderItem"}}},"example":{"object":"order","id":"8f14e45f-ceea-4a0b-9c1f-2d3b4a5c6d7e","order_type":"iot","order_mode":"bulk","status":"pending","payment_status":null,"customer":{"name":"Acme Logistics","email":"ops@acme.example","phone":"5125550100"},"shipping_address":{"line1":"100 Congress Ave","city":"Austin","state":"TX","postal_code":"78701"},"fulfillment_type":"dropship","subtotal":399.98,"tax":33,"tax_basis":"flat_rate","total":432.98,"total_due_upfront":null,"payment_method":null,"notes":null,"billing_reference":null,"billing_status":null,"created_at":"2026-07-30T17:12:04.000Z","submitted_at":"2026-07-30T17:12:04.000Z","completed_at":null,"line_items":[{"kind":"item","sku":"M-11","name":"MergeWiFi Mini","quantity":2,"unit_price":199.99}]}}}},"400":{"description":"Malformed request — see `error.param`.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"401":{"description":"Missing, invalid, revoked, or expired API key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"403":{"description":"The key lacks a required scope, or the organization is not entitled.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"404":{"description":"No such resource.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"429":{"description":"Rate limit exceeded. Honour the `Retry-After` header.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"500":{"description":"Unexpected error. Quote `request_id` when reporting it.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}}}}},"/v1/plans":{"get":{"operationId":"listPlans","summary":"List service plans","description":"The service plans available to your organization to sell alongside hardware, with their monthly pricing. Returned in full rather than paginated, like the product catalog — one request gives you everything needed to build a picker.","tags":["Catalog"],"security":[{"bearerAuth":["catalog:read"]}],"parameters":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"object":{"type":"string","const":"list"},"data":{"type":"array","items":{"$ref":"#/$defs/Plan"}},"has_more":{"type":"boolean"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Pass as `starting_after` for the next page."}},"required":["object","data","has_more","next_cursor"],"additionalProperties":false,"id":"PlanList","$defs":{"Plan":{"type":"object","properties":{"object":{"type":"string","const":"plan"},"id":{"type":"string"},"name":{"type":"string"},"kind":{"anyOf":[{"type":"string"},{"type":"null"}]},"monthly_price":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Decimal string, not a float.","example":"29.99"},"currency":{"type":"string","const":"USD"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["object","id","name","kind","monthly_price","currency","description"],"additionalProperties":false,"id":"Plan"}}},"example":{"object":"list","data":[{"object":"plan","id":"17","name":"IoT 5GB Monthly","kind":"plan","monthly_price":"29.99","currency":"USD","description":"5GB of data per month on the nationwide network."}],"has_more":false,"next_cursor":null}}}},"400":{"description":"Malformed request — see `error.param`.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"401":{"description":"Missing, invalid, revoked, or expired API key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"403":{"description":"The key lacks a required scope, or the organization is not entitled.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"429":{"description":"Rate limit exceeded. Honour the `Retry-After` header.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"500":{"description":"Unexpected error. Quote `request_id` when reporting it.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"503":{"description":"An upstream dependency is unavailable. Retry shortly.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}}}}},"/v1/devices":{"get":{"operationId":"listDevices","summary":"List devices","description":"The devices on your account, newest first. Filter with `activated`, `reachable`, `serial`, `data_plan`, `model`, or free text via `q`.\n\nRows reflect the most recent inventory sync, so a device added in the last few minutes may not appear yet; retrieving a device by id always reads current state. Usage is reported in **bytes**.","tags":["Devices"],"security":[{"bearerAuth":["devices:read"]}],"parameters":[{"name":"limit","in":"query","required":false,"description":"Rows to return, 1–100. Defaults to 25. Out-of-range values are rejected rather than clamped, so a client cannot silently receive fewer rows than it asked for.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","default":25,"type":"integer","minimum":1,"maximum":100}},{"name":"starting_after","in":"query","required":false,"description":"Opaque cursor from a previous response's `next_cursor`. Cursors rather than page numbers: rows inserted between requests would shift an offset and silently skip records.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}},{"name":"activated","in":"query","required":false,"description":"`true` or `false`. Omit for both.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"boolean"}},{"name":"reachable","in":"query","required":false,"description":"`true` or `false`. Reachability is independent of activation — a device can be activated and powered off.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"boolean"}},{"name":"serial","in":"query","required":false,"description":"Exact match on the device serial.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}},{"name":"data_plan","in":"query","required":false,"description":"Exact match on the plan name, or `unassigned` for devices with none.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}},{"name":"model","in":"query","required":false,"description":"Exact match on the hardware model.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}},{"name":"q","in":"query","required":false,"description":"Free-text search across serial, label, and id.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"object":{"type":"string","const":"list"},"data":{"type":"array","items":{"$ref":"#/$defs/Device"}},"has_more":{"type":"boolean"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Pass as `starting_after` for the next page."}},"required":["object","data","has_more","next_cursor"],"additionalProperties":false,"id":"DeviceList","$defs":{"Device":{"type":"object","properties":{"object":{"type":"string","const":"device"},"id":{"type":"string","description":"Stable device identifier."},"serial":{"type":"string"},"label":{"anyOf":[{"type":"string"},{"type":"null"}]},"activated":{"type":"boolean"},"reachable":{"type":"boolean"},"model":{"anyOf":[{"type":"string"},{"type":"null"}]},"data_plan":{"anyOf":[{"$ref":"#/$defs/NamedRef"},{"type":"null"}]},"network_group":{"anyOf":[{"$ref":"#/$defs/NamedRef"},{"type":"null"}]},"data_used_bytes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Cumulative usage in BYTES. Always bytes, on every endpoint — the underlying systems variously report kilobytes and megabytes under similar names."},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}]},"updated_at":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["object","id","serial","label","activated","reachable","model","data_plan","network_group","data_used_bytes","created_at","updated_at"],"additionalProperties":false,"id":"Device"},"NamedRef":{"type":"object","properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"type":"string"}},"required":["id","name"],"additionalProperties":false,"id":"NamedRef"}}},"example":{"object":"list","data":[{"object":"device","id":"0d5102c1-b8d2-4ba4-b6aa-43ed91d768c0","serial":"M11-2416002345","label":"Warehouse dock 3","activated":true,"reachable":true,"model":"M-11","data_plan":{"id":"17","name":"IoT 5GB Monthly"},"network_group":{"id":"5","name":"Nationwide"},"data_used_bytes":2411724800,"created_at":"2026-06-02T14:22:11.000Z","updated_at":"2026-08-04T09:15:40.000Z"}],"has_more":true,"next_cursor":"eyJpZCI6ImE0YzIiLCJ0cyI6MTc4NTQzMjAwMDAwMH0"}}}},"400":{"description":"Malformed request — see `error.param`.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"401":{"description":"Missing, invalid, revoked, or expired API key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"403":{"description":"The key lacks a required scope, or the organization is not entitled.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"429":{"description":"Rate limit exceeded. Honour the `Retry-After` header.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"500":{"description":"Unexpected error. Quote `request_id` when reporting it.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}}}}},"/v1/devices/{uuid}":{"get":{"operationId":"getDevice","summary":"Retrieve a device","description":"A single device. Devices are scoped to your organization — an id you do not own returns a 404, indistinguishable from one that does not exist.","tags":["Devices"],"security":[{"bearerAuth":["devices:read"]}],"parameters":[{"name":"uuid","in":"path","required":true,"description":"The device id.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"object":{"type":"string","const":"device"},"id":{"type":"string","description":"Stable device identifier."},"serial":{"type":"string"},"label":{"anyOf":[{"type":"string"},{"type":"null"}]},"activated":{"type":"boolean"},"reachable":{"type":"boolean"},"model":{"anyOf":[{"type":"string"},{"type":"null"}]},"data_plan":{"anyOf":[{"$ref":"#/$defs/NamedRef"},{"type":"null"}]},"network_group":{"anyOf":[{"$ref":"#/$defs/NamedRef"},{"type":"null"}]},"data_used_bytes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Cumulative usage in BYTES. Always bytes, on every endpoint — the underlying systems variously report kilobytes and megabytes under similar names."},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}]},"updated_at":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["object","id","serial","label","activated","reachable","model","data_plan","network_group","data_used_bytes","created_at","updated_at"],"additionalProperties":false,"id":"Device","$defs":{"NamedRef":{"type":"object","properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"type":"string"}},"required":["id","name"],"additionalProperties":false,"id":"NamedRef"}}},"example":{"object":"device","id":"0d5102c1-b8d2-4ba4-b6aa-43ed91d768c0","serial":"M11-2416002345","label":"Warehouse dock 3","activated":true,"reachable":true,"model":"M-11","data_plan":{"id":"17","name":"IoT 5GB Monthly"},"network_group":{"id":"5","name":"Nationwide"},"data_used_bytes":2411724800,"created_at":"2026-06-02T14:22:11.000Z","updated_at":"2026-08-04T09:15:40.000Z"}}}},"400":{"description":"Malformed request — see `error.param`.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"401":{"description":"Missing, invalid, revoked, or expired API key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"403":{"description":"The key lacks a required scope, or the organization is not entitled.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"404":{"description":"No such resource.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"429":{"description":"Rate limit exceeded. Honour the `Retry-After` header.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"500":{"description":"Unexpected error. Quote `request_id` when reporting it.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}}}},"patch":{"operationId":"updateDevice","summary":"Update a device","description":"Changes the label, data plan, or network group. Change `data_plan_id` and `network_group_id` in SEPARATE requests — they are applied independently upstream, so a combined request could half-succeed.","tags":["Devices"],"security":[{"bearerAuth":["devices:write"]}],"parameters":[{"name":"uuid","in":"path","required":true,"description":"The device id.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"label":{"type":"string"},"data_plan_id":{"type":"string"},"network_group_id":{"type":"string"}}},"example":{"label":"Warehouse dock 3"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"object":{"type":"string","const":"device"},"id":{"type":"string","description":"Stable device identifier."},"serial":{"type":"string"},"label":{"anyOf":[{"type":"string"},{"type":"null"}]},"activated":{"type":"boolean"},"reachable":{"type":"boolean"},"model":{"anyOf":[{"type":"string"},{"type":"null"}]},"data_plan":{"anyOf":[{"$ref":"#/$defs/NamedRef"},{"type":"null"}]},"network_group":{"anyOf":[{"$ref":"#/$defs/NamedRef"},{"type":"null"}]},"data_used_bytes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Cumulative usage in BYTES. Always bytes, on every endpoint — the underlying systems variously report kilobytes and megabytes under similar names."},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}]},"updated_at":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["object","id","serial","label","activated","reachable","model","data_plan","network_group","data_used_bytes","created_at","updated_at"],"additionalProperties":false,"id":"Device","$defs":{"NamedRef":{"type":"object","properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"type":"string"}},"required":["id","name"],"additionalProperties":false,"id":"NamedRef"}}},"example":{"object":"device","id":"0d5102c1-b8d2-4ba4-b6aa-43ed91d768c0","serial":"M11-2416002345","label":"Warehouse dock 3","activated":true,"reachable":true,"model":"M-11","data_plan":{"id":"17","name":"IoT 5GB Monthly"},"network_group":{"id":"5","name":"Nationwide"},"data_used_bytes":2411724800,"created_at":"2026-06-02T14:22:11.000Z","updated_at":"2026-08-04T09:15:40.000Z"}}}},"400":{"description":"Malformed request — see `error.param`.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"401":{"description":"Missing, invalid, revoked, or expired API key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"403":{"description":"The key lacks a required scope, or the organization is not entitled.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"404":{"description":"No such resource.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"429":{"description":"Rate limit exceeded. Honour the `Retry-After` header.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"500":{"description":"Unexpected error. Quote `request_id` when reporting it.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}}}}},"/v1/devices/{uuid}/actions/restart":{"post":{"operationId":"restartDevice","summary":"Restart a device","description":"Reboots the device. It is unreachable for a minute or so afterwards.","tags":["Devices"],"security":[{"bearerAuth":["devices:write"]}],"parameters":[{"name":"uuid","in":"path","required":true,"description":"The device id.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}}],"responses":{"202":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"object":{"type":"string","const":"device_action"},"action":{"type":"string"},"device_id":{"type":"string"},"status":{"type":"string","const":"accepted","description":"Always `accepted`. The device platform acknowledges an action once it has been dispatched to the hardware, not once the hardware has applied it — a restart or firmware update completes well after this response. Re-read the device to observe the effect."},"requested_at":{"type":"string"}},"required":["object","action","device_id","status","requested_at"],"additionalProperties":false,"id":"DeviceAction"},"example":{"object":"device_action","action":"restartDevice","device_id":"0d5102c1-b8d2-4ba4-b6aa-43ed91d768c0","status":"accepted","requested_at":"2026-08-04T21:15:40.000Z"}}}},"400":{"description":"Malformed request — see `error.param`.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"401":{"description":"Missing, invalid, revoked, or expired API key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"403":{"description":"The key lacks a required scope, or the organization is not entitled.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"404":{"description":"No such resource.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"409":{"description":"The Idempotency-Key was already used for a different request body. Use a new key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"429":{"description":"Rate limit exceeded. Honour the `Retry-After` header.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"500":{"description":"Unexpected error. Quote `request_id` when reporting it.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}}}}},"/v1/devices/{uuid}/actions/activate":{"post":{"operationId":"activateDevice","summary":"Activate a device","description":"Brings a device into service on a network group. Activation is billable and requires the activation capability on your account.","tags":["Devices"],"security":[{"bearerAuth":["devices:write"]}],"parameters":[{"name":"uuid","in":"path","required":true,"description":"The device id.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"network_group_id":{"type":"string","description":"From `GET /v1/devices` — a device's `network_group.id`."}},"required":["network_group_id"]},"example":{"network_group_id":"5"}}}},"responses":{"202":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"object":{"type":"string","const":"device_action"},"action":{"type":"string"},"device_id":{"type":"string"},"status":{"type":"string","const":"accepted","description":"Always `accepted`. The device platform acknowledges an action once it has been dispatched to the hardware, not once the hardware has applied it — a restart or firmware update completes well after this response. Re-read the device to observe the effect."},"requested_at":{"type":"string"}},"required":["object","action","device_id","status","requested_at"],"additionalProperties":false,"id":"DeviceAction"},"example":{"object":"device_action","action":"activateDevice","device_id":"0d5102c1-b8d2-4ba4-b6aa-43ed91d768c0","status":"accepted","requested_at":"2026-08-04T21:15:40.000Z"}}}},"400":{"description":"Malformed request — see `error.param`.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"401":{"description":"Missing, invalid, revoked, or expired API key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"403":{"description":"The key lacks a required scope, or the organization is not entitled.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"404":{"description":"No such resource.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"409":{"description":"The Idempotency-Key was already used for a different request body. Use a new key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"429":{"description":"Rate limit exceeded. Honour the `Retry-After` header.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"500":{"description":"Unexpected error. Quote `request_id` when reporting it.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}}}}},"/v1/devices/{uuid}/actions/deactivate":{"post":{"operationId":"deactivateDevice","summary":"Deactivate a device","description":"Takes a device out of service. It remains assigned to your organization.","tags":["Devices"],"security":[{"bearerAuth":["devices:write"]}],"parameters":[{"name":"uuid","in":"path","required":true,"description":"The device id.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}}],"responses":{"202":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"object":{"type":"string","const":"device_action"},"action":{"type":"string"},"device_id":{"type":"string"},"status":{"type":"string","const":"accepted","description":"Always `accepted`. The device platform acknowledges an action once it has been dispatched to the hardware, not once the hardware has applied it — a restart or firmware update completes well after this response. Re-read the device to observe the effect."},"requested_at":{"type":"string"}},"required":["object","action","device_id","status","requested_at"],"additionalProperties":false,"id":"DeviceAction"},"example":{"object":"device_action","action":"deactivateDevice","device_id":"0d5102c1-b8d2-4ba4-b6aa-43ed91d768c0","status":"accepted","requested_at":"2026-08-04T21:15:40.000Z"}}}},"400":{"description":"Malformed request — see `error.param`.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"401":{"description":"Missing, invalid, revoked, or expired API key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"403":{"description":"The key lacks a required scope, or the organization is not entitled.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"404":{"description":"No such resource.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"409":{"description":"The Idempotency-Key was already used for a different request body. Use a new key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"429":{"description":"Rate limit exceeded. Honour the `Retry-After` header.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"500":{"description":"Unexpected error. Quote `request_id` when reporting it.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}}}}},"/v1/devices/{uuid}/actions/update_firmware":{"post":{"operationId":"updateDeviceFirmware","summary":"Update device firmware","description":"Asks the device to fetch and apply the latest firmware. It downloads on its own schedule and is unreachable while it reboots.","tags":["Devices"],"security":[{"bearerAuth":["devices:write"]}],"parameters":[{"name":"uuid","in":"path","required":true,"description":"The device id.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}}],"responses":{"202":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"object":{"type":"string","const":"device_action"},"action":{"type":"string"},"device_id":{"type":"string"},"status":{"type":"string","const":"accepted","description":"Always `accepted`. The device platform acknowledges an action once it has been dispatched to the hardware, not once the hardware has applied it — a restart or firmware update completes well after this response. Re-read the device to observe the effect."},"requested_at":{"type":"string"}},"required":["object","action","device_id","status","requested_at"],"additionalProperties":false,"id":"DeviceAction"},"example":{"object":"device_action","action":"updateDeviceFirmware","device_id":"0d5102c1-b8d2-4ba4-b6aa-43ed91d768c0","status":"accepted","requested_at":"2026-08-04T21:15:40.000Z"}}}},"400":{"description":"Malformed request — see `error.param`.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"401":{"description":"Missing, invalid, revoked, or expired API key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"403":{"description":"The key lacks a required scope, or the organization is not entitled.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"404":{"description":"No such resource.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"409":{"description":"The Idempotency-Key was already used for a different request body. Use a new key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"429":{"description":"Rate limit exceeded. Honour the `Retry-After` header.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"500":{"description":"Unexpected error. Quote `request_id` when reporting it.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}}}}},"/v1/devices/{uuid}/actions/factory_reset":{"post":{"operationId":"factoryResetDevice","summary":"Reset a device to factory configuration","description":"Restores the factory configuration, discarding the SSID, LAN addressing and any networking rules on the device. This cannot be undone.","tags":["Devices"],"security":[{"bearerAuth":["devices:write"]}],"parameters":[{"name":"uuid","in":"path","required":true,"description":"The device id.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}}],"responses":{"202":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"object":{"type":"string","const":"device_action"},"action":{"type":"string"},"device_id":{"type":"string"},"status":{"type":"string","const":"accepted","description":"Always `accepted`. The device platform acknowledges an action once it has been dispatched to the hardware, not once the hardware has applied it — a restart or firmware update completes well after this response. Re-read the device to observe the effect."},"requested_at":{"type":"string"}},"required":["object","action","device_id","status","requested_at"],"additionalProperties":false,"id":"DeviceAction"},"example":{"object":"device_action","action":"factoryResetDevice","device_id":"0d5102c1-b8d2-4ba4-b6aa-43ed91d768c0","status":"accepted","requested_at":"2026-08-04T21:15:40.000Z"}}}},"400":{"description":"Malformed request — see `error.param`.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"401":{"description":"Missing, invalid, revoked, or expired API key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"403":{"description":"The key lacks a required scope, or the organization is not entitled.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"404":{"description":"No such resource.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"409":{"description":"The Idempotency-Key was already used for a different request body. Use a new key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"429":{"description":"Rate limit exceeded. Honour the `Retry-After` header.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"500":{"description":"Unexpected error. Quote `request_id` when reporting it.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}}}}},"/v1/devices/{uuid}/wifi":{"get":{"operationId":"getDeviceWifi","summary":"Retrieve Wi-Fi settings","description":"The network name, and whether a password is set. The password itself is never returned.\n\nRead live from the device, so a device that is powered off or out of coverage returns `409 device_unreachable` — or `503` if it does not answer in time.","tags":["Devices"],"security":[{"bearerAuth":["devices:read"]}],"parameters":[{"name":"uuid","in":"path","required":true,"description":"The device id.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"object":{"type":"string","const":"device_wifi"},"device_id":{"type":"string"},"ssid":{"anyOf":[{"type":"string"},{"type":"null"}]},"password_set":{"type":"boolean"}},"required":["object","device_id","ssid","password_set"],"additionalProperties":false,"id":"DeviceWifi"},"example":{"object":"device_wifi","device_id":"0d5102c1-b8d2-4ba4-b6aa-43ed91d768c0","ssid":"Acme-Warehouse","password_set":true}}}},"400":{"description":"Malformed request — see `error.param`.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"401":{"description":"Missing, invalid, revoked, or expired API key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"403":{"description":"The key lacks a required scope, or the organization is not entitled.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"404":{"description":"No such resource.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"409":{"description":"The Idempotency-Key was already used for a different request body. Use a new key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"429":{"description":"Rate limit exceeded. Honour the `Retry-After` header.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"500":{"description":"Unexpected error. Quote `request_id` when reporting it.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"503":{"description":"An upstream dependency is unavailable. Retry shortly.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}}}},"patch":{"operationId":"updateDeviceWifi","summary":"Update Wi-Fi settings","description":"Applied to the hardware, so it takes effect when the device next checks in. Passwords must be at least 8 characters.","tags":["Devices"],"security":[{"bearerAuth":["devices:write"]}],"parameters":[{"name":"uuid","in":"path","required":true,"description":"The device id.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"ssid":{"type":"string"},"password":{"type":"string","minLength":8}}},"example":{"ssid":"Acme-Warehouse"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"object":{"type":"string","const":"device_wifi"},"device_id":{"type":"string"},"ssid":{"anyOf":[{"type":"string"},{"type":"null"}]},"password_set":{"type":"boolean"}},"required":["object","device_id","ssid","password_set"],"additionalProperties":false,"id":"DeviceWifi"},"example":{"object":"device_wifi","device_id":"0d5102c1-b8d2-4ba4-b6aa-43ed91d768c0","ssid":"Acme-Warehouse","password_set":true}}}},"400":{"description":"Malformed request — see `error.param`.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"401":{"description":"Missing, invalid, revoked, or expired API key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"403":{"description":"The key lacks a required scope, or the organization is not entitled.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"404":{"description":"No such resource.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"429":{"description":"Rate limit exceeded. Honour the `Retry-After` header.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"500":{"description":"Unexpected error. Quote `request_id` when reporting it.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}}}}},"/v1/devices/{uuid}/network":{"get":{"operationId":"getDeviceNetwork","summary":"Retrieve LAN settings","description":"The device's LAN address and MTU.\n\nRead live from the device, so a device that is powered off or out of coverage returns `409 device_unreachable` — or `503` if it does not answer in time.","tags":["Devices"],"security":[{"bearerAuth":["devices:read"]}],"parameters":[{"name":"uuid","in":"path","required":true,"description":"The device id.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"object":{"type":"string","const":"device_network"},"device_id":{"type":"string"},"lan_ip":{"anyOf":[{"type":"string"},{"type":"null"}]},"mtu":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"mtu_interface":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["object","device_id","lan_ip","mtu","mtu_interface"],"additionalProperties":false,"id":"DeviceNetwork"},"example":{"object":"device_network","device_id":"0d5102c1-b8d2-4ba4-b6aa-43ed91d768c0","lan_ip":"192.168.1.1","mtu":1500,"mtu_interface":"wan"}}}},"400":{"description":"Malformed request — see `error.param`.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"401":{"description":"Missing, invalid, revoked, or expired API key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"403":{"description":"The key lacks a required scope, or the organization is not entitled.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"404":{"description":"No such resource.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"409":{"description":"The Idempotency-Key was already used for a different request body. Use a new key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"429":{"description":"Rate limit exceeded. Honour the `Retry-After` header.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"500":{"description":"Unexpected error. Quote `request_id` when reporting it.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"503":{"description":"An upstream dependency is unavailable. Retry shortly.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}}}},"patch":{"operationId":"updateDeviceNetwork","summary":"Update LAN settings","description":"`lan_ip` and `mtu` are applied by separate upstream calls, so a request setting both can partially succeed; the error names which one failed. MTU must be between 1000 and 1500.","tags":["Devices"],"security":[{"bearerAuth":["devices:write"]}],"parameters":[{"name":"uuid","in":"path","required":true,"description":"The device id.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"lan_ip":{"type":"string"},"mtu":{"type":"integer","minimum":1000,"maximum":1500}}},"example":{"mtu":1400}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"object":{"type":"string","const":"device_network"},"device_id":{"type":"string"},"lan_ip":{"anyOf":[{"type":"string"},{"type":"null"}]},"mtu":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"mtu_interface":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["object","device_id","lan_ip","mtu","mtu_interface"],"additionalProperties":false,"id":"DeviceNetwork"},"example":{"object":"device_network","device_id":"0d5102c1-b8d2-4ba4-b6aa-43ed91d768c0","lan_ip":"192.168.1.1","mtu":1500,"mtu_interface":"wan"}}}},"400":{"description":"Malformed request — see `error.param`.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"401":{"description":"Missing, invalid, revoked, or expired API key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"403":{"description":"The key lacks a required scope, or the organization is not entitled.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"404":{"description":"No such resource.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"429":{"description":"Rate limit exceeded. Honour the `Retry-After` header.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"500":{"description":"Unexpected error. Quote `request_id` when reporting it.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}}}}},"/v1/devices/{uuid}/restart_schedule":{"patch":{"operationId":"updateDeviceRestartSchedule","summary":"Set a restart schedule","description":"A device has at most one schedule, so this creates or replaces it. `time` is 24-hour HH:MM in the device's local time.\n\n`day` is an integer and is required unless `frequency` is `daily`: the day of the month for a monthly schedule, and the device platform's own weekday index for a weekly one. It is passed through to the platform unchanged.","tags":["Devices"],"security":[{"bearerAuth":["devices:write"]}],"parameters":[{"name":"uuid","in":"path","required":true,"description":"The device id.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"frequency":{"type":"string","enum":["daily","weekly","monthly"]},"time":{"type":"string"},"day":{"type":"integer","minimum":0,"maximum":31}},"required":["frequency","time"]},"example":{"frequency":"daily","time":"03:00"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"object":{"type":"string","const":"device_restart_schedule"},"device_id":{"type":"string"},"frequency":{"type":"string"},"time":{"type":"string","description":"24-hour HH:MM, in the device's local time."},"day":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Day of the month for a monthly schedule; the device platform's own weekday index for a weekly one. `null` for daily."}},"required":["object","device_id","frequency","time","day"],"additionalProperties":false,"id":"DeviceRestartSchedule"},"example":{"object":"device_restart_schedule","device_id":"0d5102c1-b8d2-4ba4-b6aa-43ed91d768c0","frequency":"daily","time":"03:00","day":null}}}},"400":{"description":"Malformed request — see `error.param`.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"401":{"description":"Missing, invalid, revoked, or expired API key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"403":{"description":"The key lacks a required scope, or the organization is not entitled.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"404":{"description":"No such resource.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"429":{"description":"Rate limit exceeded. Honour the `Retry-After` header.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"500":{"description":"Unexpected error. Quote `request_id` when reporting it.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}}}},"delete":{"operationId":"deleteDeviceRestartSchedule","summary":"Cancel the restart schedule","description":"Idempotent — cancelling when nothing is scheduled succeeds.","tags":["Devices"],"security":[{"bearerAuth":["devices:write"]}],"parameters":[{"name":"uuid","in":"path","required":true,"description":"The device id.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}}],"responses":{"204":{"description":"Success"},"400":{"description":"Malformed request — see `error.param`.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"401":{"description":"Missing, invalid, revoked, or expired API key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"403":{"description":"The key lacks a required scope, or the organization is not entitled.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"404":{"description":"No such resource.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"429":{"description":"Rate limit exceeded. Honour the `Retry-After` header.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"500":{"description":"Unexpected error. Quote `request_id` when reporting it.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}}}}},"/v1/devices/{uuid}/connectivity":{"get":{"operationId":"getDeviceConnectivity","summary":"Retrieve live connectivity","description":"How many clients are attached, who they are, and recent uptime. Read live from the device platform rather than from synced inventory. A field is `null` when that source was unavailable, so a partial outage degrades the response instead of failing it.","tags":["Devices"],"security":[{"bearerAuth":["devices:read"]}],"parameters":[{"name":"uuid","in":"path","required":true,"description":"The device id.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"object":{"type":"string","const":"device_connectivity"},"device_id":{"type":"string"},"reachable":{"type":"boolean"},"connection_count":{"description":"Null when unavailable."},"connections":{},"uptime":{}},"required":["object","device_id","reachable","connection_count","connections","uptime"],"additionalProperties":false,"id":"DeviceConnectivity"},"example":{"object":"device_connectivity","device_id":"0d5102c1-b8d2-4ba4-b6aa-43ed91d768c0","reachable":true,"connection_count":4,"connections":[],"uptime":[]}}}},"400":{"description":"Malformed request — see `error.param`.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"401":{"description":"Missing, invalid, revoked, or expired API key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"403":{"description":"The key lacks a required scope, or the organization is not entitled.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"404":{"description":"No such resource.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"429":{"description":"Rate limit exceeded. Honour the `Retry-After` header.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"500":{"description":"Unexpected error. Quote `request_id` when reporting it.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}}}}},"/v1/devices/{uuid}/events":{"get":{"operationId":"listDeviceEvents","summary":"List device events","description":"What has been done to this device, most recent first.","tags":["Devices"],"security":[{"bearerAuth":["devices:read"]}],"parameters":[{"name":"uuid","in":"path","required":true,"description":"The device id.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"object":{"type":"string","const":"list"},"data":{"type":"array","items":{"$ref":"#/$defs/DeviceReading"}},"has_more":{"type":"boolean"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Pass as `starting_after` for the next page."}},"required":["object","data","has_more","next_cursor"],"additionalProperties":false,"id":"DeviceReadingList","$defs":{"DeviceReading":{"type":"object","properties":{"object":{"type":"string","const":"device_reading"},"device_id":{"type":"string"},"kind":{"type":"string"},"recorded_at":{"anyOf":[{"type":"string"},{"type":"null"}]},"data":{}},"required":["object","device_id","kind","recorded_at","data"],"additionalProperties":false,"id":"DeviceReading"}}},"example":{"object":"list","data":[{"object":"device_reading","device_id":"0d5102c1-b8d2-4ba4-b6aa-43ed91d768c0","kind":"event","recorded_at":"2026-08-04T09:15:40.000Z","data":{}}],"has_more":false,"next_cursor":null}}}},"400":{"description":"Malformed request — see `error.param`.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"401":{"description":"Missing, invalid, revoked, or expired API key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"403":{"description":"The key lacks a required scope, or the organization is not entitled.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"404":{"description":"No such resource.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"429":{"description":"Rate limit exceeded. Honour the `Retry-After` header.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"500":{"description":"Unexpected error. Quote `request_id` when reporting it.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}}}}},"/v1/devices/{uuid}/notes":{"get":{"operationId":"listDeviceNotes","summary":"List device notes","description":"Notes attached to the device. The author is not returned — it is frequently a member of our own or the platform's staff.","tags":["Devices"],"security":[{"bearerAuth":["devices:read"]}],"parameters":[{"name":"uuid","in":"path","required":true,"description":"The device id.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"object":{"type":"string","const":"list"},"data":{"type":"array","items":{"$ref":"#/$defs/DeviceReading"}},"has_more":{"type":"boolean"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Pass as `starting_after` for the next page."}},"required":["object","data","has_more","next_cursor"],"additionalProperties":false,"id":"DeviceReadingList","$defs":{"DeviceReading":{"type":"object","properties":{"object":{"type":"string","const":"device_reading"},"device_id":{"type":"string"},"kind":{"type":"string"},"recorded_at":{"anyOf":[{"type":"string"},{"type":"null"}]},"data":{}},"required":["object","device_id","kind","recorded_at","data"],"additionalProperties":false,"id":"DeviceReading"}}},"example":{"object":"list","data":[{"object":"device_reading","device_id":"0d5102c1-b8d2-4ba4-b6aa-43ed91d768c0","kind":"note","recorded_at":"2026-08-04T09:15:40.000Z","data":{}}],"has_more":false,"next_cursor":null}}}},"400":{"description":"Malformed request — see `error.param`.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"401":{"description":"Missing, invalid, revoked, or expired API key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"403":{"description":"The key lacks a required scope, or the organization is not entitled.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"404":{"description":"No such resource.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"429":{"description":"Rate limit exceeded. Honour the `Retry-After` header.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"500":{"description":"Unexpected error. Quote `request_id` when reporting it.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}}}},"post":{"operationId":"createDeviceNote","summary":"Add a device note","description":"Attaches a note to the device.","tags":["Devices"],"security":[{"bearerAuth":["devices:write"]}],"parameters":[{"name":"uuid","in":"path","required":true,"description":"The device id.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"note":{"type":"string","minLength":1}},"required":["note"]},"example":{"note":"Relocated to dock 3"}}}},"responses":{"204":{"description":"Success"},"400":{"description":"Malformed request — see `error.param`.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"401":{"description":"Missing, invalid, revoked, or expired API key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"403":{"description":"The key lacks a required scope, or the organization is not entitled.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"404":{"description":"No such resource.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"429":{"description":"Rate limit exceeded. Honour the `Retry-After` header.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"500":{"description":"Unexpected error. Quote `request_id` when reporting it.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}}}}},"/v1/devices/{uuid}/config_backups":{"get":{"operationId":"listDeviceConfigBackups","summary":"List configuration backups","description":"Backups taken of this device's configuration. Restoring is a support operation and is not available through the API.","tags":["Devices"],"security":[{"bearerAuth":["devices:read"]}],"parameters":[{"name":"uuid","in":"path","required":true,"description":"The device id.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"object":{"type":"string","const":"list"},"data":{"type":"array","items":{"$ref":"#/$defs/DeviceReading"}},"has_more":{"type":"boolean"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Pass as `starting_after` for the next page."}},"required":["object","data","has_more","next_cursor"],"additionalProperties":false,"id":"DeviceReadingList","$defs":{"DeviceReading":{"type":"object","properties":{"object":{"type":"string","const":"device_reading"},"device_id":{"type":"string"},"kind":{"type":"string"},"recorded_at":{"anyOf":[{"type":"string"},{"type":"null"}]},"data":{}},"required":["object","device_id","kind","recorded_at","data"],"additionalProperties":false,"id":"DeviceReading"}}},"example":{"object":"list","data":[{"object":"device_reading","device_id":"0d5102c1-b8d2-4ba4-b6aa-43ed91d768c0","kind":"config_backup","recorded_at":"2026-08-04T09:15:40.000Z","data":{}}],"has_more":false,"next_cursor":null}}}},"400":{"description":"Malformed request — see `error.param`.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"401":{"description":"Missing, invalid, revoked, or expired API key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"403":{"description":"The key lacks a required scope, or the organization is not entitled.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"404":{"description":"No such resource.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"429":{"description":"Rate limit exceeded. Honour the `Retry-After` header.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"500":{"description":"Unexpected error. Quote `request_id` when reporting it.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}}}},"post":{"operationId":"createDeviceConfigBackup","summary":"Take a configuration backup","description":"Captures the device's current configuration. Completes asynchronously, so acceptance is not completion — poll the list endpoint. Taking a second backup is harmless, so retries are safe without an idempotency key.","tags":["Devices"],"security":[{"bearerAuth":["devices:write"]}],"parameters":[{"name":"uuid","in":"path","required":true,"description":"The device id.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}}],"responses":{"202":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"object":{"type":"string","const":"device_action"},"action":{"type":"string"},"device_id":{"type":"string"},"status":{"type":"string","const":"accepted","description":"Always `accepted`. The device platform acknowledges an action once it has been dispatched to the hardware, not once the hardware has applied it — a restart or firmware update completes well after this response. Re-read the device to observe the effect."},"requested_at":{"type":"string"}},"required":["object","action","device_id","status","requested_at"],"additionalProperties":false,"id":"DeviceAction"},"example":{"object":"device_action","action":"create_config_backup","device_id":"0d5102c1-b8d2-4ba4-b6aa-43ed91d768c0","status":"accepted","requested_at":"2026-08-04T21:15:40.000Z"}}}},"400":{"description":"Malformed request — see `error.param`.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"401":{"description":"Missing, invalid, revoked, or expired API key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"403":{"description":"The key lacks a required scope, or the organization is not entitled.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"404":{"description":"No such resource.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"429":{"description":"Rate limit exceeded. Honour the `Retry-After` header.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"500":{"description":"Unexpected error. Quote `request_id` when reporting it.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}}}}},"/v1/devices/{uuid}/port_forwards":{"get":{"operationId":"listPortForwards","summary":"List port forwarding rules","description":"Rules currently applied to this device.","tags":["Device networking"],"security":[{"bearerAuth":["devices:read"]}],"parameters":[{"name":"uuid","in":"path","required":true,"description":"The device id.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"object":{"type":"string","const":"list"},"data":{"type":"array","items":{"$ref":"#/$defs/PortForward"}},"has_more":{"type":"boolean"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Pass as `starting_after` for the next page."}},"required":["object","data","has_more","next_cursor"],"additionalProperties":false,"id":"PortForwardList","$defs":{"PortForward":{"type":"object","properties":{"object":{"type":"string","const":"port_forward"},"id":{"type":"string"},"inbound_ip":{"type":"string"},"inbound_port":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"internal_ip":{"type":"string"},"internal_port":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"protocol":{"type":"string","description":"`TCP`, `UDP` or `BOTH`."},"application_protocol":{"type":"string"},"source_ip":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["object","id","inbound_ip","inbound_port","internal_ip","internal_port","protocol","application_protocol","source_ip"],"additionalProperties":false,"id":"PortForward"}}},"example":{"object":"list","data":[{"object":"port_forward","id":"412","inbound_ip":"203.0.113.10","inbound_port":8080,"internal_ip":"192.168.1.50","internal_port":80,"protocol":"TCP","application_protocol":"HTTP","source_ip":null}],"has_more":false,"next_cursor":null}}}},"400":{"description":"Malformed request — see `error.param`.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"401":{"description":"Missing, invalid, revoked, or expired API key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"403":{"description":"The key lacks a required scope, or the organization is not entitled.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"404":{"description":"No such resource.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"429":{"description":"Rate limit exceeded. Honour the `Retry-After` header.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"500":{"description":"Unexpected error. Quote `request_id` when reporting it.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}}}},"post":{"operationId":"createPortForward","summary":"Create a port forwarding rule","description":"Ports must be 1-65535. `protocol` is `TCP`, `UDP` or `BOTH`; `application_protocol` is `HTTP`, `HTTPS` or `OTHER`. Returns the device's full rule set. Sending an identical rule again is a no-op, so retries are safe without an idempotency key.","tags":["Device networking"],"security":[{"bearerAuth":["devices:write"]}],"parameters":[{"name":"uuid","in":"path","required":true,"description":"The device id.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"inbound_ip":{"type":"string"},"inbound_port":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"internal_ip":{"type":"string"},"internal_port":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"protocol":{"type":"string","enum":["TCP","UDP","BOTH"]},"application_protocol":{"type":"string","enum":["HTTP","HTTPS","OTHER"]},"source_ip":{"type":"string"}},"required":["inbound_ip","inbound_port","internal_ip","internal_port","protocol"]},"example":{"inbound_ip":"203.0.113.10","inbound_port":8080,"internal_ip":"192.168.1.50","internal_port":80,"protocol":"TCP","application_protocol":"HTTP"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"object":{"type":"string","const":"list"},"data":{"type":"array","items":{"$ref":"#/$defs/PortForward"}},"has_more":{"type":"boolean"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Pass as `starting_after` for the next page."}},"required":["object","data","has_more","next_cursor"],"additionalProperties":false,"id":"PortForwardList","$defs":{"PortForward":{"type":"object","properties":{"object":{"type":"string","const":"port_forward"},"id":{"type":"string"},"inbound_ip":{"type":"string"},"inbound_port":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"internal_ip":{"type":"string"},"internal_port":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"protocol":{"type":"string","description":"`TCP`, `UDP` or `BOTH`."},"application_protocol":{"type":"string"},"source_ip":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["object","id","inbound_ip","inbound_port","internal_ip","internal_port","protocol","application_protocol","source_ip"],"additionalProperties":false,"id":"PortForward"}}},"example":{"object":"list","data":[{"object":"port_forward","id":"412","inbound_ip":"203.0.113.10","inbound_port":8080,"internal_ip":"192.168.1.50","internal_port":80,"protocol":"TCP","application_protocol":"HTTP","source_ip":null}],"has_more":false,"next_cursor":null}}}},"400":{"description":"Malformed request — see `error.param`.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"401":{"description":"Missing, invalid, revoked, or expired API key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"403":{"description":"The key lacks a required scope, or the organization is not entitled.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"404":{"description":"No such resource.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"429":{"description":"Rate limit exceeded. Honour the `Retry-After` header.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"500":{"description":"Unexpected error. Quote `request_id` when reporting it.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}}}}},"/v1/devices/{uuid}/port_forwards/{rule_id}":{"delete":{"operationId":"deletePortForward","summary":"Delete a port forwarding rule","description":"Removes the port forwarding rule. The rule is confirmed to belong to this device first, so an id from another device returns 404.","tags":["Device networking"],"security":[{"bearerAuth":["devices:write"]}],"parameters":[{"name":"uuid","in":"path","required":true,"description":"The device id.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}},{"name":"rule_id","in":"path","required":true,"description":"The rule id, from the list endpoint.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}}],"responses":{"204":{"description":"Success"},"400":{"description":"Malformed request — see `error.param`.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"401":{"description":"Missing, invalid, revoked, or expired API key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"403":{"description":"The key lacks a required scope, or the organization is not entitled.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"404":{"description":"No such resource.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"429":{"description":"Rate limit exceeded. Honour the `Retry-After` header.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"500":{"description":"Unexpected error. Quote `request_id` when reporting it.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}}}}},"/v1/devices/{uuid}/dedicated_ips":{"get":{"operationId":"listDedicatedIps","summary":"List dedicated IP rules","description":"Dedicated inbound addresses assigned to this device.","tags":["Device networking"],"security":[{"bearerAuth":["devices:read"]}],"parameters":[{"name":"uuid","in":"path","required":true,"description":"The device id.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"object":{"type":"string","const":"list"},"data":{"type":"array","items":{"$ref":"#/$defs/DedicatedIp"}},"has_more":{"type":"boolean"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Pass as `starting_after` for the next page."}},"required":["object","data","has_more","next_cursor"],"additionalProperties":false,"id":"DedicatedIpList","$defs":{"DedicatedIp":{"type":"object","properties":{"object":{"type":"string","const":"dedicated_ip"},"id":{"type":"string"},"inbound_ip":{"type":"string"},"outbound_traffic":{"type":"boolean"},"status":{"type":"string"}},"required":["object","id","inbound_ip","outbound_traffic","status"],"additionalProperties":false,"id":"DedicatedIp"}}},"example":{"object":"list","data":[{"object":"dedicated_ip","id":"77","inbound_ip":"203.0.113.10","outbound_traffic":false,"status":"active"}],"has_more":false,"next_cursor":null}}}},"400":{"description":"Malformed request — see `error.param`.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"401":{"description":"Missing, invalid, revoked, or expired API key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"403":{"description":"The key lacks a required scope, or the organization is not entitled.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"404":{"description":"No such resource.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"429":{"description":"Rate limit exceeded. Honour the `Retry-After` header.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"500":{"description":"Unexpected error. Quote `request_id` when reporting it.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}}}},"post":{"operationId":"createDedicatedIp","summary":"Assign a dedicated IP","description":"Returns the device's full set of dedicated addresses. Sending an identical rule again is a no-op, so retries are safe without an idempotency key.","tags":["Device networking"],"security":[{"bearerAuth":["devices:write"]}],"parameters":[{"name":"uuid","in":"path","required":true,"description":"The device id.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"inbound_ip":{"type":"string"},"outbound_traffic":{"type":"boolean"}},"required":["inbound_ip"]},"example":{"inbound_ip":"203.0.113.10"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"object":{"type":"string","const":"list"},"data":{"type":"array","items":{"$ref":"#/$defs/DedicatedIp"}},"has_more":{"type":"boolean"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Pass as `starting_after` for the next page."}},"required":["object","data","has_more","next_cursor"],"additionalProperties":false,"id":"DedicatedIpList","$defs":{"DedicatedIp":{"type":"object","properties":{"object":{"type":"string","const":"dedicated_ip"},"id":{"type":"string"},"inbound_ip":{"type":"string"},"outbound_traffic":{"type":"boolean"},"status":{"type":"string"}},"required":["object","id","inbound_ip","outbound_traffic","status"],"additionalProperties":false,"id":"DedicatedIp"}}},"example":{"object":"list","data":[{"object":"dedicated_ip","id":"77","inbound_ip":"203.0.113.10","outbound_traffic":false,"status":"active"}],"has_more":false,"next_cursor":null}}}},"400":{"description":"Malformed request — see `error.param`.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"401":{"description":"Missing, invalid, revoked, or expired API key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"403":{"description":"The key lacks a required scope, or the organization is not entitled.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"404":{"description":"No such resource.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"429":{"description":"Rate limit exceeded. Honour the `Retry-After` header.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"500":{"description":"Unexpected error. Quote `request_id` when reporting it.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}}}}},"/v1/devices/{uuid}/dedicated_ips/{rule_id}":{"delete":{"operationId":"deleteDedicatedIp","summary":"Delete a dedicated IP rule","description":"Removes the dedicated IP rule. The rule is confirmed to belong to this device first, so an id from another device returns 404.","tags":["Device networking"],"security":[{"bearerAuth":["devices:write"]}],"parameters":[{"name":"uuid","in":"path","required":true,"description":"The device id.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}},{"name":"rule_id","in":"path","required":true,"description":"The rule id, from the list endpoint.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}}],"responses":{"204":{"description":"Success"},"400":{"description":"Malformed request — see `error.param`.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"401":{"description":"Missing, invalid, revoked, or expired API key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"403":{"description":"The key lacks a required scope, or the organization is not entitled.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"404":{"description":"No such resource.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"429":{"description":"Rate limit exceeded. Honour the `Retry-After` header.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"500":{"description":"Unexpected error. Quote `request_id` when reporting it.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}}}}},"/v1/devices/{uuid}/bridged_ips":{"get":{"operationId":"listBridgedIps","summary":"List bridged IP rules","description":"Bridged addresses assigned to this device.","tags":["Device networking"],"security":[{"bearerAuth":["devices:read"]}],"parameters":[{"name":"uuid","in":"path","required":true,"description":"The device id.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"object":{"type":"string","const":"list"},"data":{"type":"array","items":{"$ref":"#/$defs/BridgedIp"}},"has_more":{"type":"boolean"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Pass as `starting_after` for the next page."}},"required":["object","data","has_more","next_cursor"],"additionalProperties":false,"id":"BridgedIpList","$defs":{"BridgedIp":{"type":"object","properties":{"object":{"type":"string","const":"bridged_ip"},"id":{"type":"string"},"inbound_ip":{"type":"string"},"status":{"type":"string"},"subnet":{"anyOf":[{"type":"string"},{"type":"null"}]},"gateway":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["object","id","inbound_ip","status","subnet","gateway"],"additionalProperties":false,"id":"BridgedIp"}}},"example":{"object":"list","data":[{"object":"bridged_ip","id":"31","inbound_ip":"203.0.113.20","status":"active","subnet":"255.255.255.248","gateway":"203.0.113.17"}],"has_more":false,"next_cursor":null}}}},"400":{"description":"Malformed request — see `error.param`.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"401":{"description":"Missing, invalid, revoked, or expired API key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"403":{"description":"The key lacks a required scope, or the organization is not entitled.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"404":{"description":"No such resource.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"429":{"description":"Rate limit exceeded. Honour the `Retry-After` header.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"500":{"description":"Unexpected error. Quote `request_id` when reporting it.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}}}},"post":{"operationId":"createBridgedIp","summary":"Assign a bridged IP","description":"Returns the device's full set of bridged addresses. Sending an identical rule again is a no-op, so retries are safe without an idempotency key.","tags":["Device networking"],"security":[{"bearerAuth":["devices:write"]}],"parameters":[{"name":"uuid","in":"path","required":true,"description":"The device id.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"inbound_ip":{"type":"string"}},"required":["inbound_ip"]},"example":{"inbound_ip":"203.0.113.20"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"object":{"type":"string","const":"list"},"data":{"type":"array","items":{"$ref":"#/$defs/BridgedIp"}},"has_more":{"type":"boolean"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Pass as `starting_after` for the next page."}},"required":["object","data","has_more","next_cursor"],"additionalProperties":false,"id":"BridgedIpList","$defs":{"BridgedIp":{"type":"object","properties":{"object":{"type":"string","const":"bridged_ip"},"id":{"type":"string"},"inbound_ip":{"type":"string"},"status":{"type":"string"},"subnet":{"anyOf":[{"type":"string"},{"type":"null"}]},"gateway":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["object","id","inbound_ip","status","subnet","gateway"],"additionalProperties":false,"id":"BridgedIp"}}},"example":{"object":"list","data":[{"object":"bridged_ip","id":"31","inbound_ip":"203.0.113.20","status":"active","subnet":"255.255.255.248","gateway":"203.0.113.17"}],"has_more":false,"next_cursor":null}}}},"400":{"description":"Malformed request — see `error.param`.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"401":{"description":"Missing, invalid, revoked, or expired API key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"403":{"description":"The key lacks a required scope, or the organization is not entitled.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"404":{"description":"No such resource.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"429":{"description":"Rate limit exceeded. Honour the `Retry-After` header.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"500":{"description":"Unexpected error. Quote `request_id` when reporting it.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}}}}},"/v1/devices/{uuid}/bridged_ips/{rule_id}":{"delete":{"operationId":"deleteBridgedIp","summary":"Delete a bridged IP rule","description":"Removes the bridged IP rule. The rule is confirmed to belong to this device first, so an id from another device returns 404.","tags":["Device networking"],"security":[{"bearerAuth":["devices:write"]}],"parameters":[{"name":"uuid","in":"path","required":true,"description":"The device id.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}},{"name":"rule_id","in":"path","required":true,"description":"The rule id, from the list endpoint.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}}],"responses":{"204":{"description":"Success"},"400":{"description":"Malformed request — see `error.param`.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"401":{"description":"Missing, invalid, revoked, or expired API key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"403":{"description":"The key lacks a required scope, or the organization is not entitled.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"404":{"description":"No such resource.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"429":{"description":"Rate limit exceeded. Honour the `Retry-After` header.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"500":{"description":"Unexpected error. Quote `request_id` when reporting it.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}}}}},"/v1/devices/{uuid}/actions/speed_test":{"post":{"operationId":"startDeviceSpeedTest","summary":"Start a speed test","description":"Starts a speed test on the device. Results arrive asynchronously — poll the matching read endpoint.\n\n`type` is `rapid` (the default) or `full`.","tags":["Device diagnostics"],"security":[{"bearerAuth":["devices:write"]}],"parameters":[{"name":"uuid","in":"path","required":true,"description":"The device id.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"type":{"type":"string","enum":["rapid","full"]}}},"example":{"type":"rapid"}}}},"responses":{"202":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"object":{"type":"string","const":"device_action"},"action":{"type":"string"},"device_id":{"type":"string"},"status":{"type":"string","const":"accepted","description":"Always `accepted`. The device platform acknowledges an action once it has been dispatched to the hardware, not once the hardware has applied it — a restart or firmware update completes well after this response. Re-read the device to observe the effect."},"requested_at":{"type":"string"}},"required":["object","action","device_id","status","requested_at"],"additionalProperties":false,"id":"DeviceAction"},"example":{"object":"device_action","action":"speed_test","device_id":"0d5102c1-b8d2-4ba4-b6aa-43ed91d768c0","status":"accepted","requested_at":"2026-08-04T21:15:40.000Z"}}}},"400":{"description":"Malformed request — see `error.param`.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"401":{"description":"Missing, invalid, revoked, or expired API key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"403":{"description":"The key lacks a required scope, or the organization is not entitled.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"404":{"description":"No such resource.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"409":{"description":"The Idempotency-Key was already used for a different request body. Use a new key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"429":{"description":"Rate limit exceeded. Honour the `Retry-After` header.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"500":{"description":"Unexpected error. Quote `request_id` when reporting it.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}}}}},"/v1/devices/{uuid}/speed_tests":{"get":{"operationId":"listDeviceSpeedTests","summary":"List speed test results","description":"Completed speed test results, most recent first. The payload is returned as an opaque `data` object — its shape is undocumented upstream and varies by hardware model.","tags":["Device diagnostics"],"security":[{"bearerAuth":["devices:read"]}],"parameters":[{"name":"uuid","in":"path","required":true,"description":"The device id.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"object":{"type":"string","const":"list"},"data":{"type":"array","items":{"$ref":"#/$defs/DeviceReading"}},"has_more":{"type":"boolean"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Pass as `starting_after` for the next page."}},"required":["object","data","has_more","next_cursor"],"additionalProperties":false,"id":"DeviceReadingList","$defs":{"DeviceReading":{"type":"object","properties":{"object":{"type":"string","const":"device_reading"},"device_id":{"type":"string"},"kind":{"type":"string"},"recorded_at":{"anyOf":[{"type":"string"},{"type":"null"}]},"data":{}},"required":["object","device_id","kind","recorded_at","data"],"additionalProperties":false,"id":"DeviceReading"}}},"example":{"object":"list","data":[{"object":"device_reading","device_id":"0d5102c1-b8d2-4ba4-b6aa-43ed91d768c0","kind":"speed_test","recorded_at":"2026-08-04T09:15:40.000Z","data":{}}],"has_more":false,"next_cursor":null}}}},"400":{"description":"Malformed request — see `error.param`.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"401":{"description":"Missing, invalid, revoked, or expired API key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"403":{"description":"The key lacks a required scope, or the organization is not entitled.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"404":{"description":"No such resource.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"429":{"description":"Rate limit exceeded. Honour the `Retry-After` header.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"500":{"description":"Unexpected error. Quote `request_id` when reporting it.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}}}}},"/v1/devices/{uuid}/actions/network_scan":{"post":{"operationId":"startDeviceNetworkScan","summary":"Start a network scan","description":"Starts a network scan on the device. Results arrive asynchronously — poll the matching read endpoint.","tags":["Device diagnostics"],"security":[{"bearerAuth":["devices:write"]}],"parameters":[{"name":"uuid","in":"path","required":true,"description":"The device id.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}}],"responses":{"202":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"object":{"type":"string","const":"device_action"},"action":{"type":"string"},"device_id":{"type":"string"},"status":{"type":"string","const":"accepted","description":"Always `accepted`. The device platform acknowledges an action once it has been dispatched to the hardware, not once the hardware has applied it — a restart or firmware update completes well after this response. Re-read the device to observe the effect."},"requested_at":{"type":"string"}},"required":["object","action","device_id","status","requested_at"],"additionalProperties":false,"id":"DeviceAction"},"example":{"object":"device_action","action":"network_scan","device_id":"0d5102c1-b8d2-4ba4-b6aa-43ed91d768c0","status":"accepted","requested_at":"2026-08-04T21:15:40.000Z"}}}},"400":{"description":"Malformed request — see `error.param`.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"401":{"description":"Missing, invalid, revoked, or expired API key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"403":{"description":"The key lacks a required scope, or the organization is not entitled.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"404":{"description":"No such resource.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"409":{"description":"The Idempotency-Key was already used for a different request body. Use a new key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"429":{"description":"Rate limit exceeded. Honour the `Retry-After` header.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"500":{"description":"Unexpected error. Quote `request_id` when reporting it.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}}}}},"/v1/devices/{uuid}/network_scans":{"get":{"operationId":"listDeviceNetworkScans","summary":"List network scan results","description":"Completed network scan results, most recent first. The payload is returned as an opaque `data` object — its shape is undocumented upstream and varies by hardware model.","tags":["Device diagnostics"],"security":[{"bearerAuth":["devices:read"]}],"parameters":[{"name":"uuid","in":"path","required":true,"description":"The device id.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"object":{"type":"string","const":"list"},"data":{"type":"array","items":{"$ref":"#/$defs/DeviceReading"}},"has_more":{"type":"boolean"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Pass as `starting_after` for the next page."}},"required":["object","data","has_more","next_cursor"],"additionalProperties":false,"id":"DeviceReadingList","$defs":{"DeviceReading":{"type":"object","properties":{"object":{"type":"string","const":"device_reading"},"device_id":{"type":"string"},"kind":{"type":"string"},"recorded_at":{"anyOf":[{"type":"string"},{"type":"null"}]},"data":{}},"required":["object","device_id","kind","recorded_at","data"],"additionalProperties":false,"id":"DeviceReading"}}},"example":{"object":"list","data":[{"object":"device_reading","device_id":"0d5102c1-b8d2-4ba4-b6aa-43ed91d768c0","kind":"network_scan","recorded_at":"2026-08-04T09:15:40.000Z","data":{}}],"has_more":false,"next_cursor":null}}}},"400":{"description":"Malformed request — see `error.param`.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"401":{"description":"Missing, invalid, revoked, or expired API key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"403":{"description":"The key lacks a required scope, or the organization is not entitled.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"404":{"description":"No such resource.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"429":{"description":"Rate limit exceeded. Honour the `Retry-After` header.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"500":{"description":"Unexpected error. Quote `request_id` when reporting it.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}}}}},"/v1/devices/{uuid}/actions/network_diagnostic":{"post":{"operationId":"startDeviceNetworkDiagnostic","summary":"Start a network diagnostic","description":"Starts a network diagnostic on the device. Results arrive asynchronously — poll the matching read endpoint.\n\nThe diagnostic runs against a network group. It defaults to the one the device is on; pass `network_group_id` to test a different one.","tags":["Device diagnostics"],"security":[{"bearerAuth":["devices:write"]}],"parameters":[{"name":"uuid","in":"path","required":true,"description":"The device id.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"network_group_id":{"type":"string"}}},"example":{}}}},"responses":{"202":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"object":{"type":"string","const":"device_action"},"action":{"type":"string"},"device_id":{"type":"string"},"status":{"type":"string","const":"accepted","description":"Always `accepted`. The device platform acknowledges an action once it has been dispatched to the hardware, not once the hardware has applied it — a restart or firmware update completes well after this response. Re-read the device to observe the effect."},"requested_at":{"type":"string"}},"required":["object","action","device_id","status","requested_at"],"additionalProperties":false,"id":"DeviceAction"},"example":{"object":"device_action","action":"network_diagnostic","device_id":"0d5102c1-b8d2-4ba4-b6aa-43ed91d768c0","status":"accepted","requested_at":"2026-08-04T21:15:40.000Z"}}}},"400":{"description":"Malformed request — see `error.param`.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"401":{"description":"Missing, invalid, revoked, or expired API key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"403":{"description":"The key lacks a required scope, or the organization is not entitled.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"404":{"description":"No such resource.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"409":{"description":"The Idempotency-Key was already used for a different request body. Use a new key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"429":{"description":"Rate limit exceeded. Honour the `Retry-After` header.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"500":{"description":"Unexpected error. Quote `request_id` when reporting it.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}}}}},"/v1/devices/{uuid}/network_diagnostics":{"get":{"operationId":"listDeviceNetworkDiagnostics","summary":"List network diagnostic results","description":"Completed network diagnostic results, most recent first. The payload is returned as an opaque `data` object — its shape is undocumented upstream and varies by hardware model.","tags":["Device diagnostics"],"security":[{"bearerAuth":["devices:read"]}],"parameters":[{"name":"uuid","in":"path","required":true,"description":"The device id.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"object":{"type":"string","const":"list"},"data":{"type":"array","items":{"$ref":"#/$defs/DeviceReading"}},"has_more":{"type":"boolean"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Pass as `starting_after` for the next page."}},"required":["object","data","has_more","next_cursor"],"additionalProperties":false,"id":"DeviceReadingList","$defs":{"DeviceReading":{"type":"object","properties":{"object":{"type":"string","const":"device_reading"},"device_id":{"type":"string"},"kind":{"type":"string"},"recorded_at":{"anyOf":[{"type":"string"},{"type":"null"}]},"data":{}},"required":["object","device_id","kind","recorded_at","data"],"additionalProperties":false,"id":"DeviceReading"}}},"example":{"object":"list","data":[{"object":"device_reading","device_id":"0d5102c1-b8d2-4ba4-b6aa-43ed91d768c0","kind":"network_diagnostic","recorded_at":"2026-08-04T09:15:40.000Z","data":{}}],"has_more":false,"next_cursor":null}}}},"400":{"description":"Malformed request — see `error.param`.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"401":{"description":"Missing, invalid, revoked, or expired API key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"403":{"description":"The key lacks a required scope, or the organization is not entitled.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"404":{"description":"No such resource.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"429":{"description":"Rate limit exceeded. Honour the `Retry-After` header.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"500":{"description":"Unexpected error. Quote `request_id` when reporting it.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}}}}},"/v1/network_groups":{"get":{"operationId":"listNetworkGroups","summary":"List network groups","description":"The network groups a device can be activated on or moved between. Take an `id` from here for `activate` or a network group change.","tags":["Device networking"],"security":[{"bearerAuth":["devices:read"]}],"parameters":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"object":{"type":"string","const":"list"},"data":{"type":"array","items":{"$ref":"#/$defs/NetworkGroup"}},"has_more":{"type":"boolean"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Pass as `starting_after` for the next page."}},"required":["object","data","has_more","next_cursor"],"additionalProperties":false,"id":"NetworkGroupList","$defs":{"NetworkGroup":{"type":"object","properties":{"object":{"type":"string","const":"network_group"},"id":{"type":"string"},"name":{"type":"string"}},"required":["object","id","name"],"additionalProperties":false,"id":"NetworkGroup"}}},"example":{"object":"list","data":[{"object":"network_group","id":"0d5102c1-b8d2-4ba4-b6aa-43ed91d768c0","name":"Nationwide"}],"has_more":false,"next_cursor":null}}}},"400":{"description":"Malformed request — see `error.param`.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"401":{"description":"Missing, invalid, revoked, or expired API key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"403":{"description":"The key lacks a required scope, or the organization is not entitled.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"429":{"description":"Rate limit exceeded. Honour the `Retry-After` header.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"500":{"description":"Unexpected error. Quote `request_id` when reporting it.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}}}}},"/v1/data_plans":{"get":{"operationId":"listDataPlans","summary":"List data plans","description":"The data plans a device can be assigned. Distinct from `/v1/plans`, which lists the SERVICE plans sold to end customers.","tags":["Devices"],"security":[{"bearerAuth":["devices:read"]}],"parameters":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"object":{"type":"string","const":"list"},"data":{"type":"array","items":{"$ref":"#/$defs/DataPlan"}},"has_more":{"type":"boolean"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Pass as `starting_after` for the next page."}},"required":["object","data","has_more","next_cursor"],"additionalProperties":false,"id":"DataPlanList","$defs":{"DataPlan":{"type":"object","properties":{"object":{"type":"string","const":"data_plan"},"id":{"type":"string"},"name":{"type":"string"}},"required":["object","id","name"],"additionalProperties":false,"id":"DataPlan"}}},"example":{"object":"list","data":[{"object":"data_plan","id":"7b2f1a90-2c31-4c0e-9f77-1a2b3c4d5e6f","name":"M11 Device plan"}],"has_more":false,"next_cursor":null}}}},"400":{"description":"Malformed request — see `error.param`.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"401":{"description":"Missing, invalid, revoked, or expired API key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"403":{"description":"The key lacks a required scope, or the organization is not entitled.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"429":{"description":"Rate limit exceeded. Honour the `Retry-After` header.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"500":{"description":"Unexpected error. Quote `request_id` when reporting it.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}}}}},"/v1/quotes":{"post":{"operationId":"createQuote","summary":"Price a basket","description":"Returns what a basket would cost, with no side effects — nothing is created, nothing is reserved, and a quote cannot be redeemed. Call it as often as a cart changes.\n\nLines are itemized by `kind`. Read `activation` lines carefully: those charges are **not** in `due_now` and begin when the device is activated. A plan sold on warehouse-shipped hardware always defers this way, because its service line does not exist until fulfillment picks a unit and its serial is known. Hardware the customer already holds (`source: \"provided\"`) bills its plan today instead.\n\nAmounts are estimates. The authoritative figure is `totals.due_now` on a checkout session.","tags":["Quotes"],"security":[{"bearerAuth":["quotes:write"]}],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"packages":{"minItems":1,"maxItems":50,"type":"array","items":{"$ref":"#/$defs/CheckoutPackage"}},"shipping_address":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"line1":{"type":"string","minLength":1,"maxLength":500},"line2":{"type":"string","maxLength":500},"city":{"type":"string","minLength":1,"maxLength":255},"state":{"type":"string","minLength":1,"maxLength":100},"postal_code":{"type":"string","minLength":1,"maxLength":20},"country":{"default":"US","type":"string","minLength":2,"maxLength":2}},"required":["city","state","postal_code"]}},"required":["packages"],"id":"CreateQuoteRequest","description":"Prices a basket without creating anything. Safe to call as often as you like.","$defs":{"CheckoutPackage":{"type":"object","properties":{"package_id":{"type":"string","minLength":1,"maxLength":64,"description":"Your own identifier for this package, unique within the request. Echoed back so you can match priced lines to what you sent."},"device":{"type":"object","properties":{"product_id":{"type":"string","minLength":1,"description":"A product `id` from GET /v1/products."},"quantity":{"default":1,"type":"integer","minimum":1,"maximum":999},"billing":{"default":"purchase","description":"`eaas` rents the hardware instead of selling it, and requires a plan. `lease` is set by the product, not chosen: a product with `lease: true` always bills monthly with its plan, whatever is sent here.","type":"string","enum":["purchase","eaas","lease"]},"source":{"default":"warehouse","description":"`warehouse` ships a unit from stock. `provided` activates equipment the customer already holds — requires a plan and the identifier for its kind, and is never charged for hardware.","type":"string","enum":["warehouse","provided"]},"kind":{"default":"device","description":"`device` is identified by serial number, `sim` by ICCID.","type":"string","enum":["device","sim"]},"serial":{"type":"string","minLength":3,"maxLength":64},"iccid":{"type":"string","minLength":5,"maxLength":32}},"required":["product_id"]},"plan":{"type":"object","properties":{"plan_id":{"type":"string","minLength":1,"description":"A plan `id` from GET /v1/plans."}},"required":["plan_id"]},"addons":{"default":[],"maxItems":20,"type":"array","items":{"type":"object","properties":{"product_id":{"type":"string","minLength":1},"quantity":{"default":1,"type":"integer","minimum":1,"maximum":999}},"required":["product_id"]}}},"required":["package_id","device"],"id":"CheckoutPackage"}}},"example":{"packages":[{"package_id":"pkg_1","device":{"product_id":"1","quantity":1,"billing":"purchase","source":"warehouse"},"plan":{"plan_id":"12"},"addons":[]}],"shipping_address":{"line1":"100 Congress Ave","city":"Austin","state":"TX","postal_code":"78701"}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"object":{"type":"string","const":"quote"},"totals":{"$ref":"#/$defs/QuoteTotals"},"lines":{"type":"array","items":{"$ref":"#/$defs/QuoteLine"}}},"required":["object","totals","lines"],"additionalProperties":false,"id":"Quote","$defs":{"QuoteTotals":{"type":"object","properties":{"currency":{"type":"string","const":"USD"},"subtotal":{"anyOf":[{"type":"string"},{"type":"null"}]},"tax":{"anyOf":[{"type":"string"},{"type":"null"}]},"shipping":{"anyOf":[{"type":"string"},{"type":"null"}]},"due_now":{"anyOf":[{"type":"string"},{"type":"null"}]},"recurring_monthly":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["currency","subtotal","tax","shipping","due_now","recurring_monthly"],"additionalProperties":false,"id":"QuoteTotals"},"QuoteLine":{"type":"object","properties":{"object":{"type":"string","const":"quote_line"},"product_id":{"type":"string"},"name":{"type":"string"},"category":{"anyOf":[{"type":"string"},{"type":"null"}]},"kind":{"type":"string","enum":["item","fee","eaas_fee","shipping","activation"],"description":"`item` is something you asked for; `fee` and `shipping` are added by the billing platform; `eaas_fee` is the rental fee on an EaaS package; `activation` bills later, when the device is activated."},"quantity":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"unit_price":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["object","product_id","name","category","kind","quantity","unit_price","amount"],"additionalProperties":false,"id":"QuoteLine"}}},"example":{"object":"quote","totals":{"currency":"USD","subtotal":"379.00","tax":"31.27","shipping":"12.60","due_now":"412.87","recurring_monthly":"49.99"},"lines":[{"object":"quote_line","product_id":"1","name":"MergeWiFi M11 Router","category":"hardware","kind":"item","quantity":1,"unit_price":"379.00","amount":"379.00"},{"object":"quote_line","product_id":"88","name":"Unlimited 5G","category":"plan","kind":"activation","quantity":1,"unit_price":"49.99","amount":"49.99"}]}}}},"400":{"description":"Malformed request — see `error.param`.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"401":{"description":"Missing, invalid, revoked, or expired API key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"403":{"description":"The key lacks a required scope, or the organization is not entitled.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"429":{"description":"Rate limit exceeded. Honour the `Retry-After` header.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"500":{"description":"Unexpected error. Quote `request_id` when reporting it.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"503":{"description":"An upstream dependency is unavailable. Retry shortly.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}}}}},"/v1/customers":{"get":{"operationId":"listCustomers","summary":"List customers","description":"The end customers on your account, newest first. Search across name, email and phone with `q`, or filter by `status`.\n\nPass an `id` from here as `customer_id` when opening a checkout session to bind the sale to that customer's existing billing account instead of matching on their email address.","tags":["Customers"],"security":[{"bearerAuth":["customers:read"]}],"parameters":[{"name":"limit","in":"query","required":false,"description":"Rows to return, 1–100. Defaults to 25. Out-of-range values are rejected rather than clamped, so a client cannot silently receive fewer rows than it asked for.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","default":25,"type":"integer","minimum":1,"maximum":100}},{"name":"page","in":"query","required":false,"description":"1-based page number. This collection pages by number rather than by cursor, so `next_cursor` is always null.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"integer","minimum":1,"maximum":9007199254740991}},{"name":"q","in":"query","required":false,"description":"Free-text match across first name, last name, email and phone.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}},{"name":"status","in":"query","required":false,"description":"Exact match, e.g. `active`, `paused`, `cancelled`. Customers synced from billing carry that platform's own states.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"object":{"type":"string","const":"list"},"data":{"type":"array","items":{"$ref":"#/$defs/Customer"}},"has_more":{"type":"boolean"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Pass as `starting_after` for the next page."}},"required":["object","data","has_more","next_cursor"],"additionalProperties":false,"id":"CustomerList","$defs":{"Customer":{"type":"object","properties":{"object":{"type":"string","const":"customer"},"id":{"type":"string"},"first_name":{"type":"string"},"last_name":{"type":"string"},"email":{"anyOf":[{"type":"string"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string","description":"`active`, `paused` or `cancelled` for customers you created, or the billing platform's own subscriber state for synced ones."},"plan_name":{"anyOf":[{"type":"string"},{"type":"null"}]},"monthly_rate":{"anyOf":[{"type":"string"},{"type":"null"}]},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}]},"updated_at":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["object","id","first_name","last_name","email","phone","status","plan_name","monthly_rate","created_at","updated_at"],"additionalProperties":false,"id":"Customer"}}},"example":{"object":"list","data":[{"object":"customer","id":"8f14e45f-ceea-467a-9c5b-1d0f2a3b4c5d","first_name":"Dana","last_name":"Reyes","email":"dana@example.com","phone":"5125550142","status":"active","plan_name":"Unlimited 5G","monthly_rate":"49.99","created_at":"2026-07-02T15:20:00.000Z","updated_at":"2026-08-19T11:04:00.000Z"}],"has_more":false,"next_cursor":null}}}},"400":{"description":"Malformed request — see `error.param`.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"401":{"description":"Missing, invalid, revoked, or expired API key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"403":{"description":"The key lacks a required scope, or the organization is not entitled.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"429":{"description":"Rate limit exceeded. Honour the `Retry-After` header.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"500":{"description":"Unexpected error. Quote `request_id` when reporting it.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}}}}},"/v1/customers/{id}":{"get":{"operationId":"getCustomer","summary":"Retrieve a customer","description":"One end customer on your account.","tags":["Customers"],"security":[{"bearerAuth":["customers:read"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"The customer `id`.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"object":{"type":"string","const":"customer"},"id":{"type":"string"},"first_name":{"type":"string"},"last_name":{"type":"string"},"email":{"anyOf":[{"type":"string"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string","description":"`active`, `paused` or `cancelled` for customers you created, or the billing platform's own subscriber state for synced ones."},"plan_name":{"anyOf":[{"type":"string"},{"type":"null"}]},"monthly_rate":{"anyOf":[{"type":"string"},{"type":"null"}]},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}]},"updated_at":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["object","id","first_name","last_name","email","phone","status","plan_name","monthly_rate","created_at","updated_at"],"additionalProperties":false,"id":"Customer"},"example":{"object":"customer","id":"8f14e45f-ceea-467a-9c5b-1d0f2a3b4c5d","first_name":"Dana","last_name":"Reyes","email":"dana@example.com","phone":"5125550142","status":"active","plan_name":"Unlimited 5G","monthly_rate":"49.99","created_at":"2026-07-02T15:20:00.000Z","updated_at":"2026-08-19T11:04:00.000Z"}}}},"400":{"description":"Malformed request — see `error.param`.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"401":{"description":"Missing, invalid, revoked, or expired API key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"403":{"description":"The key lacks a required scope, or the organization is not entitled.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"404":{"description":"No such resource.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"429":{"description":"Rate limit exceeded. Honour the `Retry-After` header.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"500":{"description":"Unexpected error. Quote `request_id` when reporting it.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}}}}},"/v1/payment_config":{"get":{"operationId":"getPaymentConfig","summary":"Get publishable payment credentials","description":"The credentials your own front end needs to tokenize a card.\n\nThe billing platform accepts only an opaque, single-use nonce, and that nonce can only be minted by the payment gateway's browser SDK — so a card must be tokenized in a browser. These values let it be tokenized in **your** browser, against our gateway, which means card details never reach your servers or ours.\n\nFetch this from your backend, then pass `client_key` and `api_login_id` to your page and hand them to the gateway SDK as `clientKey` and `apiLoginID`. Both are publishable and safe to expose. **Your API key is not** — it must never appear in browser code, and this API sends no CORS headers, so a browser cannot call it directly.\n\nSend `payment_type_id` back when settling a session.","tags":["Checkout"],"security":[{"bearerAuth":["orders:write"]}],"parameters":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"object":{"type":"string","const":"payment_config"},"client_key":{"type":"string"},"api_login_id":{"type":"string"},"payment_type_id":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"environment":{"type":"string","enum":["production","sandbox"]},"gateway":{"type":"string","const":"authorize_net"}},"required":["object","client_key","api_login_id","payment_type_id","environment","gateway"],"additionalProperties":false,"id":"PaymentConfig","description":"Publishable credentials for tokenizing a card in your own front end. Safe to hand to a browser; the API key that fetched them is not."},"example":{"object":"payment_config","client_key":"9Aq2Xk7fPd4tYb6R…","api_login_id":"5KpN3xW8","payment_type_id":7,"environment":"production","gateway":"authorize_net"}}}},"400":{"description":"Malformed request — see `error.param`.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"401":{"description":"Missing, invalid, revoked, or expired API key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"403":{"description":"The key lacks a required scope, or the organization is not entitled.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"429":{"description":"Rate limit exceeded. Honour the `Retry-After` header.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"500":{"description":"Unexpected error. Quote `request_id` when reporting it.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"503":{"description":"An upstream dependency is unavailable. Retry shortly.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}}}}},"/v1/checkout_sessions":{"post":{"operationId":"createCheckoutSession","summary":"Open a point-of-sale session","description":"Starts a retail sale: creates the customer's billing account if it does not exist, registers any equipment they already hold, builds the order and prices it with tax.\n\n**Nothing is charged.** The session returns `awaiting_payment` with the authoritative `totals.due_now`; settle it with the pay action once you have tokenized a card for exactly that amount.\n\nPayment is a second call on purpose. A gateway nonce is single-use, so combining the two would burn one on a total you had not yet seen — and an integration has no one to re-key a card when that happens. Creating the session first means you always tokenize against the real number.\n\nThe request carries no prices: every amount is resolved from the same catalog `/v1/products` and `/v1/plans` serve.","tags":["Checkout"],"security":[{"bearerAuth":["orders:write"]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":true,"description":"A fresh unique value (a UUID) per sale. Replaying it with the same basket returns the original session with a 200; reusing it for a different basket is a 409.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"customer":{"type":"object","properties":{"first_name":{"type":"string","minLength":1,"maxLength":255},"last_name":{"type":"string","minLength":1,"maxLength":255},"email":{"type":"string","maxLength":255,"format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},"phone":{"description":"Saved as the contact number on the customer's billing account when it's a 10-digit US number (formatting and a leading 1 are fine). An existing account's number is only filled in, never replaced.","type":"string","maxLength":50}},"required":["first_name","last_name"]},"customer_id":{"description":"A customer `id` from GET /v1/customers. Binds the sale to that customer's existing billing account instead of matching on email.","type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"shipping_address":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"line1":{"type":"string","minLength":1,"maxLength":500},"line2":{"type":"string","maxLength":500},"city":{"type":"string","minLength":1,"maxLength":255},"state":{"type":"string","minLength":1,"maxLength":100},"postal_code":{"type":"string","minLength":1,"maxLength":20},"country":{"default":"US","type":"string","minLength":2,"maxLength":2}},"required":["line1","city","state","postal_code"]},"packages":{"minItems":1,"maxItems":50,"type":"array","items":{"$ref":"#/$defs/CheckoutPackage"}},"notes":{"type":"string","maxLength":2000}},"required":["customer","shipping_address","packages"],"id":"CreateCheckoutSessionRequest","description":"Creates the order and prices it. Nothing is charged — settle it with the pay action.","$defs":{"CheckoutPackage":{"type":"object","properties":{"package_id":{"type":"string","minLength":1,"maxLength":64,"description":"Your own identifier for this package, unique within the request. Echoed back so you can match priced lines to what you sent."},"device":{"type":"object","properties":{"product_id":{"type":"string","minLength":1,"description":"A product `id` from GET /v1/products."},"quantity":{"default":1,"type":"integer","minimum":1,"maximum":999},"billing":{"default":"purchase","description":"`eaas` rents the hardware instead of selling it, and requires a plan. `lease` is set by the product, not chosen: a product with `lease: true` always bills monthly with its plan, whatever is sent here.","type":"string","enum":["purchase","eaas","lease"]},"source":{"default":"warehouse","description":"`warehouse` ships a unit from stock. `provided` activates equipment the customer already holds — requires a plan and the identifier for its kind, and is never charged for hardware.","type":"string","enum":["warehouse","provided"]},"kind":{"default":"device","description":"`device` is identified by serial number, `sim` by ICCID.","type":"string","enum":["device","sim"]},"serial":{"type":"string","minLength":3,"maxLength":64},"iccid":{"type":"string","minLength":5,"maxLength":32}},"required":["product_id"]},"plan":{"type":"object","properties":{"plan_id":{"type":"string","minLength":1,"description":"A plan `id` from GET /v1/plans."}},"required":["plan_id"]},"addons":{"default":[],"maxItems":20,"type":"array","items":{"type":"object","properties":{"product_id":{"type":"string","minLength":1},"quantity":{"default":1,"type":"integer","minimum":1,"maximum":999}},"required":["product_id"]}}},"required":["package_id","device"],"id":"CheckoutPackage"}}},"example":{"customer":{"first_name":"Dana","last_name":"Reyes","email":"dana@example.com","phone":"5125550142"},"shipping_address":{"line1":"100 Congress Ave","city":"Austin","state":"TX","postal_code":"78701"},"packages":[{"package_id":"pkg_1","device":{"product_id":"1","quantity":1,"billing":"purchase","source":"warehouse"},"plan":{"plan_id":"12"},"addons":[]}]}}}},"responses":{"200":{"description":"The Idempotency-Key matched an existing request; the original resource is returned and nothing was created.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"object":{"type":"string","const":"checkout_session"},"id":{"type":"string"},"status":{"type":"string","enum":["awaiting_payment","payment_failed","paid","submitted","submit_failed","cancelled"]},"customer":{"type":"object","properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"anyOf":[{"type":"string"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["name","email","phone"],"additionalProperties":false},"totals":{"type":"object","properties":{"currency":{"type":"string","const":"USD"},"subtotal":{"anyOf":[{"type":"string"},{"type":"null"}]},"tax":{"anyOf":[{"type":"string"},{"type":"null"}]},"total":{"anyOf":[{"type":"string"},{"type":"null"}]},"due_now":{"anyOf":[{"type":"string"},{"type":"null"}]},"recurring_monthly":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["currency","subtotal","tax","total","due_now","recurring_monthly"],"additionalProperties":false},"payment_method":{"anyOf":[{"type":"object","properties":{"brand":{"anyOf":[{"type":"string"},{"type":"null"}]},"last4":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["brand","last4"],"additionalProperties":false},{"type":"null"}]},"submitted_at":{"anyOf":[{"type":"string"},{"type":"null"}]},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}]},"updated_at":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["object","id","status","customer","totals","payment_method","submitted_at","created_at","updated_at"],"additionalProperties":false,"id":"CheckoutSession"}}}},"201":{"description":"Created","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"object":{"type":"string","const":"checkout_session"},"id":{"type":"string"},"status":{"type":"string","enum":["awaiting_payment","payment_failed","paid","submitted","submit_failed","cancelled"]},"customer":{"type":"object","properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"anyOf":[{"type":"string"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["name","email","phone"],"additionalProperties":false},"totals":{"type":"object","properties":{"currency":{"type":"string","const":"USD"},"subtotal":{"anyOf":[{"type":"string"},{"type":"null"}]},"tax":{"anyOf":[{"type":"string"},{"type":"null"}]},"total":{"anyOf":[{"type":"string"},{"type":"null"}]},"due_now":{"anyOf":[{"type":"string"},{"type":"null"}]},"recurring_monthly":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["currency","subtotal","tax","total","due_now","recurring_monthly"],"additionalProperties":false},"payment_method":{"anyOf":[{"type":"object","properties":{"brand":{"anyOf":[{"type":"string"},{"type":"null"}]},"last4":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["brand","last4"],"additionalProperties":false},{"type":"null"}]},"submitted_at":{"anyOf":[{"type":"string"},{"type":"null"}]},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}]},"updated_at":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["object","id","status","customer","totals","payment_method","submitted_at","created_at","updated_at"],"additionalProperties":false,"id":"CheckoutSession"},"example":{"object":"checkout_session","id":"3b1e77c2-9a4d-4f81-8c2e-77a90b1d5e64","status":"awaiting_payment","customer":{"name":"Dana Reyes","email":"dana@example.com","phone":"5125550142"},"totals":{"currency":"USD","subtotal":"379.00","tax":"31.27","total":"412.87","due_now":"412.87","recurring_monthly":"49.99"},"payment_method":null,"submitted_at":null,"created_at":"2026-08-26T18:41:02.000Z","updated_at":"2026-08-26T18:41:02.000Z"}}}},"400":{"description":"Malformed request — see `error.param`.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"401":{"description":"Missing, invalid, revoked, or expired API key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"403":{"description":"The key lacks a required scope, or the organization is not entitled.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"409":{"description":"The Idempotency-Key was already used for a different request body. Use a new key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"429":{"description":"Rate limit exceeded. Honour the `Retry-After` header.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"500":{"description":"Unexpected error. Quote `request_id` when reporting it.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"503":{"description":"An upstream dependency is unavailable. Retry shortly.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}}}}},"/v1/checkout_sessions/{id}":{"get":{"operationId":"getCheckoutSession","summary":"Retrieve a checkout session","description":"The current state of a sale. Poll this after a timeout to find out whether a payment landed before deciding to retry it.\n\n`totals.due_now` here is authoritative — it is what the billing platform will accept, and what `expected_total` must match when paying.\n\nA session and an order are the same record: this id also works on `GET /v1/orders/{id}`, which reports what was bought rather than what is left to do.","tags":["Checkout"],"security":[{"bearerAuth":["orders:read"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"The checkout session `id`.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"object":{"type":"string","const":"checkout_session"},"id":{"type":"string"},"status":{"type":"string","enum":["awaiting_payment","payment_failed","paid","submitted","submit_failed","cancelled"]},"customer":{"type":"object","properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"anyOf":[{"type":"string"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["name","email","phone"],"additionalProperties":false},"totals":{"type":"object","properties":{"currency":{"type":"string","const":"USD"},"subtotal":{"anyOf":[{"type":"string"},{"type":"null"}]},"tax":{"anyOf":[{"type":"string"},{"type":"null"}]},"total":{"anyOf":[{"type":"string"},{"type":"null"}]},"due_now":{"anyOf":[{"type":"string"},{"type":"null"}]},"recurring_monthly":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["currency","subtotal","tax","total","due_now","recurring_monthly"],"additionalProperties":false},"payment_method":{"anyOf":[{"type":"object","properties":{"brand":{"anyOf":[{"type":"string"},{"type":"null"}]},"last4":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["brand","last4"],"additionalProperties":false},{"type":"null"}]},"submitted_at":{"anyOf":[{"type":"string"},{"type":"null"}]},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}]},"updated_at":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["object","id","status","customer","totals","payment_method","submitted_at","created_at","updated_at"],"additionalProperties":false,"id":"CheckoutSession"},"example":{"object":"checkout_session","id":"3b1e77c2-9a4d-4f81-8c2e-77a90b1d5e64","status":"awaiting_payment","customer":{"name":"Dana Reyes","email":"dana@example.com","phone":"5125550142"},"totals":{"currency":"USD","subtotal":"379.00","tax":"31.27","total":"412.87","due_now":"412.87","recurring_monthly":"49.99"},"payment_method":null,"submitted_at":null,"created_at":"2026-08-26T18:41:02.000Z","updated_at":"2026-08-26T18:41:02.000Z"}}}},"400":{"description":"Malformed request — see `error.param`.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"401":{"description":"Missing, invalid, revoked, or expired API key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"403":{"description":"The key lacks a required scope, or the organization is not entitled.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"404":{"description":"No such resource.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"429":{"description":"Rate limit exceeded. Honour the `Retry-After` header.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"500":{"description":"Unexpected error. Quote `request_id` when reporting it.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}}}}},"/v1/checkout_sessions/{id}/actions/pay":{"post":{"operationId":"payCheckoutSession","summary":"Pay a checkout session","description":"Charges the card and submits the order. **This is the step that moves money.**\n\nSend a nonce your front end just minted with the gateway SDK, using the credentials from `GET /v1/payment_config`. A nonce is single-use and short-lived: mint one per attempt and never store one.\n\n`expected_total` must equal the session's current `totals.due_now`. It is you stating the amount you believe you are authorizing — if the total has moved, the charge is refused rather than billing a figure nobody agreed to.\n\nOn success the session is `submitted`. A `submit_failed` session **was charged** — handoff to fulfillment is being retried for you, so do not pay again. A decline returns 402 and leaves the session payable: mint a fresh nonce and call this again.","tags":["Checkout"],"security":[{"bearerAuth":["orders:write"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"The checkout session `id`.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"payment":{"type":"object","properties":{"nonce":{"type":"string","minLength":1,"maxLength":10000,"description":"`opaqueData.dataValue` from the payment gateway SDK. Single-use."},"data_descriptor":{"type":"string","minLength":1,"maxLength":255,"description":"`opaqueData.dataDescriptor` from the same tokenization call."},"payment_type_id":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991,"description":"From GET /v1/payment_config."}},"required":["nonce","data_descriptor","payment_type_id"]},"expected_total":{"type":"string","description":"The session's `totals.due_now`, echoed back. The charge is refused if the total has moved since you read it."}},"required":["payment","expected_total"],"id":"PayCheckoutSessionRequest"},"example":{"payment":{"nonce":"eyJjb2RlIjoiNTBfMl8wNjAwMDUyN0…","data_descriptor":"COMMON.ACCEPT.INAPP.PAYMENT","payment_type_id":7},"expected_total":"412.87"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"object":{"type":"string","const":"checkout_session"},"id":{"type":"string"},"status":{"type":"string","enum":["awaiting_payment","payment_failed","paid","submitted","submit_failed","cancelled"]},"customer":{"type":"object","properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"anyOf":[{"type":"string"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["name","email","phone"],"additionalProperties":false},"totals":{"type":"object","properties":{"currency":{"type":"string","const":"USD"},"subtotal":{"anyOf":[{"type":"string"},{"type":"null"}]},"tax":{"anyOf":[{"type":"string"},{"type":"null"}]},"total":{"anyOf":[{"type":"string"},{"type":"null"}]},"due_now":{"anyOf":[{"type":"string"},{"type":"null"}]},"recurring_monthly":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["currency","subtotal","tax","total","due_now","recurring_monthly"],"additionalProperties":false},"payment_method":{"anyOf":[{"type":"object","properties":{"brand":{"anyOf":[{"type":"string"},{"type":"null"}]},"last4":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["brand","last4"],"additionalProperties":false},{"type":"null"}]},"submitted_at":{"anyOf":[{"type":"string"},{"type":"null"}]},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}]},"updated_at":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["object","id","status","customer","totals","payment_method","submitted_at","created_at","updated_at"],"additionalProperties":false,"id":"CheckoutSession"},"example":{"object":"checkout_session","id":"3b1e77c2-9a4d-4f81-8c2e-77a90b1d5e64","status":"submitted","customer":{"name":"Dana Reyes","email":"dana@example.com","phone":"5125550142"},"totals":{"currency":"USD","subtotal":"379.00","tax":"31.27","total":"412.87","due_now":"412.87","recurring_monthly":"49.99"},"payment_method":{"brand":"Visa","last4":"4242"},"submitted_at":"2026-08-26T18:42:10.000Z","created_at":"2026-08-26T18:41:02.000Z","updated_at":"2026-08-26T18:41:02.000Z"}}}},"400":{"description":"Malformed request — see `error.param`.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"401":{"description":"Missing, invalid, revoked, or expired API key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"402":{"description":"The card was declined. The session is still payable — retry with a fresh nonce.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"403":{"description":"The key lacks a required scope, or the organization is not entitled.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"404":{"description":"No such resource.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"409":{"description":"The Idempotency-Key was already used for a different request body. Use a new key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"429":{"description":"Rate limit exceeded. Honour the `Retry-After` header.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"500":{"description":"Unexpected error. Quote `request_id` when reporting it.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"503":{"description":"An upstream dependency is unavailable. Retry shortly.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}}}}},"/v1/checkout_sessions/{id}/actions/cancel":{"post":{"operationId":"cancelCheckoutSession","summary":"Cancel a checkout session","description":"Abandons an unpaid sale and cancels the draft order behind it.\n\nWorth calling rather than walking away: an abandoned session leaves a draft order, and for provided equipment a draft service line, on the customer's account. They are harmless and a later sale reuses them, but a cancelled session is far easier to reconcile than a stalled one.\n\nOnly unpaid sessions can be cancelled. Once the card has been charged this returns 409 — reversing a payment is a refund, which this API does not do.","tags":["Checkout"],"security":[{"bearerAuth":["orders:write"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"The checkout session `id`.","schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"object":{"type":"string","const":"checkout_session"},"id":{"type":"string"},"status":{"type":"string","enum":["awaiting_payment","payment_failed","paid","submitted","submit_failed","cancelled"]},"customer":{"type":"object","properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"anyOf":[{"type":"string"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["name","email","phone"],"additionalProperties":false},"totals":{"type":"object","properties":{"currency":{"type":"string","const":"USD"},"subtotal":{"anyOf":[{"type":"string"},{"type":"null"}]},"tax":{"anyOf":[{"type":"string"},{"type":"null"}]},"total":{"anyOf":[{"type":"string"},{"type":"null"}]},"due_now":{"anyOf":[{"type":"string"},{"type":"null"}]},"recurring_monthly":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["currency","subtotal","tax","total","due_now","recurring_monthly"],"additionalProperties":false},"payment_method":{"anyOf":[{"type":"object","properties":{"brand":{"anyOf":[{"type":"string"},{"type":"null"}]},"last4":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["brand","last4"],"additionalProperties":false},{"type":"null"}]},"submitted_at":{"anyOf":[{"type":"string"},{"type":"null"}]},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}]},"updated_at":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["object","id","status","customer","totals","payment_method","submitted_at","created_at","updated_at"],"additionalProperties":false,"id":"CheckoutSession"},"example":{"object":"checkout_session","id":"3b1e77c2-9a4d-4f81-8c2e-77a90b1d5e64","status":"cancelled","customer":{"name":"Dana Reyes","email":"dana@example.com","phone":"5125550142"},"totals":{"currency":"USD","subtotal":"379.00","tax":"31.27","total":"412.87","due_now":"412.87","recurring_monthly":"49.99"},"payment_method":null,"submitted_at":null,"created_at":"2026-08-26T18:41:02.000Z","updated_at":"2026-08-26T18:41:02.000Z"}}}},"400":{"description":"Malformed request — see `error.param`.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"401":{"description":"Missing, invalid, revoked, or expired API key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"403":{"description":"The key lacks a required scope, or the organization is not entitled.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"404":{"description":"No such resource.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"409":{"description":"The Idempotency-Key was already used for a different request body. Use a new key.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"429":{"description":"Rate limit exceeded. Honour the `Retry-After` header.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}},"500":{"description":"Unexpected error. Quote `request_id` when reporting it.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"An API key issued from the partner portal."}},"schemas":{"Error":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","not_found_error","rate_limit_error","idempotency_error","payment_error","conflict_error","service_unavailable_error","api_error"]},"code":{"type":"string","example":"missing_scope"},"message":{"type":"string"},"request_id":{"type":"string","example":"req_4d00a64235084c1e85dda9c969709906"},"param":{"description":"Offending field, for validation errors.","type":"string"}},"required":["type","code","message","request_id"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"id":"Error","description":"Every non-2xx response uses this shape."}}}}