{"openapi":"3.0.3","info":{"title":"PacketExchange API","description":"Carrier-to-carrier voice and SMS marketplace API.\n\n## Authentication\nSend `Authorization: Bearer <api key>`, using an API key (`wmmn_live_sk_...` live, `wmmn_test_sk_...` test) created in the dashboard under **API keys**. Some account-management operations are **session-only** and refuse API keys; each operation states its access rule and, for scoped keys, the scope it needs.\n\n## Envelope\nSuccess: `{ \"success\": true, \"data\": ... }` (list endpoints may add `nextCursor` and `hasMore`). Failure: `{ \"success\": false, \"error\": { \"code\", \"message\", \"details\" } }`. For `VALIDATION_ERROR`, `details` is an array of `{ path, message }`.\n\n## Money\nEvery ledger amount is US dollars as a decimal **string** with exactly 6 places (`\"0.012500\"`). Voice prices are per minute; SMS prices are per message segment.\n\n## Rate limits\nDefault: 100 requests per second per caller (API key, session or IP address). Operations with a tighter limit state it, generated from the route's own configuration. A 429 carries `Retry-After`.\n\n## Request ids\nEvery response carries `X-Request-Id` (a UUID). Quote it when contacting support.\n\n## Error codes\n| Status | Code | Meaning |\n|---|---|---|\n| 400 | `VALIDATION_ERROR` | The body, query or path failed validation, or a business rule refused the input. Insufficient balance for a billable action is also reported this way, with a message that starts \"Insufficient balance\". |\n| 400 | `INVALID_INPUT` | A value passed validation but is not in a storable format, most often a malformed id (not a UUID) in the path or query, a number out of range, or text containing characters that cannot be stored (for example a NUL byte). |\n| 400 | `BAD_REQUEST` | The request could not be parsed, for example malformed JSON or an unsupported content type. |\n| 401 | `UNAUTHORIZED` | No credential, or the token or API key is invalid, expired or revoked. |\n| 402 | `SWITCH_SUBSCRIPTION_REQUIRED` | The Switch endpoint needs an active Switch plan or trial on the account. |\n| 403 | `FORBIDDEN` | Authenticated but not allowed. For a scoped API key the message names the missing scope (\"API key missing required scope: sms:send\"); session-only endpoints answer \"This action requires an interactive session (dashboard login), not an API key.\" |\n| 403 | `TEST_KEY_NOT_ALLOWED` | A test key (wmmn_test_sk_) asked for something that has no test mode: a Switch change (any non-GET request under /switch) or an x402 top-up, which settles real USDC into the live balance. Use a live key. Test keys may still read Switch data. |\n| 403 | `KYC_REQUIRED` | The action needs a verified identity first (Account > Verification). |\n| 404 | `NOT_FOUND` | The resource does not exist, or it is not visible to your account. |\n| 409 | `CONFLICT` | The record already exists, is referenced elsewhere, or a request with the same X-Idempotency-Key is still in progress. |\n| 409 | `STALE_WRITE` | Someone else changed this Switch record after you loaded it. Reload and re-apply your change. |\n| 409 | `INVOICE_REVIEW_STALE` | Switch invoicing: the data changed since the invoice review was built. Review again, then issue. |\n| 409 | `INVOICE_UNRATED_USAGE` | Switch invoicing: unrated usage sits inside the invoice period. Rate it (or exclude it) before issuing. |\n| 409 | `SWITCH_NO_SUBSCRIPTION` | Switch billing: there is no Switch subscription on this account to manage. |\n| 409 | `EXPORT_NOT_READY` | CDR exports: GET /billing/exports/{id}/download was called before the export finished (or after it failed). Poll the job until it is done. |\n| 410 | `EXPORT_EXPIRED` | CDR exports: the export finished, but its file has since been deleted by the retention sweep. Queue a new export. |\n| 422 | `VALIDATION_ERROR` | An X-Idempotency-Key was reused with a different request body. Use a fresh key for a different request. |\n| 429 | `RATE_LIMITED` | Too many requests. Wait for the number of seconds in the Retry-After header, then retry. |\n| 429 | `TOO_MANY_EXPORTS` | You already have exports in progress. Wait for one to finish. |\n| 500 | `INTERNAL_ERROR` | An unexpected server error. It has been logged; quote the X-Request-Id header when contacting support. |\n| 502 | `UPSTREAM_ERROR` | A service we depend on failed. Retry shortly. |\n| 502 | `STRIPE_ERROR` | Card payments: the card processor could not start the payment. Retry shortly. |\n| 503 | `SERVICE_UNAVAILABLE` | Temporarily unavailable. Retry with backoff. |\n| 503 | `STRIPE_DISABLED` | Card payments are not enabled on this platform yet. |\n| 503 | `SWITCH_BILLING_UNCONFIGURED` | Switch billing: this plan cannot be bought online yet. Contact sales. |\n| 503 | `SWITCH_PRICE_MISMATCH` | Switch billing: this plan cannot be bought online right now. Contact sales. |\n| 503 | `WIRE_UNAVAILABLE` | Wire top-ups are not available right now. |\n| 503 | `AI_UNAVAILABLE` | Switch AI Control cannot reach its model. Nothing was changed; the manual controls still work. |","version":"1.2.0"},"servers":[{"url":"https://packetexchange.io","description":"Production"}],"tags":[{"name":"Account","description":"Your profile, balance, preferences, team and account-level settings."},{"name":"API keys","description":"Create, scope and revoke API keys. Dashboard session only: a key can never mint or list keys."},{"name":"API usage","description":"Request volume, error rate and latency for your own API traffic."},{"name":"Webhooks","description":"Endpoints we POST signed events to, their delivery history and resends."},{"name":"Marketplace routes","description":"Browse, resolve, list and manage voice and SMS termination routes."},{"name":"Route checks","description":"Check up to three routes with a short real call before you buy them, then buy the ones that passed with the routing order set."},{"name":"Rate sheets","description":"Upload and manage per-prefix rate decks on routes you sell."},{"name":"Route blends","description":"Blended routes that spread traffic across several member routes."},{"name":"Purchases","description":"Buy access to marketplace routes and manage what you bought."},{"name":"Offers","description":"Propose, counter and accept prices on marketplace routes."},{"name":"Route access","description":"Request and grant access to private marketplace routes."},{"name":"Route messages","description":"Buyer and seller conversations about a route."},{"name":"Route reports","description":"Report a problem with a route you bought."},{"name":"Markets","description":"Market-wide rate indices across destinations."},{"name":"Voice and SMS","description":"Place single calls and send single SMS over the routes you bought, and read their history."},{"name":"Verify","description":"One-time passcodes by SMS or voice call: send a code, then check what the user typed. We keep only a hash of the code."},{"name":"Number lookup","description":"Validate a number and see its country, line type, network, risk and cheapest live price. Prefix-based, free."},{"name":"Phone numbers","description":"The DID Store: search, buy, route and release phone numbers; SMS and softphone lines on them."},{"name":"Billing","description":"Ledger, invoices, statements, spending and exports. All amounts are USD 6-decimal strings."},{"name":"Top-ups","description":"Add funds by card, crypto or wire."},{"name":"Dialer","description":"Outbound dialer and SMS campaigns, their numbers, caller IDs and results."},{"name":"AI voice agents","description":"Build, preview and attach AI voice agents to campaigns."},{"name":"Do not call","description":"Your opt-out and suppression list, applied to dialer and SMS traffic."},{"name":"Interconnections","description":"The SIP IP whitelist and connectivity tests for your traffic."},{"name":"Connections","description":"Your SIP and SMPP connections to the exchange."},{"name":"Switch","description":"The carrier switch: account-level settings, mode and overview. Every Switch operation requires a Switch plan."},{"name":"Switch: customers","description":"Customers you sell to: accounts, balances, credit, contacts and lifecycle."},{"name":"Switch: customer trunks","description":"Customer trunks: addressing, credentials, limits, readiness and approvals."},{"name":"Switch: suppliers","description":"Suppliers and providers you buy from: accounts, trunks, admission and diagnostics."},{"name":"Switch: rating","description":"Rate decks, sell decks and sell rates: what you pay and what you charge."},{"name":"Switch: routing","description":"Route plans, dialplans, routing rules, ACLs and route traces."},{"name":"Switch: CDRs and analytics","description":"Call records, exports, saved views, margin, cost and quality analysis."},{"name":"Switch: invoicing","description":"Invoices, credit notes, payables, netting, settlement and ageing."},{"name":"Switch: operations","description":"NOC, live calls, issues, fraud, the operations queue and AI control."},{"name":"Switch: team and audit","description":"Roles, team members, approvals and the audit history."},{"name":"Application Manager","description":"Operate retail sub-accounts: provisioning, credit and routing."},{"name":"Revenue share numbers","description":"Revenue share number pools, taking numbers (single, bulk or by range), IVR, call delivery and payouts. API keys need `revshare:read` for reads and `revshare:write` for changes; payout requests are dashboard-session only. Webhook events: `revshare.call.received`, `revshare.number.taken`, `revshare.number.released`."},{"name":"Notifications","description":"In-app notifications for your account."},{"name":"Support","description":"Support tickets and the public contact form."},{"name":"Compliance","description":"Identity verification and US calling compliance."},{"name":"Status","description":"Public platform status, incidents and maintenance."},{"name":"System","description":"Health checks and service metadata."}],"x-error-codes":[{"code":"VALIDATION_ERROR","status":400,"meaning":"The body, query or path failed validation, or a business rule refused the input. Insufficient balance for a billable action is also reported this way, with a message that starts \"Insufficient balance\".","details":"An array of { path, message }, one per failing field. A business-rule refusal usually carries only the message; a few attach an object instead (Switch trunk activation sends { code: \"TRUNK_NOT_READY\", blockers: [...] })."},{"code":"INVALID_INPUT","status":400,"meaning":"A value passed validation but is not in a storable format, most often a malformed id (not a UUID) in the path or query, a number out of range, or text containing characters that cannot be stored (for example a NUL byte)."},{"code":"BAD_REQUEST","status":400,"meaning":"The request could not be parsed, for example malformed JSON or an unsupported content type."},{"code":"UNAUTHORIZED","status":401,"meaning":"No credential, or the token or API key is invalid, expired or revoked."},{"code":"SWITCH_SUBSCRIPTION_REQUIRED","status":402,"meaning":"The Switch endpoint needs an active Switch plan or trial on the account."},{"code":"FORBIDDEN","status":403,"meaning":"Authenticated but not allowed. For a scoped API key the message names the missing scope (\"API key missing required scope: sms:send\"); session-only endpoints answer \"This action requires an interactive session (dashboard login), not an API key.\""},{"code":"TEST_KEY_NOT_ALLOWED","status":403,"meaning":"A test key (wmmn_test_sk_) asked for something that has no test mode: a Switch change (any non-GET request under /switch) or an x402 top-up, which settles real USDC into the live balance. Use a live key. Test keys may still read Switch data."},{"code":"KYC_REQUIRED","status":403,"meaning":"The action needs a verified identity first (Account > Verification)."},{"code":"NOT_FOUND","status":404,"meaning":"The resource does not exist, or it is not visible to your account."},{"code":"CONFLICT","status":409,"meaning":"The record already exists, is referenced elsewhere, or a request with the same X-Idempotency-Key is still in progress."},{"code":"STALE_WRITE","status":409,"meaning":"Someone else changed this Switch record after you loaded it. Reload and re-apply your change.","details":"An object describing the newer version that won."},{"code":"INVOICE_REVIEW_STALE","status":409,"meaning":"Switch invoicing: the data changed since the invoice review was built. Review again, then issue."},{"code":"INVOICE_UNRATED_USAGE","status":409,"meaning":"Switch invoicing: unrated usage sits inside the invoice period. Rate it (or exclude it) before issuing.","details":"An object describing the blocking usage."},{"code":"SWITCH_NO_SUBSCRIPTION","status":409,"meaning":"Switch billing: there is no Switch subscription on this account to manage."},{"code":"EXPORT_NOT_READY","status":409,"meaning":"CDR exports: GET /billing/exports/{id}/download was called before the export finished (or after it failed). Poll the job until it is done."},{"code":"EXPORT_EXPIRED","status":410,"meaning":"CDR exports: the export finished, but its file has since been deleted by the retention sweep. Queue a new export."},{"code":"VALIDATION_ERROR","status":422,"meaning":"An X-Idempotency-Key was reused with a different request body. Use a fresh key for a different request."},{"code":"RATE_LIMITED","status":429,"meaning":"Too many requests. Wait for the number of seconds in the Retry-After header, then retry."},{"code":"TOO_MANY_EXPORTS","status":429,"meaning":"You already have exports in progress. Wait for one to finish."},{"code":"INTERNAL_ERROR","status":500,"meaning":"An unexpected server error. It has been logged; quote the X-Request-Id header when contacting support."},{"code":"UPSTREAM_ERROR","status":502,"meaning":"A service we depend on failed. Retry shortly."},{"code":"STRIPE_ERROR","status":502,"meaning":"Card payments: the card processor could not start the payment. Retry shortly."},{"code":"SERVICE_UNAVAILABLE","status":503,"meaning":"Temporarily unavailable. Retry with backoff."},{"code":"STRIPE_DISABLED","status":503,"meaning":"Card payments are not enabled on this platform yet."},{"code":"SWITCH_BILLING_UNCONFIGURED","status":503,"meaning":"Switch billing: this plan cannot be bought online yet. Contact sales."},{"code":"SWITCH_PRICE_MISMATCH","status":503,"meaning":"Switch billing: this plan cannot be bought online right now. Contact sales."},{"code":"WIRE_UNAVAILABLE","status":503,"meaning":"Wire top-ups are not available right now."},{"code":"AI_UNAVAILABLE","status":503,"meaning":"Switch AI Control cannot reach its model. Nothing was changed; the manual controls still work."}],"x-rate-limit-default":{"max":100,"window":"1 second"},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"API key","description":"An API key, as `Authorization: Bearer <api key>`."},"apiKeyAuth":{"type":"apiKey","in":"header","name":"Authorization","description":"An API key as the Authorization header value, with or without the `Bearer ` prefix."}},"schemas":{"Money":{"type":"string","pattern":"^-?\\d+\\.\\d{6}$","description":"US dollars as a decimal string with exactly 6 decimal places, e.g. \"0.012500\". Do money arithmetic with a decimal type, not floating point."},"Message":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]},"ValidationIssue":{"type":"object","properties":{"path":{"type":"string","description":"Dot-joined path of the offending field (\"\" for the whole body)"},"message":{"type":"string"}},"required":["path","message"]},"Error":{"type":"object","properties":{"code":{"type":"string","description":"Stable machine-readable code; see the error-code reference"},"message":{"type":"string","description":"Human-readable explanation, safe to show to an operator"},"details":{"anyOf":[{"type":"array","items":{"$ref":"#/components/schemas/ValidationIssue"}},{"type":"object","additionalProperties":{}}],"description":"VALIDATION_ERROR: an array of { path, message }. Some codes attach a code-specific object. Usually absent otherwise."}},"required":["code","message"]},"ErrorEnvelope":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"$ref":"#/components/schemas/Error"}},"required":["success","error"]},"AccountProfile":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"contactName":{"type":"string"},"companyName":{"type":"string","nullable":true},"jobTitle":{"type":"string","nullable":true},"phone":{"type":"string","nullable":true},"country":{"type":"string","nullable":true,"description":"ISO-3166-1 alpha-2"},"timezone":{"type":"string"},"companyLogoUrl":{"type":"string","nullable":true},"avatarUrl":{"type":"string","nullable":true},"role":{"type":"string","enum":["user","admin"]},"status":{"type":"string","enum":["active","suspended"]},"accountKind":{"type":"string"},"balance":{"$ref":"#/components/schemas/Money"},"testCredit":{"allOf":[{"$ref":"#/components/schemas/Money"}],"description":"Sandbox credit, spendable only by test API keys"},"emailVerifiedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"pendingEmail":{"type":"string","nullable":true,"description":"An address change waiting for confirmation"},"verificationStatus":{"type":"string","enum":["unverified","verified"]},"kycStatus":{"type":"string","enum":["not_started","pending","verified","rejected"]},"totpEnabled":{"type":"boolean","description":"Two-factor authentication is on"},"taxId":{"type":"string","nullable":true},"taxCountry":{"type":"string","nullable":true},"payoutMethod":{"type":"string","nullable":true},"onboardingGoal":{"type":"string","nullable":true},"onboardingDismissed":{"type":"boolean"},"onboardingSeen":{"type":"boolean"},"emailNotificationsOptOut":{"type":"boolean"},"switchStatus":{"type":"string","enum":["none","active","past_due","canceled","comp"]},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","email","contactName","companyName","jobTitle","phone","country","timezone","companyLogoUrl","avatarUrl","role","status","accountKind","balance","testCredit","emailVerifiedAt","pendingEmail","verificationStatus","kycStatus","totpEnabled","taxId","taxCountry","payoutMethod","onboardingGoal","onboardingDismissed","onboardingSeen","emailNotificationsOptOut","switchStatus","createdAt","updatedAt"],"additionalProperties":true},"AccountBalance":{"type":"object","properties":{"balance":{"$ref":"#/components/schemas/Money"},"testCredit":{"$ref":"#/components/schemas/Money"},"total":{"allOf":[{"$ref":"#/components/schemas/Money"}],"description":"balance + testCredit"}},"required":["balance","testCredit","total"]},"AccountActivityEvent":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"type":{"type":"string","description":"e.g. login, password_change, api_key_created, session_revoked"},"ip":{"type":"string","nullable":true},"userAgent":{"type":"string","nullable":true},"meta":{"type":"object","additionalProperties":{},"nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","type","ip","userAgent","meta","createdAt"]},"AccountSwitchEntitlement":{"type":"object","properties":{"active":{"type":"boolean","description":"May this account use the Switch right now"},"status":{"type":"string","enum":["none","active","past_due","canceled","comp"]},"accessUntil":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"comp":{"type":"boolean"},"nodeNft":{"type":"boolean","description":"Access comes from a held Switch Node NFT"},"priceUsd":{"type":"number","description":"Monthly plan price in USD (a number, not a ledger amount)"},"plan":{"type":"string"},"purchasablePlans":{"type":"array","items":{"type":"string","enum":["starter","essentials","standard","growth","carrier"]}},"onTrial":{"type":"boolean"},"trialEndsAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"trialEligible":{"type":"boolean"},"trialDays":{"type":"integer"},"trialApplication":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["pending","approved","declined"]},"desiredPlan":{"type":"string"},"submittedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"reviewedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true}},"required":["id","status","desiredPlan","submittedAt","reviewedAt"],"nullable":true},"firstChargeDeferredTo":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"cancelAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"manageable":{"type":"boolean","description":"Has a card subscription that the billing portal can manage"}},"required":["active","status","accessUntil","comp","nodeNft","priceUsd","plan","purchasablePlans","onTrial","trialEndsAt","trialEligible","trialDays","trialApplication","firstChargeDeferredTo","cancelAt","manageable"]},"AccountSpendAlerts":{"type":"object","properties":{"lowBalanceThreshold":{"type":"string","nullable":true,"description":"USD, 2-decimal string; null = no low-balance alert"},"dailySpendCap":{"type":"string","nullable":true,"description":"USD, 2-decimal string; null = no daily cap alert"},"notifyEmail":{"type":"boolean"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true}},"required":["lowBalanceThreshold","dailySpendCap","notifyEmail","updatedAt"]},"AccountDestinationAlert":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"country":{"type":"string","description":"Platform country name, as the marketplace country filter uses it"},"trafficType":{"type":"string","enum":["voice","sms"]},"source":{"type":"string","enum":["purchase","manual","backfill"],"description":"Followed when buying a route, from Settings, or switched on for an existing purchase"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","country","trafficType","source","createdAt"]},"AccountDedicatedIp":{"type":"object","properties":{"assignmentId":{"type":"string","format":"uuid"},"ipId":{"type":"string","format":"uuid"},"address":{"type":"string"},"role":{"type":"string","enum":["ingress","egress"],"description":"ingress = where you send traffic; egress = where your calls leave from"},"boundBox":{"type":"string","nullable":true},"assignedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"hint":{"type":"string","description":"Plain-English instruction for this address"}},"required":["assignmentId","ipId","address","role","boundBox","assignedAt","hint"]},"AccountActivatedIp":{"type":"object","properties":{"assignmentId":{"type":"string","format":"uuid"},"ipId":{"type":"string","format":"uuid"},"address":{"type":"string"},"role":{"type":"string","enum":["ingress","egress"],"description":"ingress = where you send traffic; egress = where your calls leave from"},"boundBox":{"type":"string","nullable":true},"assignedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"hint":{"type":"string","description":"Plain-English instruction for this address"},"created":{"type":"boolean","description":"False when you already held one (idempotent replay)"},"monthlyPriceUsd":{"type":"number","description":"Monthly premium in USD (a number)"},"charged":{"type":"number","description":"USD booked by THIS call; 0 on a replay"}},"required":["assignmentId","ipId","address","role","boundBox","assignedAt","hint","created","monthlyPriceUsd","charged"]},"AccountInterconnect":{"type":"object","properties":{"enabled":{"type":"boolean"},"myIngressIp":{"type":"string","nullable":true},"myEgressIp":{"type":"string","nullable":true},"egressPendingNetwork":{"type":"boolean"},"edgeIp":{"type":"string","description":"The shared address to send SIP to when you hold no dedicated one"},"egressIps":{"type":"array","items":{"type":"string"},"description":"Addresses our calls leave from; whitelist these with your carriers"},"rtpPortRange":{"type":"string"},"sipPort":{"type":"integer"},"onPlatform":{"type":"boolean"},"onPlatformSignals":{"type":"object","properties":{"switchOperator":{"type":"boolean"},"marketplaceBuyer":{"type":"boolean"},"dialerUser":{"type":"boolean"}},"required":["switchOperator","marketplaceBuyer","dialerUser"]},"autoAuthorized":{"type":"boolean"},"manualWhitelistNeeded":{"type":"boolean"},"authorizedIps":{"type":"array","items":{"type":"string"}},"poolAvailable":{"type":"integer"},"egressPoolAvailable":{"type":"integer"},"egressAvailable":{"type":"boolean"},"sipUsername":{"type":"string","nullable":true},"hasSipPassword":{"type":"boolean"}},"required":["myIngressIp","myEgressIp","edgeIp","egressIps","rtpPortRange","sipPort","onPlatform","onPlatformSignals","autoAuthorized","manualWhitelistNeeded","authorizedIps","poolAvailable","egressPoolAvailable","egressAvailable","sipUsername","hasSipPassword"],"additionalProperties":true},"AccountConnectivityBrief":{"type":"object","properties":{"dedicatedIpsEnabled":{"type":"boolean"},"myAddress":{"type":"string","nullable":true},"myAddressSummary":{"type":"string"},"sendTo":{"type":"string","description":"Where to send your SIP traffic"},"sendToPort":{"type":"integer"},"sendToSummary":{"type":"string"},"egressMode":{"type":"string","enum":["dedicated","shared"]},"egressAddresses":{"type":"array","items":{"type":"string"}},"egressSummary":{"type":"string"},"authMethods":{"type":"array","items":{"type":"string","enum":["ip","digest"]}},"authSummary":{"type":"string"},"authorizedSourceIps":{"type":"array","items":{"type":"string"}},"purchasedRoutes":{"type":"array","items":{"type":"object","properties":{"purchaseId":{"type":"string","format":"uuid"},"routeId":{"type":"string","format":"uuid"},"routeName":{"type":"string","nullable":true},"destination":{"type":"string","nullable":true},"type":{"type":"string"},"status":{"type":"string"},"sendTo":{"type":"string"},"sendToPort":{"type":"integer"},"sipUsername":{"type":"string","nullable":true}},"required":["purchaseId","routeId","routeName","destination","type","status","sendTo","sendToPort","sipUsername"],"additionalProperties":true}},"rtpPortRange":{"type":"string"},"codecs":{"type":"array","items":{"type":"string"}},"autoAuthorized":{"type":"boolean"},"manualWhitelistNeeded":{"type":"boolean"}},"required":["dedicatedIpsEnabled","myAddress","myAddressSummary","sendTo","sendToPort","sendToSummary","egressMode","egressAddresses","egressSummary","authMethods","authSummary","authorizedSourceIps","purchasedRoutes","rtpPortRange","codecs","autoAuthorized","manualWhitelistNeeded"]},"ApiKey":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"keyPrefix":{"type":"string","description":"The first characters of the key, for recognising it. The full key is never shown again."},"label":{"type":"string"},"scopes":{"type":"array","items":{"type":"string","enum":["voice:send","sms:send","dialer:write","routes:read","account:read","purchases:write","offers:write","billing:write","numbers:read","numbers:write","account:write","routes:write","cdr:numbers","application:write","switch:manage","verify:write","webhooks:write","greetings:read","greetings:write","revshare:read","revshare:write"]},"nullable":true,"description":"null = full access; otherwise the only scopes this key may use"},"environment":{"type":"string","enum":["live","test"]},"lastUsedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"expiresAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true}},"required":["id","keyPrefix","label","scopes","environment","lastUsedAt","createdAt","expiresAt"]},"CreatedApiKey":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"key":{"type":"string","description":"The full secret key. Returned ONCE, here; store it now."},"keyPrefix":{"type":"string","description":"Same value as `prefix`; the name the list and update responses use."},"prefix":{"type":"string","description":"Deprecated alias of `keyPrefix`, kept for existing clients."},"label":{"type":"string"},"scopes":{"type":"array","items":{"type":"string","enum":["voice:send","sms:send","dialer:write","routes:read","account:read","purchases:write","offers:write","billing:write","numbers:read","numbers:write","account:write","routes:write","cdr:numbers","application:write","switch:manage","verify:write","webhooks:write","greetings:read","greetings:write","revshare:read","revshare:write"]},"nullable":true},"environment":{"type":"string","enum":["live","test"]},"expiresAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true}},"required":["id","key","keyPrefix","prefix","label","scopes","environment","expiresAt"]},"Webhook":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"url":{"type":"string","format":"uri"},"secretLast4":{"type":"string","description":"Last 4 characters of the signing secret, to tell secrets apart"},"events":{"type":"array","items":{"type":"string","enum":["call.completed","call.ringing","call.answered","call.gathered","sms.sent","sms.dlr","sms.delivered","sms.failed","campaign.started","campaign.completed","topup.confirmed","balance.low","offer.received","route.purchased","sub_account.balance_low","sub_account.suspended","sub_account.resumed","sub_account.topup_requested","number.call.received","number.sms.received","number.voicemail.received","verification.approved","verification.expired","invoice.created","invoice.issued","invoice.sent","invoice.voided","invoice.reissued","invoice.payment","credit_note.issued","payable.created","netting.run","sell_rate.changed","cost_rate.scheduled","cost_rate.activated","cost_rate.rolled_back","sub_account.margin_below_floor","revshare.call.received","revshare.number.taken","revshare.number.released","ping"]}},"isActive":{"type":"boolean","description":"False when you disabled it, or after sustained delivery failures"},"failureCount":{"type":"integer","description":"Consecutive failed deliveries; resets on success"},"lastDeliveryAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","url","secretLast4","events","isActive","failureCount","lastDeliveryAt","createdAt","updatedAt"]},"WebhookWithSecret":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"url":{"type":"string","format":"uri"},"secretLast4":{"type":"string","description":"Last 4 characters of the signing secret, to tell secrets apart"},"events":{"type":"array","items":{"type":"string","enum":["call.completed","call.ringing","call.answered","call.gathered","sms.sent","sms.dlr","sms.delivered","sms.failed","campaign.started","campaign.completed","topup.confirmed","balance.low","offer.received","route.purchased","sub_account.balance_low","sub_account.suspended","sub_account.resumed","sub_account.topup_requested","number.call.received","number.sms.received","number.voicemail.received","verification.approved","verification.expired","invoice.created","invoice.issued","invoice.sent","invoice.voided","invoice.reissued","invoice.payment","credit_note.issued","payable.created","netting.run","sell_rate.changed","cost_rate.scheduled","cost_rate.activated","cost_rate.rolled_back","sub_account.margin_below_floor","revshare.call.received","revshare.number.taken","revshare.number.released","ping"]}},"isActive":{"type":"boolean","description":"False when you disabled it, or after sustained delivery failures"},"failureCount":{"type":"integer","description":"Consecutive failed deliveries; resets on success"},"lastDeliveryAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"secret":{"type":"string","description":"The signing secret. Returned ONCE; store it now."}},"required":["id","url","secretLast4","events","isActive","failureCount","lastDeliveryAt","createdAt","updatedAt","secret"]},"WebhookDelivery":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Also sent as the X-Webhook-Id header. Automatic retries reuse it (de-duplicate on it); a manual resend is a new delivery with a new id."},"webhookId":{"type":"string","format":"uuid","description":"Present on the account-wide list"},"url":{"type":"string","description":"The endpoint URL, on the account-wide list"},"event":{"type":"string"},"status":{"type":"string","enum":["pending","sending","delivered","failed"]},"httpStatus":{"type":"integer","nullable":true,"description":"Response code your server returned on the last attempt"},"attempts":{"type":"integer","description":"Attempts so far (max 5, with attempts^2-minute backoff)"},"lastError":{"type":"string","nullable":true},"nextRetryAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"deliveredAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true}},"required":["id","event","status","httpStatus","attempts","lastError","nextRetryAt","createdAt","deliveredAt"]},"ApiUsage":{"type":"object","properties":{"totalRequests":{"type":"integer"},"errorRate":{"type":"number","description":"Fraction of requests answered 4xx/5xx, 0 to 1"},"p95LatencyMs":{"type":"integer"},"byDay":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string","description":"YYYY-MM-DD (UTC)"},"count":{"type":"integer"},"errors":{"type":"integer"}},"required":["date","count","errors"]}},"topEndpoints":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string","description":"Route pattern, e.g. /api/v1/routes/:id"},"count":{"type":"integer"}},"required":["path","count"]}},"keyId":{"type":"string","format":"uuid","nullable":true,"description":"The key the figures are filtered to, or null for all traffic"}},"required":["totalRequests","errorRate","p95LatencyMs","byDay","topEndpoints","keyId"]},"MeasuredRouteQuality":{"type":"object","properties":{"window":{"type":"string","enum":["7d","30d","last"],"description":"Evidence window: the last 7 days if enough, else the last 30, else `last` = the most recent 30-day stretch that had enough"},"from":{"type":"string","description":"First UTC day of the evidence, YYYY-MM-DD"},"to":{"type":"string","description":"Last UTC day of the evidence, YYYY-MM-DD"},"sessions":{"type":"integer","description":"Call attempts on this listing the figures are built from (at least 50). For anonymous callers, floored to a band (50, 100, 250, 500, 1000, 5000, ...) with `sessionsBanded: true`"},"sessionsBanded":{"type":"boolean","description":"True when `sessions` is a band floor (anonymous callers)"},"buyers":{"type":"integer","nullable":true,"description":"Distinct buying accounts behind the figures (at least 2). Null for anonymous callers"},"asr":{"type":"number","nullable":true,"description":"Answer-seizure ratio %: answered attempts / attempts"},"acd":{"type":"number","nullable":true,"description":"Average call duration of answered attempts, seconds of talk time"},"ner":{"type":"number","nullable":true,"description":"Network effectiveness ratio %: attempts the network delivered to the handset (answered, user busy, no answer, callee rejected) / attempts"},"pddMs":{"type":"integer","nullable":true,"description":"Median post-dial delay in milliseconds (to the nearest 100 ms); null when not captured"}},"required":["window","from","to","sessions","buyers","asr","acd","ner","pddMs"],"description":"Measured from real buyer calls on this listing. Excludes platform probes and route checks, test calls, the seller's own traffic, calls our platform refused before dialling and billing-excluded calls. A call that failed over counts once on each route it tried. Null unless the window holds at least 50 attempts from at least 2 buyers."},"RouteCheckRecord":{"type":"object","properties":{"total":{"type":"integer","description":"Route checks in the last 7 days that count towards the listing's health (calls to registered test lines)"},"answered":{"type":"integer","description":"Of those, how many the test line answered through this route"},"lastAt":{"type":"string","format":"date-time","description":"When the last check completed","nullable":true},"lastResult":{"type":"string","nullable":true,"description":"The last check's verdict: working, no_capacity or not_delivered"}},"required":["total","answered","lastAt","lastResult"],"description":"Route checks on this listing in the last 7 days. Null when there were none."},"MarketplaceSellerProfile":{"type":"object","properties":{"verified":{"type":"boolean","description":"Seller identity verified"},"sellerScore":{"type":"integer","nullable":true,"description":"Average Exchange Score across the seller's trafficked routes"}},"required":["verified","sellerScore"],"description":"Trust signals only. The marketplace never names the seller behind a listing."},"MarketplaceRoute":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"kind":{"type":"string","enum":["single","blend"]},"type":{"type":"string","enum":["voice","sms"]},"country":{"type":"string"},"countryCode":{"type":"string","description":"E.164 country calling code, digits only"},"prefix":{"type":"array","items":{"type":"string"},"description":"Dial prefixes the route covers"},"destinationName":{"type":"string","description":"The listing name. For anyone but the seller it is GENERATED by the platform from its own data, never the seller's text: \"<Country> <Operator?> <Mobile|Fixed|All Networks>\" for one destination (e.g. \"Niger Mobile\", \"Kenya Safaricom Mobile\"), \"A-Z Voice · <tier> · <CLI> · Ref XXXX\" or \"A-Z SMS · <quality> · Ref XXXX\" for an A-Z bundle. The seller sees the name they gave it."},"cliType":{"type":"string","enum":["full_cli","ncli","partial_cli","local_cli","mixed_cli"]},"routeType":{"type":"string","enum":["direct","premium","standard","ncli"],"description":"Quality tier"},"pricePerUnit":{"allOf":[{"$ref":"#/components/schemas/Money"}],"description":"USD per minute (voice) or per message segment (SMS). On an A-Z deck (rateCount > 0) the per-destination rates apply instead."},"billingIncrement":{"type":"string","nullable":true,"description":"First/subsequent increment in seconds, e.g. \"60/60\""},"capacity":{"type":"integer","description":"Channels (voice) or messages per second (SMS)"},"expectedAsr":{"type":"string","nullable":true,"description":"Seller-stated ASR %. The measured figure is in `measured.asr`"},"expectedAcd":{"type":"string","nullable":true,"description":"Seller-stated ACD in seconds"},"expectedPdd":{"type":"string","nullable":true,"description":"Seller-stated PDD in seconds"},"minAcd":{"type":"integer","nullable":true},"minAsr":{"type":"string","nullable":true,"description":"Decimal as a string, e.g. \"92.50\""},"visibility":{"type":"string","enum":["public","private"]},"status":{"type":"string","enum":["active","paused","suspended","pending_review"]},"wholesaleCompatible":{"type":"boolean"},"callcenterCompatible":{"type":"boolean"},"dialerCompatible":{"type":"boolean"},"retailCompatible":{"type":"boolean"},"otpCompatible":{"type":"boolean"},"notes":{"type":"string","nullable":true},"smsType":{"type":"string","enum":["a2p","p2p","both"],"nullable":true},"exchangeScore":{"type":"integer","nullable":true,"description":"Exchange Score 1-100, null until the route has carried real traffic. Uses the measured ASR, NER, ACD and PDD in place of the stated ones when the listing has recent measured figures"},"lastQcAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"measured":{"allOf":[{"$ref":"#/components/schemas/MeasuredRouteQuality"}],"nullable":true,"description":"Measured quality from real calls; null until the listing has enough traffic from enough buyers"},"routeChecks":{"allOf":[{"$ref":"#/components/schemas/RouteCheckRecord"}],"nullable":true,"description":"Route checks on this listing in the last 7 days. Null when there were none."},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"isOwn":{"type":"boolean","description":"True only on your own listings"},"listingRef":{"type":"string","description":"Anonymous short reference of the listing (4 characters, e.g. \"7K2Q\"): stable for the life of the listing, unique enough to tell two same-named listings apart, and derived from the listing alone (it says nothing about the seller). Absent on your own listings."},"sellerProfile":{"allOf":[{"$ref":"#/components/schemas/MarketplaceSellerProfile"}],"nullable":true,"description":"Trust signals only. The marketplace never names the seller behind a listing."},"rateCount":{"type":"integer","description":"Active per-destination deck rows; > 0 means an A-Z deck"},"priceTrend":{"type":"object","properties":{"changePct":{"type":"number"},"points":{"type":"array","items":{"type":"number"}}},"required":["changePct","points"],"nullable":true,"description":"Real 24h price movement from the price history; null when the route has not repriced"},"verification":{"type":"string","enum":["cli","ncli","connected","not_verified"],"nullable":true,"description":"Verification tier, measured by the platform on any network of the route: `cli` = International CLI (our international caller-ID test showed the exact number we sent, in full), `ncli` = NCLI (the test reached the phone with a different number or none), `connected` = Qualified (a real answered call or a passed test, no caller-ID result), `not_verified` = Untested (not tested by us yet, or the latest test failed; new listings start here). A route keeps its tier until newer evidence fails it. The values are stable keys; the names in brackets are what the marketplace shows. Every tier is listed and buyable. null on SMS routes."},"originPolicy":{"type":"string","enum":["any","dual","origin_only"],"description":"Caller ID origin, declared by the seller (separate from the verification tier). `any` = one price for every call. `dual` = two prices: the origin-group price for a call presenting a VALID caller ID from `originGroup` (judged on the caller ID the seller receives, in From and P-Asserted-Identity), and `pricePerUnit` / the deck rate for every other call (another country, no caller ID, or an invalid one). `origin_only` = carried only for caller IDs from `originGroup`; other calls go to the buyer's next route."},"originGroup":{"type":"string","nullable":true,"description":"Origin group key, e.g. `EEA` (the 27 EU countries, Iceland, Liechtenstein, Norway); null when `originPolicy` is `any`"},"originPricing":{"type":"object","properties":{"policy":{"type":"string","enum":["dual","origin_only"]},"group":{"type":"string"},"originFrom":{"type":"number","nullable":true,"description":"Lowest price for a call with a valid caller ID from the group"},"internationalFrom":{"type":"number","nullable":true,"description":"Lowest price for every other call"},"basis":{"type":"string","description":"The rule in one plain sentence"}},"required":["policy","group","originFrom","internationalFrom","basis"],"nullable":true,"description":"Caller ID origin prices; null on a one-price route"}},"required":["id","kind","type","country","countryCode","prefix","destinationName","cliType","routeType","pricePerUnit","billingIncrement","capacity","expectedAsr","expectedAcd","expectedPdd","minAcd","minAsr","visibility","status","wholesaleCompatible","callcenterCompatible","dialerCompatible","retailCompatible","otpCompatible","notes","exchangeScore","lastQcAt","createdAt","updatedAt","isOwn","sellerProfile","rateCount","verification"],"description":"A route as a buyer sees it: no seller identity, endpoints or credentials."},"OwnRoute":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"kind":{"type":"string","enum":["single","blend"]},"type":{"type":"string","enum":["voice","sms"]},"country":{"type":"string"},"countryCode":{"type":"string","description":"E.164 country calling code, digits only"},"prefix":{"type":"array","items":{"type":"string"},"description":"Dial prefixes the route covers"},"destinationName":{"type":"string","description":"The listing name. For anyone but the seller it is GENERATED by the platform from its own data, never the seller's text: \"<Country> <Operator?> <Mobile|Fixed|All Networks>\" for one destination (e.g. \"Niger Mobile\", \"Kenya Safaricom Mobile\"), \"A-Z Voice · <tier> · <CLI> · Ref XXXX\" or \"A-Z SMS · <quality> · Ref XXXX\" for an A-Z bundle. The seller sees the name they gave it."},"cliType":{"type":"string","enum":["full_cli","ncli","partial_cli","local_cli","mixed_cli"]},"routeType":{"type":"string","enum":["direct","premium","standard","ncli"],"description":"Quality tier"},"pricePerUnit":{"allOf":[{"$ref":"#/components/schemas/Money"}],"description":"USD per minute (voice) or per message segment (SMS). On an A-Z deck (rateCount > 0) the per-destination rates apply instead."},"billingIncrement":{"type":"string","nullable":true,"description":"First/subsequent increment in seconds, e.g. \"60/60\""},"capacity":{"type":"integer","description":"Channels (voice) or messages per second (SMS)"},"expectedAsr":{"type":"string","nullable":true,"description":"Seller-stated ASR %. The measured figure is in `measured.asr`"},"expectedAcd":{"type":"string","nullable":true,"description":"Seller-stated ACD in seconds"},"expectedPdd":{"type":"string","nullable":true,"description":"Seller-stated PDD in seconds"},"minAcd":{"type":"integer","nullable":true},"minAsr":{"type":"string","nullable":true,"description":"Decimal as a string, e.g. \"92.50\""},"visibility":{"type":"string","enum":["public","private"]},"status":{"type":"string","enum":["active","paused","suspended","pending_review"]},"wholesaleCompatible":{"type":"boolean"},"callcenterCompatible":{"type":"boolean"},"dialerCompatible":{"type":"boolean"},"retailCompatible":{"type":"boolean"},"otpCompatible":{"type":"boolean"},"notes":{"type":"string","nullable":true},"smsType":{"type":"string","enum":["a2p","p2p","both"],"nullable":true},"exchangeScore":{"type":"integer","nullable":true,"description":"Exchange Score 1-100, null until the route has carried real traffic. Uses the measured ASR, NER, ACD and PDD in place of the stated ones when the listing has recent measured figures"},"lastQcAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"measured":{"allOf":[{"$ref":"#/components/schemas/MeasuredRouteQuality"}],"nullable":true,"description":"Measured quality from real calls; null until the listing has enough traffic from enough buyers"},"routeChecks":{"allOf":[{"$ref":"#/components/schemas/RouteCheckRecord"}],"nullable":true,"description":"Route checks on this listing in the last 7 days. Null when there were none."},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"sellerId":{"type":"string","format":"uuid","description":"Your own account id"},"isOwner":{"type":"boolean","enum":[true]},"parentRouteId":{"type":"string","format":"uuid","nullable":true},"isBundle":{"type":"boolean"},"jingleSipIp":{"type":"string","nullable":true,"description":"Your SIP endpoint"},"sipPort":{"type":"integer","nullable":true},"techPrefix":{"type":"string","nullable":true},"sipAuthUsername":{"type":"string","nullable":true},"sipAuthPasswordSet":{"type":"boolean","description":"A SIP digest password is stored (never returned)"},"smsDeliveryMethod":{"type":"string","enum":["http","smpp","http_form"],"nullable":true},"smsDeliveryUrl":{"type":"string","nullable":true},"smppHost":{"type":"string","nullable":true},"smppPort":{"type":"integer","nullable":true},"smppSystemId":{"type":"string","nullable":true},"smppPasswordSet":{"type":"boolean","description":"An SMPP password, or on an http_form route the API key, is stored (never returned)"},"endpointReachable":{"type":"boolean","nullable":true},"endpointCheckedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"sellerProfile":{"allOf":[{"$ref":"#/components/schemas/MarketplaceSellerProfile"}],"nullable":true,"description":"Trust signals only. The marketplace never names the seller behind a listing."},"rateCount":{"type":"integer"}},"required":["id","kind","type","country","countryCode","prefix","destinationName","cliType","routeType","pricePerUnit","billingIncrement","capacity","expectedAsr","expectedAcd","expectedPdd","minAcd","minAsr","visibility","status","wholesaleCompatible","callcenterCompatible","dialerCompatible","retailCompatible","otpCompatible","notes","exchangeScore","lastQcAt","createdAt","updatedAt","sellerId","parentRouteId","isBundle","jingleSipIp","sipPort","techPrefix","sipAuthUsername","sipAuthPasswordSet","smsDeliveryUrl","smppHost","smppPort","smppSystemId","smppPasswordSet","endpointReachable","endpointCheckedAt"],"description":"A route you listed, as only you (the seller) see it. Passwords are never returned."},"MyRouteOrigin":{"type":"object","properties":{"endpointKey":{"type":"string","description":"The endpoint group key: the host, \"~none\" (no endpoint) or \"~blend\". Pass it as ?endpoint= to list every route on it"},"kind":{"type":"string","enum":["sip","smpp","http","blend","none"],"description":"sip = voice SIP endpoint, smpp = SMSC bind, http = delivery URL, blend = terminates via its members, none = no endpoint yet"},"host":{"type":"string","nullable":true,"description":"The SIP IP, the SMSC host, or the delivery URL's host"},"port":{"type":"integer","nullable":true,"description":"SIP port (default 5060) or SMPP port (default 2775)"},"systemId":{"type":"string","nullable":true,"description":"SMPP only: the System ID bound with"},"label":{"type":"string","nullable":true,"description":"Your own label for this IP (see GET /routes/my-endpoints), voice only"},"deckId":{"type":"string","format":"uuid","nullable":true,"description":"The A-Z deck this route was split out of, when it was"},"deckName":{"type":"string","nullable":true},"sheetName":{"type":"string","nullable":true,"description":"File name of the latest applied rate sheet behind the deck (or behind the route itself)"}},"required":["endpointKey","kind","host","port","systemId","label","deckId","deckName","sheetName"],"description":"Seller-only: your own endpoint details, never shown to buyers"},"MyRoutesGroups":{"type":"object","properties":{"by":{"type":"string","enum":["endpoint","deck"]},"groups":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"Pass back as ?endpoint= (by=endpoint) or ?deck= (by=deck) on GET /routes/my/list to page this group's routes. Sentinels: \"~none\", \"~blend\", \"~single\""},"kind":{"type":"string","enum":["sip","smpp","http","mixed","blend","none","deck","single"],"description":"by=endpoint: how routes on this host are handed over (mixed when a host serves more than one kind). by=deck: deck, or single for routes listed on their own"},"host":{"type":"string","nullable":true},"label":{"type":"string","nullable":true,"description":"Your label for this IP"},"port":{"type":"integer","nullable":true,"description":"The port when every route in the group uses the same one"},"systemId":{"type":"string","nullable":true,"description":"SMPP: the System ID when every route in the group uses the same one"},"deckId":{"type":"string","format":"uuid","nullable":true},"deckName":{"type":"string","nullable":true},"sheetName":{"type":"string","nullable":true,"description":"File name of the deck's latest applied rate sheet"},"total":{"type":"integer"},"live":{"type":"integer","description":"Visible to buyers, by the marketplace's own filters"},"hidden":{"type":"integer","description":"total - live"}},"required":["key","kind","host","label","port","systemId","deckId","deckName","sheetName","total","live","hidden"]},"description":"Largest group first, at most 500"},"total":{"type":"integer","description":"Routes across the returned groups"},"truncated":{"type":"boolean","description":"More than 500 groups matched; narrow the filter"}},"required":["by","groups","total","truncated"]},"MarketplaceStats":{"type":"object","properties":{"total":{"type":"integer"},"voiceCount":{"type":"integer"},"smsCount":{"type":"integer"},"destinations":{"type":"integer"},"avgPrice":{"type":"number","nullable":true,"description":"Signed-in callers only. Average list price (display figure)"},"avgAsr":{"type":"number","nullable":true,"description":"Signed-in only. Average seller-stated ASR %"},"measuredAsr":{"type":"number","nullable":true,"description":"Signed-in only. Measured ASR % over 30 days of real calls"},"avgScore":{"type":"integer","nullable":true,"description":"Signed-in only"},"totalCapacity":{"type":"integer","description":"Signed-in only"},"priceHistogram":{"type":"object","properties":{"min":{"$ref":"#/components/schemas/Money"},"max":{"allOf":[{"$ref":"#/components/schemas/Money"}],"description":"Top edge: the 98th percentile price in view"},"buckets":{"type":"array","items":{"type":"object","properties":{"from":{"$ref":"#/components/schemas/Money"},"to":{"$ref":"#/components/schemas/Money"},"count":{"type":"integer"}},"required":["from","to","count"]},"description":"About 20 equal-width bands, cheapest first"},"above":{"type":"integer","nullable":true,"description":"Rows priced above `max`"},"total":{"type":"integer"}},"required":["min","max","buckets","above","total"],"nullable":true,"description":"Price spread of the view, ignoring minPrice/maxPrice so a range slider can show where it sits. Per-network rows when rows=network"},"verifiedShareByCountry":{"type":"array","items":{"type":"object","properties":{"country":{"type":"string"},"countryCode":{"type":"string","nullable":true},"voice":{"type":"integer"},"verified":{"type":"integer","description":"Voice rows at Qualified or better (International CLI, NCLI or Qualified)"},"share":{"type":"number","description":"verified / voice, 0..1"}},"required":["country","countryCode","voice","verified","share"]},"nullable":true,"description":"Per country, how much of the voice market in view is proven; largest first"}},"required":["total","voiceCount","smsCount","destinations"]},"ConnectivityTestResult":{"type":"object","properties":{"pass":{"type":"boolean","description":"True when the endpoint answered from every one of our media addresses"},"barred":{"type":"boolean","description":"Reachable but refusing our calls"},"degraded":{"type":"boolean","description":"Refusing some of our source addresses"},"checks":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string"},"value":{"type":"string"},"ok":{"type":"boolean"}},"required":["label","value","ok"]}},"egressAddresses":{"type":"string","description":"The addresses our traffic comes from; whitelist these"},"gatewayIp":{"type":"string","description":"Deprecated alias of egressAddresses"},"diagnostics":{"type":"object","properties":{},"additionalProperties":true},"message":{"type":"string"}},"required":["pass","checks","egressAddresses","gatewayIp","message"]},"ResolvedRoute":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"destinationName":{"type":"string","description":"The listing name as a buyer reads it: generated by the platform, never the seller's text, and ending in the listing reference (e.g. \"Niger Mobile · Ref 7K2Q\", \"A-Z Voice · Premium · Full CLI · Ref 3MX9\"). Your own listings keep the name you gave them."},"country":{"type":"string"},"countryCode":{"type":"string"},"type":{"type":"string","enum":["voice","sms"]},"cliType":{"type":"string","nullable":true},"price":{"allOf":[{"$ref":"#/components/schemas/Money"}],"description":"Rate for this destination: USD per minute or message, 6-decimal string"},"asr":{"type":"number","nullable":true},"acd":{"type":"number","nullable":true},"matchedPrefix":{"type":"string","nullable":true}},"required":["id","destinationName","country","countryCode","type","cliType","price","asr","acd","matchedPrefix"]},"PricedRoute":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"type":{"type":"string","enum":["voice","sms"]},"name":{"type":"string","description":"The listing name as a buyer reads it: generated by the platform, never the seller's text, and ending in the listing reference (e.g. \"Niger Mobile · Ref 7K2Q\", \"A-Z Voice · Premium · Full CLI · Ref 3MX9\"). Your own listings keep the name you gave them."},"listingRef":{"type":"string","description":"Anonymous short reference of the listing (4 characters, e.g. \"7K2Q\"): stable for the life of the listing, unique enough to tell two same-named listings apart, and derived from the listing alone (it says nothing about the seller). Absent on your own listings."},"country":{"type":"string"},"countryCode":{"type":"string","description":"E.164 country calling code, digits only"},"matchedPrefix":{"type":"string","description":"The dial prefix the number matched on this route (the longest one, on a deck)"},"destination":{"type":"string","description":"The destination that prefix belongs to, e.g. \"United Kingdom-Mobile\"; the country for a flat-priced listing"},"rate":{"allOf":[{"$ref":"#/components/schemas/Money"}],"description":"What this route charges for THIS number: USD per minute (voice) or per message (SMS)"},"billingIncrement":{"type":"string","nullable":true,"description":"e.g. \"60/60\" or \"1/1\"; null when the listing does not state one"},"pricedBy":{"type":"string","enum":["deck","flat"],"description":"deck = priced by the matching rate-sheet row; flat = the listing's single price"},"expectedAsr":{"type":"string","nullable":true,"description":"Seller-stated ASR %. The measured figure is in `measured.asr`"},"expectedAcd":{"type":"string","nullable":true,"description":"Seller-stated ACD in seconds"},"cliType":{"type":"string"},"routeType":{"type":"string","description":"Quality tier"},"capacity":{"type":"integer","description":"Channels (voice) or messages per second (SMS)"},"exchangeScore":{"type":"integer","nullable":true,"description":"Exchange Score 1-100; null (\"New\") until the route has carried traffic"},"measured":{"allOf":[{"$ref":"#/components/schemas/MeasuredRouteQuality"}],"nullable":true,"description":"Measured quality of the listing from real calls; null until it has enough traffic from enough buyers"},"routeChecks":{"allOf":[{"$ref":"#/components/schemas/RouteCheckRecord"}],"nullable":true,"description":"Route checks on this listing in the last 7 days. Null when there were none."},"isOwn":{"type":"boolean","description":"True only on your own listing (signed-in callers), so you are not offered your own route"},"network":{"type":"object","properties":{"mccMnc":{"type":"string","nullable":true,"description":"Mobile network code (MCC-MNC) `rate` is for, e.g. \"234-10\"; null when unknown"},"operator":{"type":"string","nullable":true,"description":"Network name from public number-range data, e.g. \"O2\""},"source":{"type":"string","enum":["range","hlr","none"],"description":"range = number-range data; none = not determined"},"rateBasis":{"type":"string","enum":["network","all_operators","country"],"description":"network = that network's own rate; all_operators = the route's rate for networks it does not list separately; country = the price for other or unknown networks"}},"required":["mccMnc","operator","source","rateBasis"],"nullable":true,"description":"SMS routes that price the country per mobile network: which network `rate` is for. Absent otherwise"},"countryRate":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"SMS routes that price per network: the price for other or unknown networks"},"verification":{"type":"string","enum":["cli","ncli","connected","not_verified"],"nullable":true,"description":"Tier of the network row the number falls on (as the per-network board labels it), else the listing tier; null for SMS"},"networkName":{"type":"string","nullable":true,"description":"Destination network the number falls on, as plain text (SMS: the operator). On voice rows `network` carries the same string"}},"required":["id","type","name","country","countryCode","matchedPrefix","destination","rate","billingIncrement","pricedBy","expectedAsr","expectedAcd","cliType","routeType","capacity","exchangeScore","measured","routeChecks","isOwn"],"description":"One route that serves the number, at the rate it would charge for it. Never names the seller."},"RouteRate":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"routeId":{"type":"string","format":"uuid"},"destinationName":{"type":"string"},"operator":{"type":"string","nullable":true},"prefix":{"type":"string"},"ratePerUnit":{"$ref":"#/components/schemas/Money"},"billingIncrement":{"type":"string","nullable":true},"minDuration":{"type":"integer","nullable":true},"effectiveDate":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"status":{"type":"string"},"mccMnc":{"type":"string","nullable":true,"description":"SMS sheets priced by network code: the network the row price came from (\"214\" = whole country)"},"operatorRates":{"type":"array","items":{"type":"object","properties":{"mccMnc":{"type":"string","description":"\"214-07\" for one network; \"214\" for All Operators"},"operator":{"type":"string","nullable":true},"rate":{"$ref":"#/components/schemas/Money"}},"required":["mccMnc","operator","rate"]},"nullable":true,"description":"SMS sheets priced by network: the price per destination network (charged per network when `networkPriced` is true). A message is charged its network's rate (networks not listed pay the All Operators rate when there is one); `ratePerUnit` is the price for other or unknown networks. The network is determined from the number's range (ported numbers may be priced at the network the range belongs to)"},"networkPriced":{"type":"boolean","description":"True when each SMS on this row is charged its destination network's rate from `operatorRates`; `ratePerUnit` then applies to other or unknown networks"}},"required":["id","routeId","destinationName","operator","prefix","ratePerUnit","billingIncrement","minDuration","effectiveDate","status"],"additionalProperties":true},"RateSheetImport":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"routeId":{"type":"string","format":"uuid"},"filename":{"type":"string"},"fileType":{"type":"string"},"status":{"type":"string"},"rowCount":{"type":"integer","nullable":true},"columnMapping":{},"previewRows":{},"warnings":{},"currency":{"type":"string","nullable":true},"fxRate":{"type":"string","nullable":true},"errorMessage":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"appliedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true}},"required":["id","routeId","filename","fileType","status","rowCount","currency","fxRate","errorMessage","createdAt","appliedAt"],"additionalProperties":true},"ListingHealth":{"type":"object","properties":{"listed":{"type":"integer","description":"Your routes that are active, public and not an A-Z deck parent: what you have put on sale"},"live":{"type":"integer","description":"How many of those buyers can actually see on the marketplace (counted with the marketplace's own filters)"},"hidden":{"type":"integer","description":"listed - live"},"reasons":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","enum":["sms_no_delivery","voice_no_endpoint","restricted"],"description":"sms_no_delivery and voice_no_endpoint can be listed with GET /routes/my/list?hiddenReason=<key> and fixed in bulk; restricted = a destination the exchange does not carry"},"count":{"type":"integer"},"label":{"type":"string","description":"The reason in plain words"},"fix":{"type":"string","description":"What to do about it"}},"required":["key","count","label","fix"]},"description":"Why the hidden routes are hidden, in the order to fix them. Only reasons with a non-zero count are present."}},"required":["listed","live","hidden","reasons"]},"BulkEndpointResult":{"type":"object","properties":{"updated":{"type":"integer","description":"Routes changed. Always 0 on a dry run."},"wouldUpdate":{"type":"integer","description":"Dry run (or nothing eligible): how many routes the call would change"},"skipped":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"reason":{"type":"string","enum":["not_found","not_sms","not_voice","deck_parent","blend","duplicate_listing"],"description":"not_found: not one of your live routes. not_sms / not_voice: wrong route type for this action. deck_parent: set it on the deck's own Edit page. blend: a blend has no endpoint of its own. duplicate_listing (SIP only): another of your routes already lists this country and prefixes on that IP and tech prefix."}},"required":["id","reason"]},"description":"Routes left untouched, each with the reason"},"check":{"type":"object","properties":{"pass":{"type":"boolean"},"message":{"type":"string"}},"required":["pass","message"],"description":"The one endpoint check run for the whole batch (an SMPP bind, a URL check or a SIP probe). pass is false only when confirmUnreachable applied a SIP endpoint anyway."},"dryRun":{"type":"boolean"}},"required":["updated","skipped"]},"PriceNumberResult":{"type":"object","properties":{"number":{"type":"string","description":"The number as priced: digits only"},"type":{"type":"string","enum":["voice","sms"]},"unit":{"type":"string","enum":["min","msg"],"description":"What `rate` is per: a minute (voice) or a message (SMS)"},"total":{"type":"integer","description":"Routes that serve the number, before the 100-row cap"},"routes":{"type":"array","items":{"$ref":"#/components/schemas/PricedRoute"},"description":"Cheapest first"},"notice":{"type":"string","enum":["sanctioned"],"nullable":true,"description":"Why the list is empty when it is empty for a reason other than \"no route covers it\""}},"required":["number","type","unit","total","routes","notice"]},"EndpointStatus":{"type":"object","properties":{"endpoints":{"type":"array","items":{"type":"object","properties":{"endpointKey":{"type":"string"},"host":{"type":"string"},"endpoint":{"type":"string"},"kind":{"type":"string","enum":["voice"]},"routeCount":{"type":"integer"},"routeId":{"type":"string","format":"uuid"},"refusing":{"type":"boolean"},"partial":{"type":"boolean"},"refusedIps":{"type":"array","items":{"type":"string"}},"evidence":{"type":"string","nullable":true},"source":{"type":"string","enum":["traffic","probe"],"nullable":true},"since":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true}},"required":["endpointKey","host","endpoint","kind","routeCount","routeId","refusing","partial","refusedIps","evidence","source","since"]}},"allow":{"type":"object","properties":{"egressIps":{"type":"array","items":{"type":"string"}},"sipPort":{"type":"integer"},"rtpPortRange":{"type":"string"}},"required":["egressIps","sipPort","rtpPortRange"]}},"required":["endpoints","allow"]},"RouteAccessGrant":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"routeId":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid","nullable":true},"customPrice":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"Price this buyer pays instead of the list price"},"inviteCode":{"type":"string","nullable":true},"status":{"anyOf":[{"type":"string","enum":["pending","active","revoked"]},{"type":"string"}]},"message":{"type":"string","nullable":true},"requestedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","routeId","userId","customPrice","inviteCode","status","message","requestedAt","createdAt"],"additionalProperties":true},"RouteReport":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"routeId":{"type":"string","format":"uuid"},"routeName":{"type":"string","nullable":true},"role":{"type":"string","enum":["buyer","seller"]},"buyerId":{"type":"string","format":"uuid","nullable":true,"description":"Null for the seller, who sees only the pseudonym"},"buyerLabel":{"type":"string"},"category":{"type":"string","enum":["call_failure","connectivity","quality","other"]},"subject":{"type":"string","nullable":true},"status":{"type":"string","enum":["open","acknowledged","resolved","confirmed","reopened","escalated","closed"]},"evidence":{"description":"Call evidence; seller addresses are masked for the buyer"},"verifyResult":{},"escalated":{"type":"boolean"},"unread":{"type":"boolean"},"lastActivityAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"resolvedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"closedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true}},"required":["id","routeId","routeName","role","buyerId","buyerLabel","category","subject","status","escalated","unread","lastActivityAt","createdAt","resolvedAt","closedAt"]},"RouteReportThread":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"routeId":{"type":"string","format":"uuid"},"routeName":{"type":"string","nullable":true},"role":{"type":"string","enum":["buyer","seller"]},"buyerId":{"type":"string","format":"uuid","nullable":true,"description":"Null for the seller, who sees only the pseudonym"},"buyerLabel":{"type":"string"},"category":{"type":"string","enum":["call_failure","connectivity","quality","other"]},"subject":{"type":"string","nullable":true},"status":{"type":"string","enum":["open","acknowledged","resolved","confirmed","reopened","escalated","closed"]},"evidence":{"description":"Call evidence; seller addresses are masked for the buyer"},"verifyResult":{},"escalated":{"type":"boolean"},"unread":{"type":"boolean"},"lastActivityAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"resolvedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"closedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"messages":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"role":{"type":"string","enum":["buyer","seller","system","staff"]},"kind":{"type":"string","enum":["message","status_change","verification"]},"authorLabel":{"type":"string"},"mine":{"type":"boolean"},"body":{"type":"string"},"meta":{},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","role","kind","authorLabel","mine","body","createdAt"]}}},"required":["id","routeId","routeName","role","buyerId","buyerLabel","category","subject","status","escalated","unread","lastActivityAt","createdAt","resolvedAt","closedAt","messages"]},"RouteCheckLeg":{"type":"object","properties":{"position":{"type":"integer","description":"0 = your first choice (primary), then backups"},"role":{"type":"string","enum":["primary","backup"]},"routeId":{"type":"string","format":"uuid"},"routeName":{"type":"string","description":"Cleaned of seller names and contact details"},"country":{"type":"string"},"ownRoute":{"type":"boolean","description":"A listing you sell yourself (checked free)"},"result":{"type":"string","enum":["pending","checking","working","no_capacity","not_delivered","false_answer","inconclusive","accepts","accepted","delivered","refused"],"description":"pending/checking = in progress. working = the call was answered: the route delivers. no_capacity = the route refused the call or did not respond. not_delivered = the route signalled ringing but the call never reached the number. false_answer = the route answered faster than a real line can be reached (under 1.5 s from our INVITE, or under 2.5 s with no ringing): it almost certainly answered the call itself. Not working, and not charged. inconclusive = no verdict (our test lines were busy, the number was reported invalid, or the check was interrupted); nothing counted against the route. accepts = the lighter check for a destination without a full check yet: the route accepts calls. Test SMS only: accepted = the route took the message and no carrier receipt has arrived yet (on a route that returns none it stays accepted); delivered = a carrier receipt confirmed delivery to the phone; refused = the route refused the message, or the carrier receipt said it failed (see errorCode). A refused message is not charged."},"message":{"type":"string","description":"The plain-English verdict to show, e.g. \"This route is working for your needs.\""},"checkType":{"type":"string","enum":["full","light","ring_me","sms","simulated"],"nullable":true,"description":"full = a call to one of our test lines; light = acceptance only; ring_me = your own number; sms = a test message to your own mobile; simulated = test key"},"destination":{"type":"string","nullable":true,"description":"The country the check call went to"},"lineType":{"type":"string","enum":["fixed","mobile"],"nullable":true,"description":"Line type of the test line used (full checks)"},"rang":{"type":"boolean","nullable":true},"answered":{"type":"boolean","nullable":true},"pddMs":{"type":"integer","nullable":true,"description":"Post-dial delay: dial to first ring (or answer)"},"sipCode":{"type":"integer","nullable":true,"description":"Final SIP response from the route, when one came back"},"billableSeconds":{"type":"integer"},"cost":{"allOf":[{"$ref":"#/components/schemas/Money"}],"description":"What this leg cost you (route rate for the connected seconds, plus the platform fee)"},"paidFrom":{"type":"string","enum":["test_credit","balance","mixed"],"nullable":true,"description":"Which wallet paid: test credit is used first, then your balance. Null when nothing was charged"},"answerMs":{"type":"integer","nullable":true,"description":"Milliseconds from our INVITE to the answer, when it answered (the false-answer test)"},"completedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"messageRef":{"type":"string","nullable":true,"description":"Test SMS: the 4-character reference printed at the end of the message, so you can find it on your phone"},"sender":{"type":"string","nullable":true,"description":"Test SMS: the sender the platform used (set from the route's sender rules; you cannot choose it)"},"errorCode":{"type":"string","enum":["SELLER_REJECTED","NO_ENDPOINT","UNDELIVERABLE","EXPIRED","REJECTED"],"nullable":true,"description":"Test SMS refused: SELLER_REJECTED = the route refused the message; NO_ENDPOINT = the route has no delivery endpoint; UNDELIVERABLE, EXPIRED, REJECTED = the carrier receipt said it failed. The same codes as GET /comms/sms/{id}"},"carrierStatus":{"type":"string","nullable":true,"description":"Test SMS: the carrier receipt's own stat value (DELIVRD, UNDELIV, ...), when a receipt arrived"},"carrierError":{"type":"string","nullable":true,"description":"Test SMS: the carrier receipt's own err value, when it carried one"},"acceptedAt":{"type":"string","format":"date-time","description":"Test SMS: when the route accepted the message","nullable":true},"receiptAt":{"type":"string","format":"date-time","description":"Test SMS: when the carrier receipt arrived","nullable":true},"routeReturnsReceipts":{"type":"boolean","nullable":true,"description":"Test SMS still accepted: whether this route has returned any carrier receipt in the last 30 days. false = a confirmation may never come; check your phone"}},"required":["position","role","routeId","routeName","country","ownRoute","result","message","checkType","destination","lineType","rang","answered","pddMs","sipCode","billableSeconds","cost","paidFrom","answerMs","completedAt","messageRef","sender","errorCode","carrierStatus","carrierError","acceptedAt","receiptAt","routeReturnsReceipts"]},"RouteCheck":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["running","done"],"description":"Poll GET /routes/check/{id} until done (usually under 40 seconds)"},"mode":{"type":"string","enum":["network","ring_me","sms"],"description":"sms = a test message (POST /routes/check/sms)"},"simulated":{"type":"boolean","description":"True for a test key: no call was placed and nothing was charged"},"number":{"type":"string","nullable":true,"description":"The number or dial code you checked for (+digits)"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"completedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"totalCost":{"$ref":"#/components/schemas/Money"},"routes":{"type":"array","items":{"$ref":"#/components/schemas/RouteCheckLeg"}},"working":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Route ids that passed (working or accepts; delivered for a test SMS), in your order"}},"required":["id","status","mode","simulated","number","createdAt","completedAt","totalCost","routes","working"]},"RouteCheckPurchase":{"type":"object","properties":{"purchases":{"type":"array","items":{"type":"object","properties":{"routeId":{"type":"string","format":"uuid"},"routeName":{"type":"string"},"purchaseId":{"type":"string","format":"uuid","nullable":true},"status":{"type":"string","nullable":true,"description":"The purchase status (active, or pending_review for a route that needs review)"},"alreadyOwned":{"type":"boolean"},"error":{"type":"string","nullable":true}},"required":["routeId","routeName","purchaseId","status","alreadyOwned","error"]}},"routingOrder":{"type":"array","items":{"type":"object","properties":{"position":{"type":"integer","description":"1 = primary"},"role":{"type":"string","enum":["primary","backup"]},"purchaseId":{"type":"string","format":"uuid"},"routeId":{"type":"string","format":"uuid"},"routeName":{"type":"string"}},"required":["position","role","purchaseId","routeId","routeName"]}}},"required":["purchases","routingOrder"]},"RouteCheckHealth":{"type":"object","properties":{"networks":{"type":"array","items":{"type":"object","properties":{"network":{"type":"string"},"kind":{"type":"string","nullable":true},"prefix":{"type":"string","nullable":true},"answered":{"type":"integer"},"checks":{"type":"integer"},"cliMark":{"type":"string","enum":["full","replaced","none","not_verified"]},"state":{"type":"string","enum":["ok","warning","grace","delisted"]},"graceUntil":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"reason":{"type":"string","nullable":true},"lastCheckAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true}},"required":["network","kind","prefix","answered","checks","cliMark","state","graceUntil","reason","lastCheckAt"]},"nullable":true},"window":{"type":"object","properties":{"hours":{"type":"integer"},"working":{"type":"integer"},"failed":{"type":"integer"},"total":{"type":"integer"},"suspendAfter":{"type":"integer","description":"Failures (with none working) that trigger the confirmation check"}},"required":["hours","working","failed","total","suspendAfter"]},"suspension":{"type":"object","properties":{"status":{"type":"string","enum":["suspended","notice"],"description":"notice = an A-Z rate sheet warned for one country; nothing was suspended"},"since":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"reason":{"type":"string"},"destination":{"type":"string","nullable":true},"evidence":{"type":"object","properties":{},"additionalProperties":true,"description":"Counts, SIP codes, causes and times of the failed checks"}},"required":["status","since","reason","destination","evidence"],"nullable":true},"lastReinstatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"recent":{"type":"array","items":{"type":"object","properties":{"at":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"result":{"type":"string","enum":["pending","checking","working","no_capacity","not_delivered","false_answer","inconclusive","accepts","accepted","delivered","refused"],"description":"pending/checking = in progress. working = the call was answered: the route delivers. no_capacity = the route refused the call or did not respond. not_delivered = the route signalled ringing but the call never reached the number. false_answer = the route answered faster than a real line can be reached (under 1.5 s from our INVITE, or under 2.5 s with no ringing): it almost certainly answered the call itself. Not working, and not charged. inconclusive = no verdict (our test lines were busy, the number was reported invalid, or the check was interrupted); nothing counted against the route. accepts = the lighter check for a destination without a full check yet: the route accepts calls. Test SMS only: accepted = the route took the message and no carrier receipt has arrived yet (on a route that returns none it stays accepted); delivered = a carrier receipt confirmed delivery to the phone; refused = the route refused the message, or the carrier receipt said it failed (see errorCode). A refused message is not charged."},"checkType":{"type":"string","enum":["full","light","sms"],"description":"sms = a test message on an SMS listing"},"errorCode":{"type":"string","nullable":true,"description":"A test message's refusal code; null on calls"},"sipCode":{"type":"integer","nullable":true},"cause":{"type":"string","nullable":true},"destination":{"type":"string","nullable":true},"byYou":{"type":"boolean"},"runBy":{"type":"string","enum":["you","buyer","platform"],"description":"Who ran it: you, a buyer (never named), or the platform (confirmation / new test line)"},"answerMs":{"type":"integer","nullable":true,"description":"Milliseconds from our INVITE to the answer"},"rang":{"type":"boolean","nullable":true}},"required":["at","result","checkType","errorCode","sipCode","cause","destination","byYou","runBy","answerMs","rang"]}}},"required":["window","suspension","lastReinstatedAt","recent"]},"Purchase":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"buyerId":{"type":"string","format":"uuid","description":"Your account id"},"routeId":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["active","paused","cancelled","pending_review"]},"sipUsername":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"cancelledAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"agreedPrice":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"Negotiated price (from an accepted offer) that overrides the list price"},"heldOldRate":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"Set while the purchase is paused by a seller rate increase: the rate you were paying"},"heldNewRate":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"The increased rate waiting for your acceptance"},"routingPriority":{"type":"integer","nullable":true,"description":"Your routing position (1 = first); null = unranked"},"sipPassword":{"type":"string","nullable":true,"description":"Your own SIP password, for your connection card"},"heldDeckVersion":{"type":"string","nullable":true,"description":"Deck fingerprint to pass as deckVersion when accepting a deck increase"},"route":{"type":"object","properties":{"type":{"type":"string","enum":["voice","sms"]},"country":{"type":"string"},"prefix":{"type":"array","items":{"type":"string"}},"countryCode":{"type":"string"},"destinationName":{"type":"string","description":"The listing name as a buyer reads it: generated by the platform, never the seller's text, and ending in the listing reference (e.g. \"Niger Mobile · Ref 7K2Q\", \"A-Z Voice · Premium · Full CLI · Ref 3MX9\"). Your own listings keep the name you gave them."},"pricePerUnit":{"$ref":"#/components/schemas/Money"},"billingIncrement":{"type":"string","nullable":true},"jingleSipIp":{"enum":["null"],"nullable":true,"description":"Always null: the seller endpoint is never disclosed"},"capacity":{"type":"integer"},"expectedAsr":{"type":"string","nullable":true},"expectedAcd":{"type":"string","nullable":true},"dialerCompatible":{"type":"boolean"},"rateCount":{"type":"integer"}},"required":["type","country","prefix","countryCode","destinationName","pricePerUnit","billingIncrement","jingleSipIp","capacity","expectedAsr","expectedAcd","dialerCompatible","rateCount"]}},"required":["id","buyerId","routeId","status","sipUsername","createdAt","cancelledAt","agreedPrice","heldOldRate","heldNewRate","routingPriority","sipPassword","heldDeckVersion","route"]},"PurchaseDetail":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"buyerId":{"type":"string","format":"uuid","description":"Your account id"},"routeId":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["active","paused","cancelled","pending_review"]},"sipUsername":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"cancelledAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"agreedPrice":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"Negotiated price (from an accepted offer) that overrides the list price"},"heldOldRate":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"Set while the purchase is paused by a seller rate increase: the rate you were paying"},"heldNewRate":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"The increased rate waiting for your acceptance"},"routingPriority":{"type":"integer","nullable":true,"description":"Your routing position (1 = first); null = unranked"},"requiresUsCompliance":{"type":"boolean","description":"A US voice route that needs STIR/SHAKEN review before traffic flows"},"reviewedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"reviewNote":{"type":"string","nullable":true,"description":"The compliance reviewer's note to you, if any"},"sipPasswordSet":{"type":"boolean","description":"Whether a SIP password exists. The value is not returned here: it is shown once at purchase, on your purchased-routes list and on Interconnections."},"smppSystemId":{"type":"string","nullable":true},"offerId":{"type":"string","format":"uuid","nullable":true,"description":"The accepted offer that set agreedPrice"},"route":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"type":{"type":"string","enum":["voice","sms"]},"country":{"type":"string"},"destinationName":{"type":"string","description":"The listing name as a buyer reads it: generated by the platform, never the seller's text, and ending in the listing reference (e.g. \"Niger Mobile · Ref 7K2Q\", \"A-Z Voice · Premium · Full CLI · Ref 3MX9\"). Your own listings keep the name you gave them."},"listingRef":{"type":"string","description":"Anonymous short reference of the listing (4 characters, e.g. \"7K2Q\"): stable for the life of the listing, unique enough to tell two same-named listings apart, and derived from the listing alone (it says nothing about the seller). Absent on your own listings."},"pricePerUnit":{"$ref":"#/components/schemas/Money"},"billingIncrement":{"type":"string","nullable":true},"jingleSipIp":{"enum":["null"],"nullable":true}},"required":["id","type","country","destinationName","listingRef","pricePerUnit","billingIncrement","jingleSipIp"],"nullable":true},"sipPublicIp":{"type":"string","description":"Where to send your SIP traffic"}},"required":["id","buyerId","routeId","status","sipUsername","createdAt","cancelledAt","agreedPrice","heldOldRate","heldNewRate","routingPriority","requiresUsCompliance","reviewedAt","reviewNote","sipPasswordSet","smppSystemId","offerId","route","sipPublicIp"]},"PurchaseRow":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"buyerId":{"type":"string","format":"uuid","description":"Your account id"},"routeId":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["active","paused","cancelled","pending_review"]},"sipUsername":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"cancelledAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"agreedPrice":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"Negotiated price (from an accepted offer) that overrides the list price"},"heldOldRate":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"Set while the purchase is paused by a seller rate increase: the rate you were paying"},"heldNewRate":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"The increased rate waiting for your acceptance"},"routingPriority":{"type":"integer","nullable":true,"description":"Your routing position (1 = first); null = unranked"},"requiresUsCompliance":{"type":"boolean","description":"A US voice route that needs STIR/SHAKEN review before traffic flows"},"reviewedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"reviewNote":{"type":"string","nullable":true,"description":"The compliance reviewer's note to you, if any"},"sipPasswordSet":{"type":"boolean","description":"Whether a SIP password exists. The value is not returned here: it is shown once at purchase, on your purchased-routes list and on Interconnections."},"smppSystemId":{"type":"string","nullable":true},"offerId":{"type":"string","format":"uuid","nullable":true,"description":"The accepted offer that set agreedPrice"}},"required":["id","buyerId","routeId","status","sipUsername","createdAt","cancelledAt","agreedPrice","heldOldRate","heldNewRate","routingPriority","requiresUsCompliance","reviewedAt","reviewNote","sipPasswordSet","smppSystemId","offerId"]},"RoutingOrderEntry":{"type":"object","properties":{"purchaseId":{"type":"string","format":"uuid"},"routeId":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["active","paused","cancelled","pending_review"]},"routingPriority":{"type":"integer","nullable":true,"description":"Your position (1 = first); null = unranked"},"createdAt":{"type":"string","format":"date-time","description":"When you bought it (the tie-break among unranked routes)"},"destinationName":{"type":"string","description":"The listing name as a buyer reads it: generated by the platform, never the seller's text, and ending in the listing reference (e.g. \"Niger Mobile · Ref 7K2Q\", \"A-Z Voice · Premium · Full CLI · Ref 3MX9\"). Your own listings keep the name you gave them."},"country":{"type":"string"},"countryCode":{"type":"string"},"prefix":{"type":"array","items":{"type":"string"}},"rateSheet":{"type":"boolean","description":"Priced by an A-Z rate sheet, so it can overlap any destination"}},"required":["purchaseId","routeId","status","routingPriority","createdAt","destinationName","country","countryCode","prefix","rateSheet"]},"RouteForCandidate":{"type":"object","properties":{"position":{"type":"integer","description":"1 = the route that would carry the call"},"carries":{"type":"boolean"},"purchaseId":{"type":"string","format":"uuid","nullable":true,"description":"null for one of your own listings"},"routeId":{"type":"string","format":"uuid"},"ownRoute":{"type":"boolean","description":"True when this is a route you sell yourself"},"destinationName":{"type":"string","description":"The listing name as a buyer reads it: generated by the platform, never the seller's text, and ending in the listing reference (e.g. \"Niger Mobile · Ref 7K2Q\", \"A-Z Voice · Premium · Full CLI · Ref 3MX9\"). Your own listings keep the name you gave them."},"country":{"type":"string"},"matchedPrefix":{"type":"string","nullable":true},"matchedDigits":{"type":"integer","description":"Length of the matching prefix"},"routingPriority":{"type":"integer","nullable":true},"rate":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"What you are billed per minute for this number on this route"},"rateSheet":{"type":"boolean","description":"The route is priced by an A-Z rate sheet"},"purchasedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"behindBecause":{"type":"string","enum":["prefix","routing_order","rate","age","route_id"],"description":"For every route after the first: why the route above it wins","nullable":true}},"required":["position","carries","purchaseId","routeId","ownRoute","destinationName","country","matchedPrefix","matchedDigits","routingPriority","rate","rateSheet","purchasedAt","behindBecause"]},"RoutingOrderResult":{"type":"object","properties":{"order":{"type":"array","items":{"type":"object","properties":{"purchaseId":{"type":"string","format":"uuid"},"routingPriority":{"type":"integer"}},"required":["purchaseId","routingPriority"]}}},"required":["order"]},"FailoverOverview":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Whether automatic failover is switched on"},"maxAttempts":{"type":"integer","description":"The most routes tried for one call, the first included"},"destinations":{"type":"array","items":{"type":"object","properties":{"prefix":{"type":"string","description":"\"+\" and the listed prefix"},"country":{"type":"string"},"routes":{"type":"array","items":{"type":"object","properties":{"purchaseId":{"type":"string","format":"uuid"},"routeId":{"type":"string","format":"uuid"},"destinationName":{"type":"string","description":"The listing name as a buyer reads it: generated by the platform, never the seller's text, and ending in the listing reference (e.g. \"Niger Mobile · Ref 7K2Q\", \"A-Z Voice · Premium · Full CLI · Ref 3MX9\"). Your own listings keep the name you gave them."},"position":{"type":"integer","description":"1 is tried first"},"role":{"type":"string","enum":["first","backup","not_tried"],"description":"not_tried: beyond maxAttempts, so never reached by one call"},"apiOnly":{"type":"boolean","description":"true for a backup that calls over your SIP trunk never use (it needs SIP credentials, call screening or a reshaped number, or the first choice does); Voice API calls still fail over to it"}},"required":["purchaseId","routeId","destinationName","position","role","apiOnly"]}},"singleRoute":{"type":"boolean","description":"True when only one of your routes covers this prefix: no backup"}},"required":["prefix","country","routes","singleRoute"]}},"rateSheets":{"type":"array","items":{"type":"object","properties":{"purchaseId":{"type":"string","format":"uuid"},"routeId":{"type":"string","format":"uuid"},"destinationName":{"type":"string","description":"The listing name as a buyer reads it: generated by the platform, never the seller's text, and ending in the listing reference (e.g. \"Niger Mobile · Ref 7K2Q\", \"A-Z Voice · Premium · Full CLI · Ref 3MX9\"). Your own listings keep the name you gave them."}},"required":["purchaseId","routeId","destinationName"]}}},"required":["enabled","maxAttempts","destinations","rateSheets"]},"RouteForResult":{"type":"object","properties":{"number":{"type":"string","description":"The number as checked, \"+\" and digits"},"carriedBy":{"allOf":[{"$ref":"#/components/schemas/RouteForCandidate"}],"nullable":true,"description":"The route that would carry it (candidates[0]); null when none covers it"},"reason":{"type":"string","description":"Why that route wins, in words"},"decidedBy":{"type":"string","enum":["prefix","routing_order","rate","age","route_id"],"description":"The step that decided between the first two routes; null with fewer than two","nullable":true},"candidates":{"type":"array","items":{"$ref":"#/components/schemas/RouteForCandidate"}},"refused":{"type":"object","properties":{"reason":{"type":"string","enum":["embargoed","no_balance"]},"message":{"type":"string"}},"required":["reason","message"],"nullable":true}},"required":["number","carriedBy","reason","decidedBy","candidates","refused"]},"PurchaseUpcomingRateChanges":{"type":"object","properties":{"purchaseId":{"type":"string","format":"uuid"},"affectsYou":{"type":"boolean","description":"True when you pay the list rate, so this change would pause you until accepted"},"changes":{"type":"array","items":{"type":"object","properties":{"changeId":{"type":"string","format":"uuid","description":"Pass as changeId to POST /purchases/{id}/accept-rate"},"kind":{"type":"string","enum":["flat","deck"],"description":"flat = the route's single price changes; deck = rate-sheet rows change"},"effectiveDate":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"increases":{"type":"integer"},"decreases":{"type":"integer"},"added":{"type":"integer"},"removed":{"type":"integer"},"largestIncreasePct":{"type":"number","nullable":true},"accepted":{"type":"boolean"},"acceptedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"rows":{"type":"array","items":{"type":"object","properties":{"destination":{"type":"string","nullable":true},"prefix":{"type":"string","nullable":true},"oldRate":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"US dollars as a decimal string with exactly 6 decimal places, e.g. \"0.012500\". Do money arithmetic with a decimal type, not floating point."},"newRate":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"US dollars as a decimal string with exactly 6 decimal places, e.g. \"0.012500\". Do money arithmetic with a decimal type, not floating point."},"oldIncrement":{"type":"string","nullable":true},"newIncrement":{"type":"string","nullable":true},"deltaPct":{"type":"number","nullable":true},"removed":{"type":"boolean"}},"required":["destination","prefix","oldRate","newRate","oldIncrement","newIncrement","deltaPct","removed"]}},"totalRows":{"type":"integer","description":"Rows in the change for this listing (rows is capped at 200)"}},"required":["changeId","kind","effectiveDate","increases","decreases","added","removed","largestIncreasePct","accepted","acceptedAt","rows","totalRows"]}}},"required":["purchaseId","affectsYou","changes"]},"Offer":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"routeId":{"type":"string","format":"uuid"},"groupId":{"type":"string","format":"uuid","nullable":true,"description":"Set when the offer is part of a bulk (multi-route) offer"},"listPrice":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"The route list price when the offer was made"},"proposedPrice":{"allOf":[{"$ref":"#/components/schemas/Money"}],"description":"The latest price on the table"},"agreedPrice":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"Set once accepted"},"status":{"type":"string","enum":["pending","countered","accepted","rejected","withdrawn","expired"]},"lastActor":{"type":"string","enum":["buyer","seller"]},"message":{"type":"string","nullable":true,"description":"Cleaned of contact details"},"expiresAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"role":{"type":"string","enum":["buyer","seller"],"description":"Your side of this offer"},"yourTurn":{"type":"boolean"},"counterparty":{"type":"string","description":"Pseudonym for the other side, stable per route"},"route":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"destinationName":{"type":"string","description":"The seller reads the name they gave the route; the buyer reads the platform-generated name (see MarketplaceRoute.destinationName)"},"listingRef":{"type":"string","description":"Anonymous short reference of the listing (4 characters, e.g. \"7K2Q\"): stable for the life of the listing, unique enough to tell two same-named listings apart, and derived from the listing alone (it says nothing about the seller). Absent on your own listings."},"country":{"type":"string"},"countryCode":{"type":"string"},"type":{"type":"string","enum":["voice","sms"]},"routeType":{"type":"string"},"pricePerUnit":{"$ref":"#/components/schemas/Money"}},"required":["id","destinationName","country","countryCode","type","routeType","pricePerUnit"],"nullable":true}},"required":["id","routeId","groupId","listPrice","proposedPrice","agreedPrice","status","lastActor","message","expiresAt","createdAt","updatedAt","role","yourTurn","counterparty","route"]},"CallAction":{"anyOf":[{"type":"object","properties":{"say":{"type":"string","minLength":1,"maxLength":500,"description":"Text spoken by our text-to-speech voice"},"language":{"type":"string","enum":["en","es","fr","de","pt","hi"],"description":"Overrides the call default for this action"}},"required":["say"],"description":"say"},{"type":"object","properties":{"play":{"type":"string","format":"uri","maxLength":2048,"description":"HTTPS URL of an MP3 file, at most 2 MB. We download it once before dialling (public addresses only, no redirects) and play our copy"}},"required":["play"],"description":"play"},{"type":"object","properties":{"gather":{"type":"object","properties":{"digits":{"type":"integer","minimum":1,"maximum":20,"default":1,"description":"Most keys to collect"},"timeout":{"type":"integer","minimum":1,"maximum":30,"default":5,"description":"Seconds to wait for the first key"},"finishOnKey":{"type":"string","enum":["#","*",""],"default":"#","description":"Key that ends input early; empty for none"},"tries":{"type":"integer","minimum":1,"maximum":3,"default":1,"description":"Prompt and wait again this many times in total when nothing is pressed"},"say":{"type":"string","minLength":1,"maxLength":500,"description":"Prompt spoken while listening; a key press interrupts it"},"play":{"type":"string","format":"uri","maxLength":2048,"description":"Prompt played while listening (instead of say)"},"language":{"type":"string","enum":["en","es","fr","de","pt","hi"]}}}},"required":["gather"],"description":"gather"},{"type":"object","properties":{"pause":{"type":"integer","minimum":1,"maximum":10,"description":"Seconds of silence"}},"required":["pause"],"description":"pause"},{"type":"object","properties":{"hangup":{"type":"boolean","enum":[true]}},"required":["hangup"],"description":"hangup (must be last)"}]},"CommsCallAccepted":{"type":"object","properties":{"callId":{"type":"string","format":"uuid","description":"Use with GET /comms/calls/{id}; the same id appears on the call.* webhooks"},"status":{"type":"string","enum":["ringing"],"description":"The call has been handed to the network and is being dialled"},"mode":{"type":"string","enum":["async"]},"to":{"type":"string"},"from":{"type":"string"},"actions":{"type":"integer","description":"How many call actions will run on answer"},"statusUrl":{"type":"string","description":"Path of GET /comms/calls/{id} for this call"}},"required":["callId","status","mode","to","from","actions","statusUrl"]},"CommsCallStatus":{"type":"object","properties":{"callId":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["queued","ringing","answered","completed","no_answer","busy","failed"],"description":"queued, ringing and answered are live states; completed (answered, then ended), no_answer, busy and failed are final"},"mode":{"type":"string","enum":["sync","async"]},"to":{"type":"string"},"from":{"type":"string"},"simulated":{"type":"boolean","description":"True for test-key calls: nothing was dialled"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"ringingAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"answeredAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"endedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"durationSeconds":{"type":"integer","nullable":true},"billableSeconds":{"type":"integer","nullable":true,"description":"Duration rounded up to the route billing increment"},"cost":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"What the call cost you, platform fee included. Null until it ends"},"billingIncrement":{"type":"string","nullable":true},"sipResponseCode":{"type":"integer","nullable":true},"hangupCause":{"type":"string","nullable":true,"description":"The switch cause code, e.g. NORMAL_CLEARING or USER_BUSY"},"hangupReason":{"type":"string","nullable":true,"description":"Why the call ended, in plain words. Null while it is live"},"error":{"type":"string","nullable":true,"description":"Why the call could not be placed, when it failed before reaching the network"},"actions":{"type":"array","items":{},"nullable":true,"description":"The call actions as you sent them"},"gathered":{"type":"array","items":{"type":"object","properties":{"index":{"type":"integer","description":"Which gather action (0 for the first)"},"digits":{"type":"string","nullable":true,"description":"The keys pressed, without the finish key"},"status":{"type":"string","enum":["received","no_input"],"description":"no_input: nothing was pressed, or the call ended before this step"}},"required":["index","digits","status"]},"nullable":true,"description":"Keypad input from gather actions, filled in when the call ends"},"routeId":{"type":"string","format":"uuid","nullable":true,"description":"Present when the call was placed over a failover chain: the route that carried it, or the last one tried"},"attempts":{"type":"array","items":{"type":"object","properties":{"attempt":{"type":"integer","description":"1 for the first route tried"},"routeId":{"type":"string","format":"uuid","nullable":true},"status":{"type":"string","description":"answered, failed, busy or no_answer"},"sipResponseCode":{"type":"integer","nullable":true},"hangupCause":{"type":"string","nullable":true}},"required":["attempt","routeId","status","sipResponseCode","hangupCause"]},"description":"Present when the call was tried on more than one route: every attempt in order. Only the attempt that connected is billed"}},"required":["callId","status","mode","to","from","simulated","createdAt","ringingAt","answeredAt","endedAt","durationSeconds","billableSeconds","cost","billingIncrement","sipResponseCode","hangupCause","hangupReason","error","actions","gathered"]},"CommsCall":{"type":"object","properties":{"callId":{"type":"string"},"to":{"type":"string"},"from":{"type":"string"},"status":{"type":"string","enum":["answered","no_answer","busy","failed","accepted"],"description":"Final outcome. `accepted` is returned only for simulated calls on a test key"},"sipResponseCode":{"type":"integer","nullable":true},"hangupCause":{"type":"string","nullable":true},"durationSeconds":{"type":"integer"},"billableSeconds":{"type":"integer","description":"Duration rounded up to the route billing increment"},"cost":{"allOf":[{"$ref":"#/components/schemas/Money"}],"description":"What this call cost you, platform fee included"},"billingIncrement":{"type":"string","description":"The route billing increment, e.g. \"6/6\" or \"60/60\""},"startedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"completedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"simulated":{"type":"boolean","description":"Present and true for test-key calls: nothing was dialled"},"routeId":{"type":"string","format":"uuid","nullable":true,"description":"Present on calls placed over a failover chain (Smart Routing calls with automatic failover, and Switch sub-account calls): the route that carried the call, or the last one tried"},"attempts":{"type":"array","items":{"type":"object","properties":{"routeId":{"type":"string","format":"uuid"},"sipResponseCode":{"type":"integer","nullable":true},"status":{"type":"string"},"hangupCause":{"type":"string","nullable":true}},"required":["routeId","sipResponseCode","status","hangupCause"]},"description":"Present when the call was tried on more than one route: each route tried, in order. Only the one that connected is billed; a wrong number (404/484), a busy or declined call and no answer are never retried"}},"required":["callId","to","from","status","sipResponseCode","hangupCause","durationSeconds","billableSeconds","cost","billingIncrement","startedAt","completedAt"]},"CommsSms":{"type":"object","properties":{"messageId":{"type":"string","description":"Use with GET /comms/sms/{messageId}"},"to":{"type":"string"},"from":{"type":"string"},"status":{"type":"string","enum":["sent","delivered","failed","pending","accepted"],"description":"Send-time outcome when we forwarded the message, not a handset delivery receipt"},"segments":{"type":"integer","description":"Billed segments (160 GSM-7 / 70 UCS-2 characters each, fewer when concatenated)"},"cost":{"$ref":"#/components/schemas/Money"},"submittedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"simulated":{"type":"boolean","description":"Present and true for test-key messages: nothing was sent"},"network":{"type":"object","properties":{"mccMnc":{"type":"string","nullable":true,"description":"Mobile network code (MCC-MNC) the message was priced as, e.g. \"234-10\""},"operator":{"type":"string","nullable":true,"description":"Network name from public number-range data"},"source":{"type":"string","enum":["range","hlr","none"],"description":"range = number-range data; hlr = a live network lookup; none = not determined"},"rateBasis":{"type":"string","enum":["network","all_operators","country"],"description":"network = that network's own rate; all_operators = the route's rate for networks it does not list separately; country = the route's price for other or unknown networks"}},"required":["mccMnc","operator","source","rateBasis"],"nullable":true,"description":"Present when the route prices SMS to this country per destination network. The network is determined from the number's range (ported numbers may be priced at the network the range belongs to)"}},"required":["messageId","to","from","status","segments","cost","submittedAt"]},"CommsHistoryEntry":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"type":{"type":"string","description":"Ledger entry type, e.g. charge"},"amount":{"allOf":[{"$ref":"#/components/schemas/Money"}],"description":"Signed: a charge is negative"},"balanceAfter":{"$ref":"#/components/schemas/Money"},"reference":{"type":"string","nullable":true,"description":"Human-readable description of the call or message"},"relatedEntityType":{"type":"string","nullable":true,"description":"api_call for calls; api_sms or smpp_sms for messages"},"relatedEntityId":{"type":"string","format":"uuid","nullable":true,"description":"The callId or messageId"},"callId":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","userId","type","amount","balanceAfter","reference","relatedEntityType","relatedEntityId","callId","createdAt"]},"SmsTimelineStep":{"type":"object","properties":{"status":{"type":"string","enum":["queued","sent","accepted","delivered","failed"],"description":"queued = charged and waiting to be handed off; sent = the route accepted it; accepted = simulated on a test key; delivered / failed = final"},"at":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"source":{"type":"string","enum":["platform","submit","carrier_receipt","simulated"],"description":"Where we learned it: our ledger, the hand-off to the route, the carrier's delivery receipt, or a test-key simulation"},"errorCode":{"type":"string","nullable":true,"description":"On failed: SELLER_REJECTED, NO_ENDPOINT, UNDELIVERABLE, EXPIRED, REJECTED or TEMPORARY_FAILURE"},"carrierStatus":{"type":"string","nullable":true,"description":"The carrier receipt's own status value, e.g. DELIVRD or UNDELIV"},"carrierError":{"type":"string","nullable":true,"description":"The carrier receipt's own error value, when it sent one"}},"required":["status","at","source"]},"CommsSmsStatus":{"type":"object","properties":{"messageId":{"type":"string"},"status":{"type":"string","description":"Current state: sent, accepted (test key), delivered or failed; not_found when the id is not on your account. delivered only ever comes from a carrier receipt"},"to":{"type":"string","nullable":true},"from":{"type":"string","nullable":true},"segments":{"type":"integer","nullable":true},"errorCode":{"type":"string","nullable":true,"description":"Set when status is failed: SELLER_REJECTED (the route refused the hand-off), NO_ENDPOINT, UNDELIVERABLE, EXPIRED or REJECTED (from the carrier receipt), or TEMPORARY_FAILURE (the supplier session was momentarily unavailable on our side; retry)"},"timeline":{"type":"array","items":{"$ref":"#/components/schemas/SmsTimelineStep"},"description":"Every state the message has been in, oldest first"},"awaitingReceipt":{"type":"boolean","description":"True while the message is sent and no carrier receipt has arrived. It stays true for good on a route that returns no receipts"},"routeReturnsReceipts":{"type":"boolean","nullable":true,"description":"Whether the route that carried this message has returned at least one carrier receipt in the last 30 days. null for test-key messages"},"dlrSupported":{"type":"boolean","description":"True: the platform collects carrier delivery receipts. Whether one arrives for this message depends on the route (routeReturnsReceipts)"},"simulated":{"type":"boolean","description":"Present and true for test-key messages: nothing was sent"},"cost":{"$ref":"#/components/schemas/Money","description":"The ledger amount of the charge (negative)"},"reference":{"type":"string","nullable":true},"sentAt":{"type":"string","format":"date-time","description":"When the message was charged"},"message":{"type":"string","description":"Explanation, present when status is not_found"}},"required":["messageId","status"]},"CommsBulkSmsResult":{"type":"object","properties":{"total":{"type":"integer"},"sent":{"type":"integer"},"failed":{"type":"integer","description":"Failed plus skipped"},"totalCost":{"$ref":"#/components/schemas/Money"},"results":{"type":"array","items":{"type":"object","properties":{"to":{"type":"string"},"status":{"type":"string","description":"The send status, or failed / skipped"},"messageId":{"type":"string"},"from":{"type":"string"},"segments":{"type":"integer"},"cost":{"$ref":"#/components/schemas/Money","description":"US dollars as a decimal string with exactly 6 decimal places, e.g. \"0.012500\". Do money arithmetic with a decimal type, not floating point."},"submittedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"error":{"type":"string"}},"required":["to","status"]}}},"required":["total","sent","failed","totalCost","results"]},"VoiceOtpResult":{"type":"object","properties":{"voiceOtpId":{"type":"string","format":"uuid","description":"Use with GET /comms/voice-otp/{id}"},"callId":{"type":"string","description":"The call carrying the code; it also appears in GET /comms/calls and the call.completed webhook"},"status":{"type":"string","enum":["initiated","accepted"],"description":"`initiated`: the call is ringing. `accepted`: simulated on a test key"},"to":{"type":"string"},"from":{"type":"string","description":"The caller ID presented"},"language":{"type":"string"},"codeLength":{"type":"integer"},"repeat":{"type":"integer","description":"How many times the code is read"},"code":{"type":"string","description":"Present only when we generated the code AND you sent `returnCode: true`"},"cost":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"Test keys: the simulated charge. Live: null here; the final cost arrives with call.completed and on GET"},"simulated":{"type":"boolean","description":"Present and true for test keys: nothing was dialled"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["voiceOtpId","callId","status","to","from","language","codeLength","repeat","cost","createdAt"]},"VoiceOtpStatus":{"type":"object","properties":{"voiceOtpId":{"type":"string","format":"uuid"},"callId":{"type":"string","nullable":true},"status":{"type":"string","enum":["initiated","answered","no_answer","busy","failed","accepted"]},"to":{"type":"string"},"language":{"type":"string"},"codeLength":{"type":"integer"},"cost":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"What the call cost you, platform fee included. Null until it ends"},"durationSeconds":{"type":"integer","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"completedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"simulated":{"type":"boolean"}},"required":["voiceOtpId","callId","status","to","language","codeLength","cost","durationSeconds","createdAt","completedAt"]},"VerifyStartResult":{"type":"object","properties":{"verificationId":{"type":"string","format":"uuid","description":"Pass to POST /verify/check"},"reference":{"type":"string","nullable":true,"description":"Your reference, when you sent one"},"to":{"type":"string"},"channel":{"type":"string","enum":["sms","voice"]},"status":{"type":"string","enum":["pending"]},"expiresAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"maxAttempts":{"type":"integer","description":"Wrong guesses allowed before the verification is dead (5)"},"sendRef":{"type":"string","description":"The messageId (SMS) or callId (voice) that carried the code"},"sendStatus":{"type":"string","description":"SMS send-time status, or `initiated` for a voice call"},"simulated":{"type":"boolean","description":"Present and true for test keys: nothing was sent"},"testCode":{"type":"string","description":"Test keys ONLY: the code, so a sandbox can complete the check. Never present on a live key"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["verificationId","reference","to","channel","status","expiresAt","maxAttempts","sendRef","sendStatus","createdAt"]},"VerifyCheckResult":{"type":"object","properties":{"verificationId":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["approved","denied","expired","max_attempts"]},"attemptsRemaining":{"type":"integer"},"reason":{"type":"string","enum":["wrong_code","already_used","not_pending"],"description":"Why a check was not approved, when it is not obvious from `status`"}},"required":["verificationId","status","attemptsRemaining"]},"CallInVerification":{"type":"object","properties":{"verificationId":{"type":"string","format":"uuid","description":"Use with GET /verify/{id}"},"reference":{"type":"string","nullable":true,"description":"Your reference, when you sent one"},"to":{"type":"string","description":"The phone number being verified"},"channel":{"type":"string","enum":["call_in"]},"status":{"type":"string","enum":["pending","approved","expired"]},"callNumber":{"type":"string","description":"The number the user must call from `to` (E.164)"},"callNumberDisplay":{"type":"string","description":"The same number formatted for people, e.g. +1 (773) 232-1843"},"callerNumber":{"type":"string","nullable":true,"description":"The caller ID the approving call came from"},"callReceivedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"callerIdAttestation":{"type":"string","nullable":true,"description":"What the calling carrier said about the caller ID, when it said anything: STIR/SHAKEN attestation A, B or C, or a verstat value such as TN-Validation-Passed. Null when nothing was passed"},"expiresAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"approvedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"price":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"Charged once, when approved. Expired verifications are free"},"instructions":{"type":"string","description":"Start only: a sentence you can show the user as-is"},"simulated":{"type":"boolean","description":"Present and true for test keys"}},"required":["verificationId","reference","to","channel","status","callNumber","callNumberDisplay","callerNumber","callReceivedAt","callerIdAttestation","expiresAt","createdAt","approvedAt","price"]},"CallInCoverage":{"type":"object","properties":{"price":{"allOf":[{"$ref":"#/components/schemas/Money"}],"description":"Per approved call-in verification"},"currency":{"type":"string","enum":["USD"]},"numbers":{"type":"array","items":{"type":"object","properties":{"country":{"type":"string","description":"ISO country of the number to call"},"coversDialCode":{"type":"string","description":"Phone numbers starting with this dial code can be verified with it"},"callNumber":{"type":"string"},"callNumberDisplay":{"type":"string"},"yours":{"type":"boolean","description":"True for your own number (switched on under call-in numbers)"}},"required":["country","coversDialCode","callNumber","callNumberDisplay","yours"]}}},"required":["price","currency","numbers"]},"CallInNumber":{"type":"object","properties":{"phoneNumberId":{"type":"string","format":"uuid","description":"Your phone number's id (the same id as in the DID Store)"},"number":{"type":"string"},"numberDisplay":{"type":"string"},"country":{"type":"string","nullable":true},"verifiesDialCode":{"type":"string","nullable":true,"description":"Phone numbers starting with this dial code are verified with this number"},"type":{"type":"string","nullable":true},"status":{"type":"string"},"callInEnabled":{"type":"boolean"},"hasCallRouting":{"type":"boolean","description":"The number has ringing set up. While call-in is on, calls to it are used for verification only and never ring"}},"required":["phoneNumberId","number","numberDisplay","country","verifiesDialCode","type","status","callInEnabled","hasCallRouting"]},"Verification":{"type":"object","properties":{"verificationId":{"type":"string","format":"uuid"},"reference":{"type":"string","nullable":true},"to":{"type":"string"},"channel":{"type":"string","enum":["sms","voice"]},"status":{"type":"string","enum":["pending","approved","expired","max_attempts","failed"]},"attempts":{"type":"integer"},"maxAttempts":{"type":"integer"},"expiresAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"approvedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"sendRef":{"type":"string","nullable":true},"sendStatus":{"type":"string","nullable":true},"simulated":{"type":"boolean"}},"required":["verificationId","reference","to","channel","status","attempts","maxAttempts","expiresAt","createdAt","approvedAt","sendRef","sendStatus"]},"DidCatalogSku":{"type":"object","properties":{"skuId":{"type":"string","description":"Pass to POST /dids/buy"},"channels":{"type":"integer","description":"Concurrent call channels included"},"setupPrice":{"type":"number","description":"One-off price in USD (display number, not a money string)"},"monthlyPrice":{"type":"number","description":"Monthly price in USD (display number, not a money string)"}},"required":["skuId","channels","setupPrice","monthlyPrice"]},"DidCatalogGroup":{"type":"object","properties":{"groupId":{"type":"string","description":"Pass to POST /dids/buy with a skuId"},"country":{"type":"string"},"countryId":{"type":"string","description":"Catalogue country id (filter value), not an ISO code"},"countryPrefix":{"type":"string"},"city":{"type":"string","nullable":true},"areaPrefix":{"type":"string","nullable":true},"typeId":{"type":"string","nullable":true},"typeName":{"type":"string","nullable":true,"description":"Local, National, Mobile, Toll-free..."},"skus":{"type":"array","items":{"$ref":"#/components/schemas/DidCatalogSku"}}},"required":["groupId","country","countryId","countryPrefix","city","areaPrefix","typeId","typeName","skus"]},"DidCatalogCountry":{"type":"object","properties":{"countryId":{"type":"string"},"country":{"type":"string"},"countryPrefix":{"type":"string"}},"required":["countryId","country","countryPrefix"]},"DidCatalogType":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"]},"DidCatalogSummary":{"anyOf":[{"type":"object","properties":{"ready":{"type":"boolean","enum":[true]},"complete":{"type":"boolean","description":"false when the catalogue was larger than the indexing budget, so the figures are a lower bound"},"asOf":{"type":"string","format":"date-time","description":"When the catalogue was last indexed"},"groups":{"type":"integer","description":"Buyable number groups (a city, area or national pool you order a number from)"},"countries":{"type":"integer"},"fromMonthly":{"type":"number","nullable":true,"description":"Cheapest monthly price in the catalogue, USD"},"types":{"type":"array","items":{"type":"object","properties":{"typeId":{"type":"string"},"typeName":{"type":"string","description":"Local, National, Mobile, Toll-free..."},"groups":{"type":"integer","description":"Number groups of this type"},"countries":{"type":"integer","description":"Countries with at least one group of this type"},"fromMonthly":{"type":"number","nullable":true,"description":"Cheapest monthly price of this type, USD"},"fromSetup":{"type":"number","nullable":true,"description":"Cheapest one-off setup price of this type, USD"}},"required":["typeId","typeName","groups","countries","fromMonthly","fromSetup"]},"description":"Most groups first"},"countryList":{"type":"array","items":{"type":"object","properties":{"countryId":{"type":"string","description":"Catalogue country id (filter value)"},"country":{"type":"string"},"countryPrefix":{"type":"string"},"groups":{"type":"integer"},"fromMonthly":{"type":"number","nullable":true,"description":"Cheapest monthly price in this country, USD"},"typeIds":{"type":"array","items":{"type":"string"},"description":"Number types sold in this country"}},"required":["countryId","country","countryPrefix","groups","fromMonthly","typeIds"]},"description":"Alphabetical"}},"required":["ready","complete","asOf","groups","countries","fromMonthly","types","countryList"]},{"type":"object","properties":{"ready":{"type":"boolean","enum":[false],"description":"The catalogue is being indexed (the first minute after a restart); ask again shortly"}},"required":["ready"]}]},"Did":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"number":{"type":"string","nullable":true,"description":"null while the number is still being provisioned"},"country":{"type":"string","nullable":true},"countryCode":{"type":"string","minLength":2,"maxLength":2,"description":"ISO-3166-1 alpha-2 country code","nullable":true},"city":{"type":"string","nullable":true},"areaPrefix":{"type":"string","nullable":true},"didType":{"type":"string","nullable":true},"channelsIncluded":{"type":"integer"},"status":{"type":"string","enum":["pending","active","suspended","released","failed"],"description":"suspended = a monthly renewal failed; the number is held for `graceDays` before release"},"pointMode":{"type":"string","enum":["unrouted","sip","forward"]},"pointsTo":{"type":"string","nullable":true,"description":"Primary destination: host[:port] for sip, E.164 for forward"},"pointsToBackup":{"type":"string","nullable":true},"autoRenew":{"type":"boolean"},"setupPrice":{"$ref":"#/components/schemas/Money"},"monthlyPrice":{"$ref":"#/components/schemas/Money"},"orderedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"activatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"nextRenewalAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"suspendedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"releasedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"endpointReachable":{"type":"boolean","nullable":true,"description":"null = not checked yet"},"endpointCause":{"type":"string","nullable":true},"endpointCheckedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"aiAgentId":{"type":"string","format":"uuid","nullable":true,"description":"The AI voice agent answering inbound calls to this number, or null (PUT /dids/{id}/ai-agent)"},"graceDays":{"type":"integer","description":"Days an unpaid (suspended) number is held before release"}},"required":["id","number","country","countryCode","city","areaPrefix","didType","channelsIncluded","status","pointMode","pointsTo","pointsToBackup","autoRenew","setupPrice","monthlyPrice","orderedAt","activatedAt","nextRenewalAt","suspendedAt","releasedAt","endpointReachable","endpointCause","endpointCheckedAt","aiAgentId","graceDays"]},"DidBulkBuyResult":{"type":"object","properties":{"requested":{"type":"integer"},"succeeded":{"type":"integer"},"failed":{"type":"integer"},"skipped":{"type":"integer"},"items":{"type":"array","items":{"type":"object","properties":{"index":{"type":"integer","description":"Position in the submitted array"},"skuId":{"type":"string"},"groupId":{"type":"string"},"status":{"type":"string","enum":["ok","failed","skipped"]},"did":{"$ref":"#/components/schemas/Did","description":"Present when status is ok"},"error":{"type":"string"}},"required":["index","skuId","groupId","status"]}}},"required":["requested","succeeded","failed","skipped","items"]},"DidCallFlow":{"type":"object","properties":{"strategy":{"type":"string","enum":["failover","simultaneous"]},"timeoutSec":{"type":"integer"},"endpoints":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"kind":{"type":"string","enum":["sip","forward","hosted"]},"target":{"type":"string","nullable":true},"sipUsername":{"type":"string","nullable":true,"description":"Hosted lines only; the password is never listed"},"label":{"type":"string","nullable":true},"priority":{"type":"integer"},"enabled":{"type":"boolean"}},"required":["id","kind","target","sipUsername","label","priority","enabled"]}}},"required":["strategy","timeoutSec","endpoints"]},"DidSipLineLogin":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"sipUsername":{"type":"string"},"sipPassword":{"type":"string","description":"Shown only here and on an explicit reveal"},"server":{"type":"string"},"port":{"type":"string"}},"required":["id","sipUsername","sipPassword","server","port"]},"DidSipLine":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"sipUsername":{"type":"string"},"label":{"type":"string","nullable":true},"priority":{"type":"integer"},"enabled":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","sipUsername","label","priority","enabled","createdAt"]},"DidCalls":{"type":"object","properties":{"calls":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"fromNumber":{"type":"string","nullable":true},"toNumber":{"type":"string","nullable":true},"durationSec":{"type":"integer"},"status":{"type":"string","nullable":true},"startedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","fromNumber","toNumber","durationSec","status","startedAt"]}},"summary":{"type":"object","properties":{"calls":{"type":"integer"},"minutes":{"type":"number"}},"required":["calls","minutes"]}},"required":["calls","summary"]},"DidFeatures":{"type":"object","properties":{"voicemail":{"type":"object","properties":{"enabled":{"type":"boolean"},"mode":{"type":"string","enum":["on_no_answer","always"]},"greetingAssetId":{"type":"string","format":"uuid","nullable":true},"hasGreeting":{"type":"boolean"},"transcribe":{"type":"boolean"}},"required":["enabled","mode","greetingAssetId","hasGreeting","transcribe"]},"recording":{"type":"object","properties":{"enabled":{"type":"boolean"},"announce":{"type":"boolean"},"retentionDays":{"type":"integer"}},"required":["enabled","announce","retentionDays"]},"ivr":{"type":"object","properties":{"enabled":{"type":"boolean"},"greetingAssetId":{"type":"string","format":"uuid","nullable":true},"hasGreeting":{"type":"boolean"},"timeoutSec":{"type":"integer"},"maxRetries":{"type":"integer"},"options":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"digit":{"type":"string"},"action":{"type":"string","enum":["endpoint","voicemail","hangup"]},"endpointId":{"type":"string","format":"uuid","nullable":true},"label":{"type":"string","nullable":true}},"required":["id","digit","action","endpointId","label"]}}},"required":["enabled","greetingAssetId","hasGreeting","timeoutSec","maxRetries","options"]},"schedule":{"type":"object","properties":{"enabled":{"type":"boolean"},"timezone":{"type":"string"},"schedule":{"type":"object","required":["sun","mon","tue","wed","thu","fri","sat"],"properties":{"sun":{"type":"array","items":{"type":"object","properties":{"open":{"type":"string","maxLength":5,"description":"HH:MM"},"close":{"type":"string","maxLength":5,"description":"HH:MM"}},"required":["open","close"]}},"mon":{"type":"array","items":{"type":"object","properties":{"open":{"type":"string","maxLength":5,"description":"HH:MM"},"close":{"type":"string","maxLength":5,"description":"HH:MM"}},"required":["open","close"]}},"tue":{"type":"array","items":{"type":"object","properties":{"open":{"type":"string","maxLength":5,"description":"HH:MM"},"close":{"type":"string","maxLength":5,"description":"HH:MM"}},"required":["open","close"]}},"wed":{"type":"array","items":{"type":"object","properties":{"open":{"type":"string","maxLength":5,"description":"HH:MM"},"close":{"type":"string","maxLength":5,"description":"HH:MM"}},"required":["open","close"]}},"thu":{"type":"array","items":{"type":"object","properties":{"open":{"type":"string","maxLength":5,"description":"HH:MM"},"close":{"type":"string","maxLength":5,"description":"HH:MM"}},"required":["open","close"]}},"fri":{"type":"array","items":{"type":"object","properties":{"open":{"type":"string","maxLength":5,"description":"HH:MM"},"close":{"type":"string","maxLength":5,"description":"HH:MM"}},"required":["open","close"]}},"sat":{"type":"array","items":{"type":"object","properties":{"open":{"type":"string","maxLength":5,"description":"HH:MM"},"close":{"type":"string","maxLength":5,"description":"HH:MM"}},"required":["open","close"]}}},"nullable":true},"holidays":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string","maxLength":10,"description":"YYYY-MM-DD"},"name":{"type":"string","maxLength":120}},"required":["date"]},"nullable":true},"outsideHoursAction":{"type":"string","enum":["voicemail","endpoints","hangup"]},"closedEndpoints":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"kind":{"type":"string","enum":["sip","forward"]},"target":{"type":"string"},"label":{"type":"string","nullable":true},"priority":{"type":"integer"},"enabled":{"type":"boolean"}},"required":["id","kind","target","label","priority","enabled"]}},"openNow":{"type":"boolean","nullable":true}},"required":["enabled","timezone","schedule","holidays","outsideHoursAction","closedEndpoints","openNow"]},"assets":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"kind":{"type":"string","enum":["voicemail_greeting","ivr_greeting"]},"name":{"type":"string","nullable":true},"mime":{"type":"string"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","kind","name","mime","createdAt"]}},"mediaLive":{"type":"boolean","description":"Whether voicemail and recording capture is live on the platform"}},"required":["voicemail","recording","ivr","schedule","assets","mediaLive"]},"DidGreeting":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"kind":{"type":"string","enum":["voicemail_greeting","ivr_greeting"]},"name":{"type":"string","nullable":true},"mime":{"type":"string"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","kind","name","mime","createdAt"]},"DidRecording":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"kind":{"type":"string","enum":["call","voicemail"]},"fromNumber":{"type":"string","nullable":true},"toNumber":{"type":"string","nullable":true},"durationSec":{"type":"integer"},"mime":{"type":"string","nullable":true},"byteSize":{"type":"integer"},"heard":{"type":"boolean"},"transcript":{"type":"string","nullable":true},"hasAudio":{"type":"boolean"},"expiresAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","kind","fromNumber","toNumber","durationSec","mime","byteSize","heard","transcript","hasAudio","expiresAt","createdAt"]},"DidMessage":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"direction":{"type":"string","enum":["in","out"]},"from":{"type":"string"},"to":{"type":"string"},"peer":{"type":"string","description":"The other party, digits only; the conversation key"},"body":{"type":"string"},"segments":{"type":"integer"},"status":{"type":"string","enum":["received","queued","sent","delivered","failed"]},"error":{"type":"string","nullable":true},"providerMessageId":{"type":"string","nullable":true,"description":"Upstream carrier message id"},"readAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","direction","from","to","peer","body","segments","status","error","providerMessageId","readAt","createdAt"]},"DidSmsSettings":{"type":"object","properties":{"smsEnabled":{"type":"boolean"},"forwardWebhookUrl":{"type":"string","nullable":true,"description":"https URL each inbound SMS is forwarded to"},"notifyEmail":{"type":"string","nullable":true}},"required":["smsEnabled","forwardWebhookUrl","notifyEmail"]},"DidConversation":{"type":"object","properties":{"peer":{"type":"string"},"lastBody":{"type":"string"},"lastDirection":{"type":"string","enum":["in","out"]},"lastStatus":{"type":"string","enum":["received","queued","sent","delivered","failed"]},"lastAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"unread":{"type":"integer"},"total":{"type":"integer"}},"required":["peer","lastBody","lastDirection","lastStatus","lastAt","unread","total"]},"DidAnalytics":{"type":"object","properties":{"number":{"type":"string","nullable":true},"status":{"type":"string"},"price":{"type":"object","properties":{"setup":{"$ref":"#/components/schemas/Money"},"monthly":{"$ref":"#/components/schemas/Money"}},"required":["setup","monthly"]},"spend":{"type":"object","properties":{"gross":{"type":"number"},"refunded":{"type":"number"},"net":{"type":"number"},"setup":{"type":"number"},"recurring":{"type":"number"}},"required":["gross","refunded","net","setup","recurring"],"description":"USD as display numbers"},"usage":{"type":"object","properties":{"calls":{"type":"integer"},"callMinutes":{"type":"number"},"sms":{"type":"integer"},"voicemails":{"type":"integer"},"voicemailMinutes":{"type":"number"}},"required":["calls","callMinutes","sms","voicemails","voicemailMinutes"]},"window":{"type":"object","properties":{"months":{"type":"integer"},"from":{"type":"string"}},"required":["months","from"]},"series":{"type":"array","items":{"type":"object","properties":{"calls":{"type":"integer"},"callMinutes":{"type":"number"},"sms":{"type":"integer"},"voicemails":{"type":"integer"},"voicemailMinutes":{"type":"number"},"period":{"type":"string","description":"YYYY-MM"},"spend":{"type":"number","description":"USD, display number"}},"required":["calls","callMinutes","sms","voicemails","voicemailMinutes","period","spend"]}}},"required":["number","status","price","spend","usage","window","series"]},"DidNumbersOverview":{"type":"object","properties":{"counts":{"type":"object","properties":{"total":{"type":"integer"},"active":{"type":"integer"},"pending":{"type":"integer"},"suspended":{"type":"integer"},"released":{"type":"integer"},"failed":{"type":"integer"}},"required":["total","active","pending","suspended","released","failed"]},"monthlyRecurring":{"type":"number","description":"Sum of monthly prices on active numbers, USD display number"},"lifetimeSpend":{"type":"number","description":"Net charged across all your numbers, USD display number"},"usage":{"type":"object","properties":{"calls":{"type":"integer"},"callMinutes":{"type":"number"},"sms":{"type":"integer"},"voicemails":{"type":"integer"},"voicemailMinutes":{"type":"number"}},"required":["calls","callMinutes","sms","voicemails","voicemailMinutes"]}},"required":["counts","monthlyRecurring","lifetimeSpend","usage"]},"DidListingRequestView":{"type":"object","properties":{"ownedActiveDids":{"type":"integer"},"request":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string"},"selectedDids":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"number":{"type":"string","nullable":true},"country":{"type":"string","nullable":true},"didType":{"type":"string","nullable":true}},"required":["id","number","country","didType"]},"nullable":true},"didCount":{"type":"integer","nullable":true},"submittedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"reviewedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true}},"required":["id","status","selectedDids","didCount","submittedAt","reviewedAt"],"nullable":true,"description":"Your latest request, or null"},"prefill":{"type":"object","properties":{"companyName":{"type":"string"},"contactName":{"type":"string"},"contactEmail":{"type":"string"},"contactPhone":{"type":"string"}},"required":["companyName","contactName","contactEmail","contactPhone"]}},"required":["ownedActiveDids","request","prefill"]},"DidCliEligible":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"cli":{"type":"string","description":"Digits only"},"number":{"type":"string"},"country":{"type":"string","nullable":true},"countryCode":{"type":"string","nullable":true},"city":{"type":"string","nullable":true},"didType":{"type":"string","nullable":true},"channels":{"type":"integer"},"label":{"type":"string","nullable":true}},"required":["id","cli","number","country","countryCode","city","didType","channels","label"]},"DidAiAgent":{"type":"object","properties":{"didId":{"type":"string","format":"uuid"},"agentId":{"type":"string","format":"uuid","nullable":true},"agentName":{"type":"string","nullable":true},"agentEnabled":{"type":"boolean","nullable":true,"description":"A disabled agent does not answer; the number rings its call flow"},"live":{"type":"boolean","description":"Whether inbound AI answering is switched on for the platform right now"},"ratePerMin":{"type":"string","description":"AI voice rate in USD per minute, billed per second"}},"required":["didId","agentId","agentName","agentEnabled","live","ratePerMin"]},"NumberLookup":{"type":"object","properties":{"input":{"type":"string","description":"What you sent"},"valid":{"type":"boolean","description":"Whether the input is a well-formed E.164 number"},"reason":{"type":"string","nullable":true,"description":"Why it is not valid, when it is not"},"e164":{"type":"string","nullable":true,"description":"+ followed by digits, e.g. +447700900123"},"internationalFormat":{"type":"string","nullable":true,"description":"+<country code> <rest>, e.g. +44 7700900123"},"country":{"type":"object","properties":{"iso":{"type":"string","nullable":true,"description":"ISO 3166 alpha-2. null for a shared dial code the decks do not resolve (+1, +7)"},"name":{"type":"string"},"dialCode":{"type":"string"},"basis":{"type":"string","enum":["rate_decks","dial_code"],"description":"rate_decks when the matching destinations name the country; dial_code otherwise"}},"required":["iso","name","dialCode","basis"],"nullable":true},"numberType":{"type":"string","enum":["mobile","fixed","toll_free","premium","unknown"],"description":"Inferred from the destination names on the rate decks that match the number (prefix-based, not an HLR query)"},"numberTypeConfidence":{"type":"number","description":"0 to 1: the share of matching decks that agree on numberType"},"operator":{"type":"string","nullable":true,"description":"The network, only when at least three different sellers' decks name the same one for this prefix. Prefix-based: a ported number keeps its original network here"},"network":{"type":"object","properties":{"mccMnc":{"type":"string","nullable":true,"description":"Mobile network code (MCC-MNC), when known, e.g. \"234-58\""},"operator":{"type":"string","nullable":true,"description":"The network the number range was allocated to, e.g. \"Manx Telecom\""},"source":{"type":"string","enum":["range","hlr"],"description":"range = public number-range data"}},"required":["mccMnc","operator","source"],"nullable":true,"description":"The mobile network the number's RANGE belongs to, from public number-range data. A ported number keeps its range's network here. null when the range is not known"},"matchedPrefix":{"type":"string","nullable":true,"description":"The longest dial prefix any live deck matched"},"risk":{"type":"object","properties":{"blocked":{"type":"boolean","description":"A destination we do not carry (embargoed or platform-blocked)"},"sanctioned":{"type":"boolean"},"highRisk":{"type":"boolean","description":"Premium-rate, or a prefix on our high-risk list (satellite, remote and high-cost destinations often abused for revenue-share fraud)"},"reasons":{"type":"array","items":{"type":"string"}}},"required":["blocked","sanctioned","highRisk","reasons"]},"pricing":{"type":"object","properties":{"voice":{"type":"object","properties":{"rate":{"type":"string","description":"USD, 6 decimals: per minute for voice, per message for SMS"},"currency":{"type":"string","enum":["USD"]},"unit":{"type":"string","enum":["min","msg"]},"billingIncrement":{"type":"string","nullable":true,"description":"e.g. \"60/60\"; null when the listing does not state one"},"destination":{"type":"string","description":"The destination the number matched on that route, e.g. \"United Kingdom-Mobile\""},"routeId":{"type":"string","format":"uuid","description":"The cheapest public route that serves the number (see GET /routes/{id})"},"routesServing":{"type":"integer","description":"How many public routes serve the number"},"network":{"type":"object","properties":{"mccMnc":{"type":"string","nullable":true,"description":"Mobile network code (MCC-MNC) the price is for, e.g. \"234-10\"; null when unknown"},"operator":{"type":"string","nullable":true,"description":"Network name from public number-range data, e.g. \"O2\""},"source":{"type":"string","enum":["range","hlr","none"],"description":"range = number-range data; none = not determined"},"rateBasis":{"type":"string","enum":["network","all_operators","country"],"description":"network = that network's own rate; all_operators = the route's rate for networks it does not list separately; country = the route's price for other or unknown networks"}},"required":["mccMnc","operator","source","rateBasis"],"description":"SMS only: the network `rate` is for, when the route prices per network; null otherwise","nullable":true},"countryRate":{"type":"string","nullable":true,"description":"SMS only: the route's price for other or unknown networks (USD, 6 decimals), when it prices per network"}},"required":["rate","currency","unit","billingIncrement","destination","routeId","routesServing"],"nullable":true,"description":"The cheapest live public route for the number, or null when none serves it"},"sms":{"type":"object","properties":{"rate":{"type":"string","description":"USD, 6 decimals: per minute for voice, per message for SMS"},"currency":{"type":"string","enum":["USD"]},"unit":{"type":"string","enum":["min","msg"]},"billingIncrement":{"type":"string","nullable":true,"description":"e.g. \"60/60\"; null when the listing does not state one"},"destination":{"type":"string","description":"The destination the number matched on that route, e.g. \"United Kingdom-Mobile\""},"routeId":{"type":"string","format":"uuid","description":"The cheapest public route that serves the number (see GET /routes/{id})"},"routesServing":{"type":"integer","description":"How many public routes serve the number"},"network":{"type":"object","properties":{"mccMnc":{"type":"string","nullable":true,"description":"Mobile network code (MCC-MNC) the price is for, e.g. \"234-10\"; null when unknown"},"operator":{"type":"string","nullable":true,"description":"Network name from public number-range data, e.g. \"O2\""},"source":{"type":"string","enum":["range","hlr","none"],"description":"range = number-range data; none = not determined"},"rateBasis":{"type":"string","enum":["network","all_operators","country"],"description":"network = that network's own rate; all_operators = the route's rate for networks it does not list separately; country = the route's price for other or unknown networks"}},"required":["mccMnc","operator","source","rateBasis"],"description":"SMS only: the network `rate` is for, when the route prices per network; null otherwise","nullable":true},"countryRate":{"type":"string","nullable":true,"description":"SMS only: the route's price for other or unknown networks (USD, 6 decimals), when it prices per network"}},"required":["rate","currency","unit","billingIncrement","destination","routeId","routesServing"],"nullable":true,"description":"The cheapest live public route for the number, or null when none serves it"}},"required":["voice","sms"]},"method":{"type":"string","enum":["prefix"],"description":"Always prefix: no carrier network query is made"},"cachedAt":{"type":"string","description":"When this answer was computed. Answers are cached for up to 10 minutes"}},"required":["input","valid","reason","e164","internationalFormat","country","numberType","numberTypeConfidence","operator","network","matchedPrefix","risk","pricing","method","cachedAt"]},"LedgerTransaction":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"type":{"type":"string","enum":["topup","charge","credit","payout","platform_fee","test_credit","chargeback","refund_reversal","refund","transfer"],"description":"charge = usage you paid for; credit = seller earnings or a grant; platform_fee = the exchange fee"},"amount":{"allOf":[{"$ref":"#/components/schemas/Money"}],"description":"Signed: negative for money out (charges, fees, payouts), positive for money in"},"balanceAfter":{"$ref":"#/components/schemas/Money"},"reference":{"type":"string","nullable":true},"relatedEntityType":{"type":"string","nullable":true},"relatedEntityId":{"type":"string","format":"uuid","nullable":true},"callId":{"type":"string","nullable":true,"description":"The call or message this line bills; equals the CDR callUuid"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","userId","type","amount","balanceAfter","reference","relatedEntityType","relatedEntityId","createdAt"],"additionalProperties":true},"BillingCdr":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"callUuid":{"type":"string","nullable":true},"callGroupId":{"type":"string","format":"uuid","nullable":true,"description":"Groups the legs of one customer call when it failed over"},"direction":{"type":"string","enum":["outbound","inbound"]},"kind":{"type":"string","enum":["voice","sms"]},"routeId":{"type":"string","format":"uuid","nullable":true},"fromNumber":{"type":"string","nullable":true},"toNumber":{"type":"string","nullable":true},"cli":{"type":"string","nullable":true},"status":{"type":"string","nullable":true},"sipCode":{"type":"integer","nullable":true},"hangupCause":{"type":"string","nullable":true},"durationSeconds":{"type":"integer","nullable":true},"billedSeconds":{"type":"integer","nullable":true},"segments":{"type":"integer","nullable":true,"description":"SMS segments"},"pddMs":{"type":"integer","nullable":true},"buyerCost":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"What you were charged for this record"},"sellerCredit":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"Seller earnings. Null unless you are the seller on this record"},"ratePerUnit":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"US dollars as a decimal string with exactly 6 decimal places, e.g. \"0.012500\". Do money arithmetic with a decimal type, not floating point."},"answeredAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"endedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"why":{"type":"object","properties":{"key":{"type":"string","description":"Stable reason key, for grouping"},"who":{"type":"string","enum":["you","route","destination","platform","unknown"],"description":"Whose move it is to unblock the call"},"title":{"type":"string"},"explanation":{"type":"string"},"fix":{"type":"object","properties":{"label":{"type":"string"},"href":{"type":"string"}},"required":["label","href"]},"evidence":{"type":"string","description":"The signalling fact behind the answer, e.g. \"SIP 503 Service Unavailable\""}},"required":["key","who","title","explanation"],"nullable":true,"description":"Why this call failed, in plain English. Null unless it is a failed call."},"rating":{"type":"object","properties":{"rate":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"US dollars as a decimal string with exactly 6 decimal places, e.g. \"0.012500\". Do money arithmetic with a decimal type, not floating point."},"unit":{"type":"string","enum":["minute","segment"]},"increment":{"type":"string","nullable":true},"billedSeconds":{"type":"integer","nullable":true},"rateLine":{"type":"string","nullable":true,"description":"The rate line the number matched"},"listingPrice":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"The listing headline price, only when it differs from the billed rate"},"note":{"type":"string","nullable":true}},"required":["rate","unit","increment","billedSeconds","rateLine","listingPrice","note"]},"route":{"type":"object","properties":{"label":{"type":"string","description":"Public listing name with its Ref"},"ref":{"type":"string"},"own":{"type":"boolean"},"loopRisk":{"type":"boolean"}},"required":["label","ref","own","loopRisk"],"nullable":true}},"required":["id","callUuid","callGroupId","direction","kind","routeId","fromNumber","toNumber","cli","status","sipCode","hangupCause","durationSeconds","billedSeconds","segments","pddMs","buyerCost","sellerCredit","ratePerUnit","answeredAt","endedAt","createdAt"],"additionalProperties":true,"description":"Supplier-side identity and network fields are nulled unless you are the seller on the record."},"BillingExportJob":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"type":{"type":"string","enum":["cdr"]},"params":{"type":"object","properties":{"from":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"to":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"kind":{"type":"string","enum":["voice","sms"]},"direction":{"type":"string","enum":["outbound","inbound"]}}},"status":{"type":"string","enum":["pending","running","done","failed"]},"rowCount":{"type":"integer","nullable":true},"error":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"completedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"downloadable":{"type":"boolean","description":"True once the job is done and its file is on record"},"downloadUrl":{"type":"string","nullable":true,"description":"The download endpoint for this job once it is done (GET /billing/exports/{id}/download). The only way to the file: no server path is ever returned."}},"required":["id","type","params","status","rowCount","error","createdAt","completedAt","downloadable","downloadUrl"],"additionalProperties":true},"BillingDocument":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"number":{"type":"integer","description":"Sequential document number; printed as INV-000123"},"type":{"type":"string","enum":["topup_receipt","statement"]},"amount":{"$ref":"#/components/schemas/Money"},"currency":{"type":"string"},"periodStart":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"periodEnd":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","number","type","amount","currency","periodStart","periodEnd","createdAt"],"additionalProperties":true},"TaxInvoiceSummary":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"seq":{"type":"integer","description":"Gap-free per-account sequence"},"number":{"type":"string"},"period":{"type":"string","description":"YYYY-MM"},"periodStart":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"periodEnd":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"currency":{"type":"string"},"subtotal":{"type":"string","description":"Decimal string"},"taxAmount":{"type":"string","description":"Decimal string"},"total":{"type":"string","description":"Decimal string"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","seq","number","period","periodStart","periodEnd","currency","subtotal","taxAmount","total","createdAt"]},"TaxInvoice":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"seq":{"type":"integer","description":"Gap-free per-account sequence"},"number":{"type":"string"},"period":{"type":"string","description":"YYYY-MM"},"periodStart":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"periodEnd":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"currency":{"type":"string"},"subtotal":{"type":"string","description":"Decimal string"},"taxAmount":{"type":"string","description":"Decimal string"},"total":{"type":"string","description":"Decimal string"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"dataJson":{"type":"object","additionalProperties":{},"nullable":true,"description":"Frozen line items and the tax section as issued"}},"required":["id","seq","number","period","periodStart","periodEnd","currency","subtotal","taxAmount","total","createdAt","dataJson"]},"Topup":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"method":{"type":"string","enum":["crypto","wire","stripe","x402"],"description":"stripe = card"},"amountUsd":{"$ref":"#/components/schemas/Money"},"status":{"type":"string","enum":["pending","confirmed","rejected"]},"cryptoToken":{"type":"string","nullable":true},"cryptoNetwork":{"type":"string","nullable":true},"cryptoTxHash":{"type":"string","nullable":true},"wireReference":{"type":"string","nullable":true},"depositAddress":{"type":"string","nullable":true},"depositMemo":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"confirmedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true}},"required":["id","method","amountUsd","status","cryptoToken","cryptoNetwork","cryptoTxHash","wireReference","depositAddress","depositMemo","createdAt","confirmedAt"],"additionalProperties":true},"AutoRecharge":{"type":"object","properties":{"enabled":{"type":"boolean"},"threshold":{"type":"string","nullable":true,"description":"USD, 2-decimal string: recharge when the balance falls below this"},"amount":{"type":"string","nullable":true,"description":"USD, 2-decimal string: how much each recharge adds"},"dailyCap":{"type":"string","nullable":true,"description":"USD, 2-decimal string: most that auto-recharge may charge per UTC day"},"hasDefaultCard":{"type":"boolean"}},"required":["enabled","threshold","amount","dailyCap","hasDefaultCard"]},"DialerCampaign":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"routeId":{"type":"string","format":"uuid","nullable":true,"description":"The purchased route the campaign sends over"},"name":{"type":"string"},"kind":{"type":"string","enum":["voice","sms"]},"environment":{"type":"string","enum":["live","test"],"description":"test = created with a test key; simulated, never really dialled or billed"},"status":{"type":"string","enum":["draft","ready","running","paused","completed","failed"]},"messageBody":{"type":"string","nullable":true,"description":"SMS campaigns: the message text"},"senderId":{"type":"string","nullable":true,"description":"SMS campaigns: the sender ID"},"aiAgentId":{"type":"string","format":"uuid","nullable":true,"description":"Voice campaigns: the AI voice agent that handles answered calls"},"concurrency":{"type":"integer"},"maxCallDuration":{"type":"integer","description":"Seconds"},"callInterval":{"type":"integer"},"platformFeePerCall":{"$ref":"#/components/schemas/Money"},"totalNumbers":{"type":"integer"},"totalClis":{"type":"integer"},"cliSetId":{"type":"string","format":"uuid","nullable":true},"cliStrategy":{"type":"object","additionalProperties":{},"nullable":true,"description":"Caller-ID rotation strategy, when a caller-ID set is assigned"},"numbersDialed":{"type":"integer"},"numbersAnswered":{"type":"integer"},"numbersFailed":{"type":"integer"},"totalDurationSeconds":{"type":"integer"},"windowStartHour":{"type":"integer","nullable":true},"windowEndHour":{"type":"integer","nullable":true},"windowTz":{"type":"string","nullable":true},"maxAttempts":{"type":"integer"},"retryDelayMinutes":{"type":"integer"},"maxSpend":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"Budget cap; the campaign pauses when reached"},"scheduleAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"startedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"completedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","userId","routeId","name","kind","environment","status","messageBody","senderId","aiAgentId","concurrency","maxCallDuration","callInterval","platformFeePerCall","totalNumbers","totalClis","cliSetId","cliStrategy","numbersDialed","numbersAnswered","numbersFailed","totalDurationSeconds","windowStartHour","windowEndHour","windowTz","maxAttempts","retryDelayMinutes","maxSpend","scheduleAt","startedAt","completedAt","createdAt","updatedAt"]},"DialerCampaignStats":{"type":"object","properties":{"totalNumbers":{"type":"integer"},"numbersDialed":{"type":"integer"},"numbersAnswered":{"type":"integer"},"numbersFailed":{"type":"integer"},"numbersPending":{"type":"integer"},"totalDurationSeconds":{"type":"integer"},"asr":{"type":"number","description":"Answer-seizure ratio, percent"},"acd":{"type":"number","description":"Average call duration, seconds"},"progress":{"type":"number","description":"Percent of numbers dialled"},"activeCalls":{"type":"integer"},"totalSpend":{"type":"number","description":"USD spent so far (a display number, not a 6-decimal string)"},"maxSpend":{"type":"number","nullable":true,"description":"Budget cap in USD, as a number"},"budgetProgress":{"type":"number","nullable":true,"description":"Percent of the budget used"}},"required":["totalNumbers","numbersDialed","numbersAnswered","numbersFailed","numbersPending","totalDurationSeconds","asr","acd","progress","activeCalls","totalSpend","maxSpend","budgetProgress"]},"DialerNumber":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"campaignId":{"type":"string","format":"uuid"},"number":{"type":"string"},"status":{"type":"string","enum":["pending","dialing","answered","no_answer","busy","failed","skipped"]},"sipResponseCode":{"type":"integer","nullable":true},"durationSeconds":{"type":"integer","nullable":true},"attempt":{"type":"integer"},"nextAttemptAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"dialedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"answeredAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"completedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"cost":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"Cost of the latest call to this number, when there is one"},"cli":{"type":"string","nullable":true,"description":"Caller ID presented on the latest call"},"sipCause":{"type":"string","nullable":true}},"required":["id","campaignId","number","status","sipResponseCode","durationSeconds","attempt","nextAttemptAt","dialedAt","answeredAt","completedAt","createdAt","cost","cli","sipCause"]},"DialerNumbersUploadResult":{"type":"object","properties":{"count":{"type":"integer","description":"Same as `inserted` (kept for existing clients)"},"inserted":{"type":"integer"},"skipped":{"type":"integer"},"rejects":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"reason":{"type":"string"}},"required":["value","reason"]},"description":"Up to 200 rejected entries with the reason"},"totalNumbers":{"type":"integer"},"campaign":{"$ref":"#/components/schemas/DialerCampaign"}},"required":["count","inserted","skipped","rejects","totalNumbers","campaign"]},"DialerCampaignCli":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"campaignId":{"type":"string","format":"uuid"},"cli":{"type":"string"},"status":{"type":"string","enum":["pending","verified","failed"]},"verified":{"type":"boolean"},"verifiedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","campaignId","cli","status","verified","verifiedAt","createdAt"]},"DialerContactMapping":{"type":"object","properties":{"headerRowIndex":{"type":"integer","description":"0-based header row, or -1 when the file has none"},"columns":{"type":"object","properties":{"phone":{"type":"integer"},"name":{"type":"integer","nullable":true},"firstName":{"type":"integer","nullable":true},"lastName":{"type":"integer","nullable":true}},"required":["phone","name","firstName","lastName"]},"extraColumns":{"type":"array","items":{"type":"integer"},"description":"Columns kept as per-contact fields"},"notes":{"type":"string"}},"required":["headerRowIndex","columns","extraColumns"]},"DialerCallerIdSet":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","userId","name","description","createdAt","updatedAt"]},"DialerCallerIdNumber":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"setId":{"type":"string","format":"uuid"},"cli":{"type":"string"},"label":{"type":"string","nullable":true},"country":{"type":"string","nullable":true},"countryCode":{"type":"string","nullable":true},"areaCode":{"type":"string","nullable":true},"source":{"type":"string","enum":["upload","paste","manual","revshare","did"]},"enabled":{"type":"boolean"},"weight":{"type":"integer"},"dailyCap":{"type":"integer","nullable":true},"campaignCap":{"type":"integer","nullable":true},"hourlyCap":{"type":"integer","nullable":true},"cooldownSec":{"type":"integer","nullable":true},"status":{"type":"string","enum":["active","resting","retired"]},"tags":{"type":"array","items":{"type":"string"}},"notes":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","setId","cli","label","country","countryCode","areaCode","source","enabled","weight","dailyCap","campaignCap","hourlyCap","cooldownSec","status","tags","notes","createdAt"]},"DialerCallerIdAddResult":{"type":"object","properties":{"inserted":{"type":"integer"},"skipped":{"type":"integer"},"rejects":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"reason":{"type":"string"}},"required":["value","reason"]}}},"required":["inserted","skipped","rejects"]},"DialerRevshareCaller":{"type":"object","properties":{"prefix":{"type":"string","description":"The MASKED leading digits of the caller; full numbers are never stored"},"fromCarrier":{"type":"string","nullable":true},"originIso":{"type":"string","nullable":true},"originCountry":{"type":"string","nullable":true},"originDialCode":{"type":"string","nullable":true},"callCount":{"type":"integer"},"lastCallAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"dialable":{"type":"boolean","description":"False for masked prefixes, which is currently always the case"}},"required":["prefix","fromCarrier","originIso","originCountry","originDialCode","callCount","lastCallAt","dialable"]},"DialerContactList":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"name":{"type":"string"},"count":{"type":"integer"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","userId","name","count","createdAt"]},"DialerCompatibleTargets":{"type":"object","properties":{"setId":{"type":"string","format":"uuid"},"setName":{"type":"string"},"groups":{"type":"array","items":{"type":"object","properties":{"cli":{"type":"string"},"label":{"type":"string","nullable":true},"country":{"type":"string","nullable":true},"countryCode":{"type":"string","nullable":true},"targets":{"type":"array","items":{"$ref":"#/components/schemas/DialerRevshareCaller"}}},"required":["cli","label","country","countryCode","targets"]}},"saved":{"type":"object","properties":{"list":{"$ref":"#/components/schemas/DialerContactList"},"saved":{"type":"integer"},"skipped":{"type":"integer"}},"required":["list","saved","skipped"],"nullable":true,"description":"The saved contact list, when saveAsListName was given and there was something dialable to save"},"limitation":{"type":"string","nullable":true}},"required":["setId","setName","groups","saved","limitation"]},"DialerSmsTemplate":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"name":{"type":"string"},"body":{"type":"string"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","userId","name","body","createdAt"]},"DialerCliSet":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"name":{"type":"string"},"clis":{"type":"string","description":"The caller IDs, newline-separated"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","userId","name","clis","createdAt"]},"DialerContactParseResult":{"type":"object","properties":{"hasHeader":{"type":"boolean"},"columns":{"type":"array","items":{"type":"object","properties":{"index":{"type":"integer"},"label":{"type":"string"}},"required":["index","label"]}},"sampleRows":{"type":"array","items":{"type":"array","items":{"type":"string"}}},"dataRows":{"type":"array","items":{"type":"array","items":{"type":"string"}}},"suggestedMapping":{"$ref":"#/components/schemas/DialerContactMapping"},"rowCount":{"type":"integer"},"truncated":{"type":"boolean"}},"required":["hasHeader","columns","sampleRows","dataRows","suggestedMapping","rowCount","truncated"]},"DncEntry":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid","nullable":true,"description":"null = a platform-wide entry (read-only to you)"},"phoneNumber":{"type":"string","description":"Digits only"},"reason":{"type":"string","nullable":true},"source":{"type":"string","enum":["manual","sms_stop","upload","callguard_optout"],"description":"How it was added"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","userId","phoneNumber","reason","source","createdAt"]},"AiAgent":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"name":{"type":"string"},"voiceId":{"type":"string","nullable":true},"voiceProvider":{"type":"string"},"language":{"type":"string"},"firstMessage":{"type":"string","nullable":true,"description":"What the agent says when the call is answered"},"systemPrompt":{"type":"string","description":"The script and instructions the agent follows"},"model":{"type":"string"},"guardrails":{"type":"string","nullable":true},"tools":{"type":"array","items":{"type":"string"}},"maxCallSeconds":{"type":"integer"},"enabled":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","userId","name","voiceId","voiceProvider","language","firstMessage","systemPrompt","model","guardrails","tools","maxCallSeconds","enabled","createdAt","updatedAt"]},"AiVoice":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"gender":{"type":"string"},"language":{"type":"string"},"is_pro":{"type":"boolean"}},"required":["id","name","description","gender","language","is_pro"]},"AiAgentDraft":{"type":"object","properties":{"name":{"type":"string"},"firstMessage":{"type":"string"},"systemPrompt":{"type":"string"},"guardrails":{"type":"string"},"suggestedTools":{"type":"array","items":{"type":"string"}}},"required":["name","firstMessage","systemPrompt","guardrails","suggestedTools"]},"AiAgentTurn":{"type":"object","properties":{"reply":{"type":"string","description":"What the agent would say"},"action":{"type":"string","enum":["continue","end","transfer"]},"captured":{"type":"object","additionalProperties":{"type":"string"},"description":"Structured details captured this turn (name, email, intent...)"}},"required":["reply","action"]},"SwitchCustomer":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"label":{"type":"string"},"source":{"type":"string","enum":["marketplace","external"]},"status":{"type":"string","enum":["draft","active","suspended","closed"]},"externalRef":{"type":"string","nullable":true},"balance":{"allOf":[{"$ref":"#/components/schemas/Money"}],"description":"Prepaid wallet balance (negative = owed), 6-decimal USD string"},"creditLimit":{"type":"string","description":"USD decimal string as stored (2 decimal places), e.g. \"5000.00\""},"currency":{"type":"string","nullable":true},"markupPct":{"type":"string","nullable":true,"description":"Default markup over cost, percent as a decimal string"},"billingIncrement":{"type":"string","nullable":true,"description":"e.g. \"60/60\" or \"6/6\""},"minMarginPct":{"type":"string","nullable":true},"marginFloorAction":{"type":"string","enum":["block","alert"],"nullable":true},"dailySpendCap":{"type":"string","nullable":true,"description":"USD decimal string as stored (2 decimal places), e.g. \"5000.00\""},"maxConcurrentCalls":{"type":"integer","nullable":true},"maxCps":{"type":"integer","nullable":true},"blockedPrefixes":{"type":"array","items":{"type":"string"},"nullable":true},"sipUsername":{"type":"string","nullable":true},"sipPasswordSet":{"type":"boolean","description":"Whether an inbound SIP password is set. The value itself is only ever returned by the audited credentials endpoint."},"portalEmail":{"type":"string","nullable":true},"taxCountry":{"type":"string","nullable":true},"taxId":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","label","source","status","externalRef","balance","creditLimit","currency","markupPct","billingIncrement","minMarginPct","marginFloorAction","dailySpendCap","maxConcurrentCalls","maxCps","blockedPrefixes","sipUsername","sipPasswordSet","portalEmail","taxCountry","taxId","createdAt","updatedAt"],"additionalProperties":true},"SwitchCustomerListRow":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"label":{"type":"string"},"source":{"type":"string","enum":["marketplace","external"]},"status":{"type":"string","enum":["draft","active","suspended","closed"]},"externalRef":{"type":"string","nullable":true},"balance":{"$ref":"#/components/schemas/Money"},"creditLimit":{"type":"string","description":"USD decimal string as stored (2 decimal places), e.g. \"5000.00\""},"currency":{"type":"string","nullable":true},"sipUsername":{"type":"string","nullable":true},"portalEmail":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"trunkCount":{"type":"integer","description":"Trunks excluding archived ones"},"trunksUp":{"type":"integer"},"trunksDown":{"type":"integer"},"liveCalls":{"type":"integer"},"calls24h":{"type":"integer"},"answered24h":{"type":"integer"},"asr24h":{"type":"number","nullable":true,"description":"Percent; null when no calls ran (not 0)"},"revenue24h":{"type":"number","description":"US dollars as a JSON number (computed figure)"},"margin24h":{"type":"number","description":"US dollars as a JSON number (computed figure)"},"marginPct24h":{"type":"number","nullable":true},"pddMs24h":{"type":"number","nullable":true},"creditUsedPct":{"type":"number","nullable":true},"contact":{"type":"object","properties":{"name":{"type":"string"},"email":{"type":"string","nullable":true},"phone":{"type":"string","nullable":true}},"required":["name","email","phone"],"nullable":true},"attention":{"type":"object","properties":{"highest":{"type":"string","nullable":true},"open":{"type":"integer"},"unacknowledged":{"type":"integer"},"refs":{"type":"array","items":{"type":"string"}}},"required":["highest","open","unacknowledged","refs"],"additionalProperties":true,"nullable":true,"description":"Open operational issues. Null means the check could not run, not that nothing is wrong."},"setup":{"type":"object","properties":{"trunks":{"type":"integer"},"enabled":{"type":"integer"},"identified":{"type":"integer"},"routed":{"type":"integer"},"unrouted":{"type":"integer"}},"required":["trunks","enabled","identified","routed","unrouted"]},"refused24h":{"type":"object","properties":{"forbidden":{"type":"integer"},"capacity":{"type":"integer"}},"required":["forbidden","capacity"]},"flags":{"type":"array","items":{"type":"string"},"description":"Filterable problem and state flags, e.g. \"problem:no_traffic\""}},"required":["id","label","source","status","externalRef","balance","creditLimit","currency","sipUsername","portalEmail","createdAt","trunkCount","trunksUp","trunksDown","liveCalls","calls24h","answered24h","asr24h","revenue24h","margin24h","marginPct24h","pddMs24h","creditUsedPct","contact","attention","setup","refused24h","flags"],"additionalProperties":true},"SwitchCustomerCreated":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"label":{"type":"string"},"source":{"type":"string","enum":["marketplace","external"]},"status":{"type":"string","enum":["draft","active","suspended","closed"]},"externalRef":{"type":"string","nullable":true},"balance":{"allOf":[{"$ref":"#/components/schemas/Money"}],"description":"Prepaid wallet balance (negative = owed), 6-decimal USD string"},"creditLimit":{"type":"string","description":"USD decimal string as stored (2 decimal places), e.g. \"5000.00\""},"currency":{"type":"string","nullable":true},"markupPct":{"type":"string","nullable":true,"description":"Default markup over cost, percent as a decimal string"},"billingIncrement":{"type":"string","nullable":true,"description":"e.g. \"60/60\" or \"6/6\""},"minMarginPct":{"type":"string","nullable":true},"marginFloorAction":{"type":"string","enum":["block","alert"],"nullable":true},"dailySpendCap":{"type":"string","nullable":true,"description":"USD decimal string as stored (2 decimal places), e.g. \"5000.00\""},"maxConcurrentCalls":{"type":"integer","nullable":true},"maxCps":{"type":"integer","nullable":true},"blockedPrefixes":{"type":"array","items":{"type":"string"},"nullable":true},"sipUsername":{"type":"string","nullable":true},"portalEmail":{"type":"string","nullable":true},"taxCountry":{"type":"string","nullable":true},"taxId":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"sipPassword":{"type":"string","description":"The inbound SIP password in plain text. Returned ONCE, here."},"defaultTrunkId":{"type":"string","format":"uuid","description":"The \"Default\" trunk created with every customer"},"apiKey":{"type":"string","description":"The customer's first API key. Returned ONCE, here."},"apiKeyPrefix":{"type":"string"}},"required":["id","label","source","status","externalRef","balance","creditLimit","currency","markupPct","billingIncrement","minMarginPct","marginFloorAction","dailySpendCap","maxConcurrentCalls","maxCps","blockedPrefixes","sipUsername","portalEmail","taxCountry","taxId","createdAt","updatedAt","sipPassword","defaultTrunkId","apiKey","apiKeyPrefix"],"additionalProperties":true},"SwitchCustomerSipCredentials":{"type":"object","properties":{"sipUsername":{"type":"string","nullable":true},"sipPassword":{"type":"string","nullable":true}},"required":["sipUsername","sipPassword"]},"SwitchCustomerLifecycleEntry":{"type":"object","properties":{"id":{"type":"string"},"at":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"action":{"type":"string"},"from":{"type":"string","nullable":true},"to":{"type":"string","nullable":true},"reason":{"type":"string","nullable":true},"actor":{"type":"string","nullable":true,"description":"Email of whoever did it"},"detail":{"type":"object","additionalProperties":{}}},"required":["id","at","action","from","to","reason","actor","detail"]},"SwitchCustomerLifecycle":{"type":"object","properties":{"customer":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"label":{"type":"string"},"status":{"type":"string","enum":["draft","active","suspended","closed"]},"source":{"type":"string"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","label","status","source","createdAt"]},"available":{"type":"array","items":{"type":"string","enum":["activate","suspend","reactivate","close","reopen"]},"description":"Actions allowed from the current state"},"liveCalls":{"type":"integer"},"trunks":{"type":"object","properties":{"total":{"type":"integer"},"active":{"type":"integer"}},"required":["total","active"]},"history":{"type":"array","items":{"$ref":"#/components/schemas/SwitchCustomerLifecycleEntry"}},"financials":{"type":"object","properties":{"currency":{"type":"string"},"prepaidBalance":{"type":"number","description":"US dollars as a JSON number (computed figure)"},"invoicesOutstanding":{"type":"number","description":"US dollars as a JSON number (computed figure)"},"invoicesOverdue":{"type":"number","description":"US dollars as a JSON number (computed figure)"},"creditNotesOpen":{"type":"number","description":"US dollars as a JSON number (computed figure)"},"unbilledUsage":{"type":"number","description":"US dollars as a JSON number (computed figure)"},"creditLimit":{"type":"number","description":"US dollars as a JSON number (computed figure)"},"openInvoiceCount":{"type":"integer"},"paidInvoiceCount":{"type":"integer"},"paymentCount":{"type":"integer"},"hasOpenPosition":{"type":"boolean"}},"required":["currency","prepaidBalance","invoicesOutstanding","invoicesOverdue","creditNotesOpen","unbilledUsage","creditLimit","openInvoiceCount","paidInvoiceCount","paymentCount","hasOpenPosition"]},"canDelete":{"type":"boolean"},"deleteBlockers":{"type":"array","items":{"type":"string"}}},"required":["customer","available","liveCalls","trunks","history","financials","canDelete","deleteBlockers"]},"SwitchCustomerOverview":{"type":"object","properties":{"customer":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"label":{"type":"string"},"status":{"type":"string","enum":["draft","active","suspended","closed"]},"source":{"type":"string"}},"required":["id","label","status","source"],"additionalProperties":true},"kpis":{"type":"object","additionalProperties":{},"description":"Balance owed, wallet, credit used and today's traffic figures (numbers)"},"commercial":{"type":"object","additionalProperties":{}},"activity":{"type":"array","items":{"type":"object","additionalProperties":{}}},"topDestinationsToday":{"type":"array","items":{"type":"object","additionalProperties":{}}},"health":{},"setup":{},"reconciliation":{},"freshness":{}},"required":["customer","kpis","commercial","activity","topDestinationsToday"],"additionalProperties":true},"SwitchCustomerQuality":{"type":"object","properties":{"windowHours":{"type":"number"},"window":{"type":"object","properties":{"from":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"to":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"label":{"type":"string"}},"required":["from","to","label"]},"destinationDigits":{"type":"integer"},"kpis":{"type":"object","properties":{"calls":{"type":"integer"},"answered":{"type":"integer"},"asr":{"type":"number","nullable":true},"ner":{"type":"number","nullable":true}},"required":["calls","answered","asr","ner"],"additionalProperties":true},"destinations":{"type":"array","items":{"type":"object","properties":{"prefix":{"type":"string"},"calls":{"type":"integer"},"answered":{"type":"integer"},"asr":{"type":"number","nullable":true},"ner":{"type":"number","nullable":true},"health":{"type":"string"}},"required":["prefix","calls","answered","asr","ner","health"],"additionalProperties":true}},"thresholds":{},"minJudgeableSessions":{"type":"integer"},"supports":{"type":"array","items":{"type":"string"},"description":"Call Records filter ids this view honours"},"unsupported":{"type":"array","items":{},"description":"Filters you sent that this view could not apply"}},"required":["windowHours","window","destinationDigits","kpis","destinations","minJudgeableSessions","supports","unsupported"],"additionalProperties":true},"SwitchCustomerContact":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"subAccountId":{"type":"string","format":"uuid"},"name":{"type":"string"},"role":{"type":"string","enum":["technical","noc","billing","escalation","commercial"]},"email":{"type":"string","nullable":true},"phone":{"type":"string","nullable":true},"priority":{"type":"integer","description":"1 = try first within this role"},"isPrimary":{"type":"boolean"},"preferredMethod":{"type":"string","enum":["email","phone","either"]},"availability":{"type":"string","enum":["24x7","business_hours","on_call"],"nullable":true},"timezone":{"type":"string","nullable":true},"notes":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","subAccountId","name","role","email","phone","priority","isPrimary","preferredMethod","availability","timezone","notes","createdAt","updatedAt"],"additionalProperties":true},"SwitchCustomerNote":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"subAccountId":{"type":"string","format":"uuid"},"body":{"type":"string"},"type":{"type":"string","enum":["general","technical","billing","warning"]},"pinned":{"type":"boolean"},"followUpAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"createdBy":{"type":"string","format":"uuid","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","subAccountId","body","type","pinned","followUpAt","createdBy","createdAt","updatedAt"],"additionalProperties":true},"SwitchCustomerAttentionItem":{"type":"object","properties":{"kind":{"type":"string","enum":["quality","commercial","credit","config","setup"]},"title":{"type":"string"},"detail":{"type":"string"},"at":{"type":"string"},"actionable":{"type":"boolean"}},"required":["kind","title","detail","at","actionable"],"additionalProperties":true},"SwitchCustomerIssue":{"type":"object","properties":{"ref":{"type":"string","description":"Issue reference, e.g. OPS-1042"},"detector":{"type":"string"},"severity":{"type":"string"},"status":{"type":"string"},"title":{"type":"string"},"summary":{"type":"string"},"trigger":{"type":"string"},"recovery":{"type":"string"},"sampleSize":{"type":"number"},"evidence":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string"},"value":{"type":"string"}},"required":["label","value"]}},"firstDetectedAt":{"type":"string"},"lastDetectedAt":{"type":"string"},"acknowledgedAt":{"type":"string","nullable":true},"resolvedAt":{"type":"string","nullable":true}},"required":["ref","detector","severity","status","title","summary","trigger","recovery","sampleSize","evidence","firstDetectedAt","lastDetectedAt","acknowledgedAt","resolvedAt"],"additionalProperties":true},"SwitchCustomerBillingSummary":{"type":"object","properties":{"balanceOwed":{"type":"number","description":"Open invoices less open credit notes"},"grossBalanceOwed":{"type":"number","description":"US dollars as a JSON number (computed figure)"},"creditNotesOpen":{"type":"number","description":"US dollars as a JSON number (computed figure)"},"paymentsRecorded":{"type":"number","description":"US dollars as a JSON number (computed figure)"},"creditLimit":{"type":"number","description":"US dollars as a JSON number (computed figure)"},"unbilledRated":{"type":"number","description":"US dollars as a JSON number (computed figure)"},"unbilledSinceLastInvoice":{"type":"number","description":"US dollars as a JSON number (computed figure)"},"unratedUsage":{"type":"object","properties":{"calls":{"type":"integer"},"minutes":{"type":"number","nullable":true},"note":{"type":"string"}},"required":["calls","minutes","note"]},"overdueIsSubsetOfOpenInvoices":{"type":"boolean","enum":[true]},"disputed":{"enum":["null"],"nullable":true,"description":"Customer-side disputes are not recorded, so always null"},"avgDaysToPay":{"type":"number","nullable":true},"lastInvoicePeriodEnd":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"currency":{"type":"string"},"aging":{"type":"object","properties":{"current":{"type":"number","description":"US dollars as a JSON number (computed figure)"},"d1_30":{"type":"number","description":"US dollars as a JSON number (computed figure)"},"d31_60":{"type":"number","description":"US dollars as a JSON number (computed figure)"},"d61_90":{"type":"number","description":"US dollars as a JSON number (computed figure)"},"d90_plus":{"type":"number","description":"US dollars as a JSON number (computed figure)"}},"required":["current","d1_30","d31_60","d61_90","d90_plus"]}},"required":["balanceOwed","grossBalanceOwed","creditNotesOpen","paymentsRecorded","creditLimit","unbilledRated","unbilledSinceLastInvoice","unratedUsage","overdueIsSubsetOfOpenInvoices","disputed","avgDaysToPay","lastInvoicePeriodEnd","currency","aging"],"additionalProperties":true},"SwitchCustomerCreditPosition":{"type":"object","properties":{"customerId":{"type":"string","format":"uuid"},"label":{"type":"string"},"currency":{"type":"string"},"mode":{"type":"string","description":"prepaid or postpaid, derived from the credit limit"},"creditLimit":{"type":"object","properties":{"value":{"type":"number","description":"US dollars as a JSON number (computed figure)"},"ambiguous":{"type":"string","nullable":true}},"required":["value","ambiguous"]},"exposure":{"type":"number","description":"US dollars as a JSON number (computed figure)"},"balance":{"type":"number","description":"US dollars as a JSON number (computed figure)"},"reservations":{"type":"object","properties":{"amount":{"type":"number","description":"US dollars as a JSON number (computed figure)"},"calls":{"type":"integer"},"enforced":{"type":"boolean"},"basis":{"type":"string"}},"required":["amount","calls","enforced","basis"]},"availableCredit":{"type":"number","description":"US dollars as a JSON number (computed figure)"},"availableAfterReservations":{"type":"number","description":"US dollars as a JSON number (computed figure)"},"admitsNextCall":{"type":"boolean"},"usedPct":{"type":"number","nullable":true},"overCommitted":{"type":"boolean"}},"required":["customerId","label","currency","mode","creditLimit","exposure","balance","reservations","availableCredit","availableAfterReservations","admitsNextCall","usedPct","overCommitted"],"additionalProperties":true},"SwitchCustomerPayment":{"type":"object","properties":{"kind":{"type":"string","enum":["payment"]},"transactionId":{"type":"string","format":"uuid"},"amount":{"type":"number","description":"US dollars as a JSON number (computed figure)"},"currency":{"type":"string"},"postedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"externalReference":{"type":"string","nullable":true},"method":{"type":"string","nullable":true},"operatorLabel":{"type":"string","nullable":true},"billingMode":{"type":"string"},"allocations":{"type":"array","items":{"type":"object","properties":{"invoiceId":{"type":"string","format":"uuid"},"invoiceNumber":{"type":"string"},"applied":{"type":"number","description":"US dollars as a JSON number (computed figure)"},"outstandingAfter":{"type":"number","description":"US dollars as a JSON number (computed figure)"},"status":{"type":"string"}},"required":["invoiceId","invoiceNumber","applied","outstandingAfter","status"],"additionalProperties":true},"description":"Oldest-due invoices first"},"unapplied":{"type":"number","description":"Left on account after paying every open invoice"},"positionAfter":{"type":"object","additionalProperties":{}}},"required":["kind","transactionId","amount","currency","postedAt","externalReference","method","operatorLabel","billingMode","allocations","unapplied","positionAfter"]},"SwitchCustomerInvoicePreview":{"type":"object","properties":{"customer":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"label":{"type":"string"},"legalName":{"type":"string"},"currency":{"type":"string"}},"required":["id","label","legalName","currency"]},"period":{"type":"object","additionalProperties":{}},"dueDate":{"type":"string"},"paymentTermsDays":{"type":"integer"},"currency":{"type":"string"},"usage":{"type":"object","additionalProperties":{}},"unrated":{"type":"object","additionalProperties":{},"description":"Usage that has no price yet; blocks issue unless excluded"},"reviewToken":{"type":"string","description":"Pass to generate-invoice to issue exactly what was reviewed"},"reviewDigest":{"type":"string"}},"required":["customer","period","dueDate","paymentTermsDays","currency","usage","unrated","reviewToken","reviewDigest"],"additionalProperties":true},"SwitchCustomerIssuedInvoice":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"invoiceNumber":{"type":"string"},"customerId":{"type":"string","format":"uuid"},"status":{"type":"string"},"subtotal":{"$ref":"#/components/schemas/Money"},"total":{"$ref":"#/components/schemas/Money"},"currency":{"type":"string"},"periodStart":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"periodEnd":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"issueDate":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"dueDate":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"lines":{"type":"array","items":{"type":"object","additionalProperties":{}}},"reviewDigest":{"type":"string","nullable":true}},"required":["id","invoiceNumber","customerId","status","subtotal","total","currency","periodStart","periodEnd","issueDate","dueDate","lines","reviewDigest"],"additionalProperties":true},"SwitchCustomerBillingProfile":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"legalName":{"type":"string"},"version":{"type":"integer","description":"Bumped on every save; frozen onto invoices issued afterwards"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","legalName","version","updatedAt"],"additionalProperties":true},"SwitchCustomerSellDeckRef":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"version":{"type":"integer"},"status":{"type":"string"},"currency":{"type":"string"},"isSystemDefault":{"type":"boolean"},"defaultRatePerUnit":{"type":"number","nullable":true,"description":"USD per minute for destinations the deck does not list; null = refuse them"},"charging":{"type":"object","additionalProperties":{}}},"required":["id","name","version","status","currency","isSystemDefault","defaultRatePerUnit","charging"],"additionalProperties":true},"SwitchTrunkEffectiveSellDeck":{"type":"object","properties":{"deck":{"allOf":[{"$ref":"#/components/schemas/SwitchCustomerSellDeckRef"}],"nullable":true},"mode":{"type":"string"},"choice":{"type":"string","description":"Which rule won: the trunk, the customer default or the system default"},"bypassesCustomerDefault":{"type":"boolean"},"customerDefault":{"allOf":[{"$ref":"#/components/schemas/SwitchCustomerSellDeckRef"}],"nullable":true},"systemDefault":{"allOf":[{"$ref":"#/components/schemas/SwitchCustomerSellDeckRef"}],"nullable":true},"liveRowCount":{"type":"integer"},"explanation":{"type":"string"},"problem":{"type":"string","nullable":true}},"required":["deck","mode","choice","bypassesCustomerDefault","customerDefault","systemDefault","liveRowCount","explanation","problem"]},"SwitchCustomerSellRate":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"subAccountId":{"type":"string","format":"uuid"},"customerTrunkId":{"type":"string","format":"uuid","nullable":true},"prefix":{"type":"string"},"originPrefix":{"type":"string","description":"\"\" = any origin"},"ratePerUnit":{"allOf":[{"$ref":"#/components/schemas/Money"}],"description":"Sell price per minute, 6-decimal USD string"},"billingIncrement":{"type":"string","nullable":true},"status":{"type":"string","description":"active, pending (scheduled) or discontinued"},"effectiveFrom":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"endDate":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true}},"required":["id","subAccountId","customerTrunkId","prefix","originPrefix","ratePerUnit","billingIncrement","status","effectiveFrom","endDate"],"additionalProperties":true},"SwitchCustomerSellRatePage":{"type":"object","properties":{"rows":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"subAccountId":{"type":"string","format":"uuid"},"customerTrunkId":{"type":"string","format":"uuid","nullable":true},"prefix":{"type":"string"},"originPrefix":{"type":"string","description":"\"\" = any origin"},"ratePerUnit":{"allOf":[{"$ref":"#/components/schemas/Money"}],"description":"Sell price per minute, 6-decimal USD string"},"billingIncrement":{"type":"string","nullable":true},"status":{"type":"string","description":"active, pending (scheduled) or discontinued"},"effectiveFrom":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"endDate":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"buyCost":{"type":"number","nullable":true,"description":"Best eligible buy cost per minute (USD number); null = no supplier prices it"},"marginPct":{"type":"number","nullable":true},"thin":{"type":"boolean"},"negative":{"type":"boolean"},"costSupplier":{"type":"string","nullable":true},"costSource":{"type":"string"},"costMatchedPrefix":{"type":"string","nullable":true},"costNote":{"type":"string","nullable":true}},"required":["id","subAccountId","customerTrunkId","prefix","originPrefix","ratePerUnit","billingIncrement","status","effectiveFrom","endDate","buyCost","marginPct","thin","negative","costSupplier","costSource","costMatchedPrefix","costNote"],"additionalProperties":true}},"total":{"type":"integer"},"totalIsPageScoped":{"type":"boolean","description":"True when a cost or margin filter narrowed the page, so `total` counts this page only"},"limit":{"type":"integer"},"offset":{"type":"integer"},"view":{"type":"string"},"summary":{"type":"object","properties":{"prefixes":{"type":"integer"},"blendedMarginPct":{"type":"number","nullable":true},"thinCount":{"type":"integer"},"negativeCount":{"type":"integer"},"defaultRateCostCount":{"type":"integer"},"unpricedCount":{"type":"integer"}},"required":["prefixes","blendedMarginPct","thinCount","negativeCount","defaultRateCostCount","unpricedCount"]},"basis":{}},"required":["rows","total","totalIsPageScoped","limit","offset","view","summary"]},"SwitchCustomerTrunk":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"subAccountId":{"type":"string","format":"uuid","description":"The customer this trunk belongs to"},"label":{"type":"string"},"status":{"type":"string","enum":["active","disabled","archived"]},"authMode":{"type":"string","enum":["ip","credentials","ip_and_credentials","registration","certificate"]},"sipUsername":{"type":"string","nullable":true},"sipPasswordSet":{"type":"boolean"},"maxConcurrentCalls":{"type":"integer","nullable":true,"description":"Null inherits the customer ceiling"},"maxCps":{"type":"integer","nullable":true},"markupPct":{"type":"string","nullable":true},"billingIncrement":{"type":"string","nullable":true},"techPrefix":{"type":"string","nullable":true},"mediaMode":{"type":"string","enum":["proxy","direct"]},"cliRewrite":{"type":"object","additionalProperties":{},"nullable":true},"allowedPrefixes":{"type":"array","items":{"type":"string"},"nullable":true},"allowedCountries":{"type":"array","items":{"type":"string"},"nullable":true},"blockedCountries":{"type":"array","items":{"type":"string"},"nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","subAccountId","label","status","sipUsername","sipPasswordSet","maxConcurrentCalls","maxCps","markupPct","billingIncrement","techPrefix","cliRewrite","allowedPrefixes","allowedCountries","blockedCountries","createdAt","updatedAt"],"additionalProperties":true},"SwitchCustomerTrunkListRow":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"subAccountId":{"type":"string","format":"uuid","description":"The customer this trunk belongs to"},"label":{"type":"string"},"status":{"type":"string","enum":["active","disabled","archived"]},"authMode":{"type":"string","enum":["ip","credentials","ip_and_credentials","registration","certificate"]},"sipUsername":{"type":"string","nullable":true},"sipPasswordSet":{"type":"boolean"},"maxConcurrentCalls":{"type":"integer","nullable":true,"description":"Null inherits the customer ceiling"},"maxCps":{"type":"integer","nullable":true},"markupPct":{"type":"string","nullable":true},"billingIncrement":{"type":"string","nullable":true},"techPrefix":{"type":"string","nullable":true},"mediaMode":{"type":"string","enum":["proxy","direct"]},"cliRewrite":{"type":"object","additionalProperties":{},"nullable":true},"allowedPrefixes":{"type":"array","items":{"type":"string"},"nullable":true},"allowedCountries":{"type":"array","items":{"type":"string"},"nullable":true},"blockedCountries":{"type":"array","items":{"type":"string"},"nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"authentication":{"type":"object","properties":{"mode":{"type":"string","enum":["ip","credentials","ip_and_credentials","registration","certificate"]},"title":{"type":"string"},"summary":{"type":"string"},"sends":{"type":"array","items":{"type":"string"}},"checks":{"type":"array","items":{"type":"string"}},"gaps":{"type":"array","items":{"type":"string"},"description":"Empty when the trunk is configured for its declared mode"},"enforced":{"type":"boolean"}},"required":["mode","title","summary","sends","checks","gaps","enforced"]},"identification":{"type":"object","properties":{"namedBy":{"type":"array","items":{"type":"string"}},"unique":{"type":"boolean"},"note":{"type":"string","nullable":true}},"required":["namedBy","unique","note"]},"allowedIps":{"type":"array","items":{"type":"string"}},"allowedAddresses":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"cidr":{"type":"string"}},"required":["id","cidr"]}},"routing":{"type":"object","additionalProperties":{},"nullable":true},"inherited":{"type":"object","properties":{"from":{"type":"string","enum":["customer"]},"maxConcurrentCalls":{"type":"integer","nullable":true},"maxCps":{"type":"integer","nullable":true},"billingIncrement":{"type":"string","nullable":true}},"required":["from","maxConcurrentCalls","maxCps","billingIncrement"]},"last24h":{"type":"object","properties":{"calls":{"type":"integer"},"minutes":{"type":"number"},"revenue":{"type":"number","description":"US dollars as a JSON number (computed figure)"}},"required":["calls","minutes","revenue"]},"period":{"description":"The window the traffic figures cover"},"traffic":{"type":"object","properties":{"calls":{"type":"integer"},"answered":{"type":"integer"},"minutes":{"type":"number"},"revenue":{"type":"number","description":"US dollars as a JSON number (computed figure)"},"margin":{"type":"number","description":"US dollars as a JSON number (computed figure)"},"asr":{"type":"number","nullable":true},"pddMs":{"type":"number","nullable":true}},"required":["calls","answered","minutes","revenue","margin","asr","pddMs"]},"refused":{"type":"object","properties":{"forbidden":{"type":"integer"},"capacity":{"type":"integer"},"capacityChannels":{"type":"integer"},"capacityCps":{"type":"integer"}},"required":["forbidden","capacity","capacityChannels","capacityCps"]}},"required":["id","subAccountId","label","status","sipUsername","sipPasswordSet","maxConcurrentCalls","maxCps","markupPct","billingIncrement","techPrefix","cliRewrite","allowedPrefixes","allowedCountries","blockedCountries","createdAt","updatedAt","authentication","identification","allowedIps","allowedAddresses","routing","inherited","last24h","traffic","refused"],"additionalProperties":true},"SwitchTrunkAddressPanel":{"type":"object","properties":{"trunkId":{"type":"string","format":"uuid"},"trunkLabel":{"type":"string"},"customerId":{"type":"string","format":"uuid"},"entries":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"cidr":{"type":"string"},"canonical":{"type":"string","nullable":true},"description":{"type":"string","nullable":true},"ambiguous":{"type":"boolean"}},"required":["id","cidr","canonical","description"],"additionalProperties":true}},"customerLevel":{"type":"array","items":{"type":"object","additionalProperties":{}},"description":"Addresses added on the customer, which apply to every trunk"},"ambiguousCount":{"type":"integer"},"activation":{"type":"object","properties":{"appliesTo":{"type":"string","enum":["new_requests"]},"affectsCallsInProgress":{"type":"boolean","enum":[false]},"note":{"type":"string"}},"required":["appliesTo","affectsCallsInProgress","note"]}},"required":["trunkId","trunkLabel","customerId","entries","customerLevel","ambiguousCount","activation"]},"SwitchCustomerRoutingAssignment":{"type":"object","properties":{"subAccountId":{"type":"string","format":"uuid"},"customerTrunkId":{"type":"string","format":"uuid","nullable":true},"dialplanId":{"type":"string","format":"uuid","nullable":true},"routePlanId":{"type":"string","format":"uuid","nullable":true},"failoverRoutePlanId":{"type":"string","format":"uuid","nullable":true},"strategyOverride":{"type":"string","nullable":true},"directRouteId":{"type":"string","format":"uuid","nullable":true},"directVendorTrunkId":{"type":"string","format":"uuid","nullable":true}},"required":["subAccountId","dialplanId","routePlanId","failoverRoutePlanId","strategyOverride","directRouteId","directVendorTrunkId"],"additionalProperties":true},"SwitchTrunkCredentialStatus":{"type":"object","properties":{"trunkId":{"type":"string","format":"uuid"},"trunkLabel":{"type":"string"},"customerId":{"type":"string","format":"uuid"},"customerLabel":{"type":"string","nullable":true},"username":{"type":"string","nullable":true},"passwordSet":{"type":"boolean"},"storage":{"type":"object","properties":{"sealed":{"type":"boolean"},"note":{"type":"string"}},"required":["sealed","note"]},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"lastChange":{},"lastReveal":{},"historyAvailable":{"type":"boolean"},"lastSuccessfulAuth":{"type":"object","properties":{"at":{"type":"string"},"sourceIp":{"type":"string","nullable":true},"sourceIsRegistered":{"type":"boolean"}},"required":["at","sourceIp","sourceIsRegistered"],"additionalProperties":true,"nullable":true}},"required":["trunkId","trunkLabel","customerId","customerLabel","username","passwordSet","storage","createdAt","historyAvailable","lastSuccessfulAuth"],"additionalProperties":true},"SwitchTrunkEffectiveConfig":{"type":"object","properties":{"trunk":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"label":{"type":"string"},"status":{"type":"string"},"customerId":{"type":"string","format":"uuid"},"customerLabel":{"type":"string"}},"required":["id","label","status","customerId","customerLabel"]},"sections":{"type":"array","items":{"type":"object","additionalProperties":{}},"description":"Each setting with the value in force and the level it came from"},"capacity":{"type":"object","properties":{"limits":{"type":"array","items":{"type":"object","additionalProperties":{}}},"refusals":{},"checkOrder":{"type":"array","items":{"type":"string"}},"note":{"type":"string"}},"required":["limits","checkOrder","note"]},"readOnly":{"type":"boolean","enum":[true]}},"required":["trunk","sections","capacity","readOnly"]},"SwitchCustomerRateNotice":{"type":"object","properties":{"rateNoticeDays":{"type":"integer","description":"Days of notice before a sell-rate increase takes effect; 0 = none"},"queued":{"type":"integer","description":"Sell-rate changes queued and not yet in effect"},"increases":{"type":"integer","description":"How many of the queued changes are increases"},"nextEffectiveFrom":{"type":"string","format":"date-time","description":"When the soonest queued change takes effect","nullable":true},"defaultRecipients":{"type":"array","items":{"type":"string"},"description":"Who a notice goes to when you do not name recipients"}},"required":["rateNoticeDays","queued","increases","nextEffectiveFrom","defaultRecipients"]},"SwitchCustomerRateChange":{"type":"object","properties":{"trunk":{"type":"string","description":"The customer trunk's label (\"\" when it has none)"},"prefix":{"type":"string"},"origin":{"type":"string","description":"Origin prefix for origin-based pricing; \"\" when the rate applies from any origin"},"currentRate":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"The rate in force today; null for a new destination"},"newRate":{"$ref":"#/components/schemas/Money"},"changePct":{"type":"number","nullable":true,"description":"Percentage move, 2 decimals; null for a new destination"},"currentIncrement":{"type":"string","nullable":true},"newIncrement":{"type":"string","nullable":true},"effectiveFrom":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["trunk","prefix","origin","currentRate","newRate","changePct","currentIncrement","newIncrement","effectiveFrom"]},"SwitchSupplierTrunk":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"supplierId":{"type":"string","format":"uuid","nullable":true,"description":"The owning provider; null = ungrouped"},"label":{"type":"string"},"source":{"type":"string","description":"\"external\" for a carrier you entered; \"marketplace\" for a trunk promoted from a marketplace purchase"},"status":{"type":"string","enum":["active","disabled","draft","testing","draining","fault"]},"sipHost":{"type":"string","nullable":true,"description":"Null on a marketplace trunk: the seller address is never disclosed"},"sipPort":{"type":"integer","nullable":true},"transport":{"type":"string","enum":["udp","tcp","tls"],"nullable":true},"techPrefix":{"type":"string","nullable":true},"sipAuthUsername":{"type":"string","nullable":true},"sipAuthPasswordSet":{"type":"boolean","description":"Whether a SIP password is stored. The value is only readable via GET /switch/suppliers/{id}/credentials"},"smppPasswordSet":{"type":"boolean"},"mediaMode":{"type":"string","enum":["proxy","direct"]},"defaultRatePerUnit":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"Cost per minute used when no deck row matches"},"billingIncrement":{"type":"string","nullable":true},"currency":{"type":"string","nullable":true},"capacity":{"type":"integer","nullable":true,"description":"Max concurrent channels"},"maxCps":{"type":"integer","nullable":true},"settlementMode":{"type":"string","enum":["ap","prepaid"]},"balance":{"allOf":[{"$ref":"#/components/schemas/Money"}],"description":"Prepaid credit remaining with this supplier (prepaid settlement)"},"smsDeliveryMethod":{"type":"string","enum":["http","smpp"],"nullable":true},"reachable":{"type":"boolean","nullable":true},"reachCheckedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","supplierId","label","source","status","sipHost","sipPort","transport","techPrefix","sipAuthUsername","sipAuthPasswordSet","smppPasswordSet","mediaMode","defaultRatePerUnit","billingIncrement","currency","capacity","maxCps","settlementMode","balance","smsDeliveryMethod","reachable","reachCheckedAt","createdAt","updatedAt"],"additionalProperties":true,"description":"A supplier (vendor) trunk. Carries every spec section-4 policy field accepted on create/update; secrets are replaced by *Set booleans."},"SwitchSupplierTrunkDetail":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"supplierId":{"type":"string","format":"uuid","nullable":true,"description":"The owning provider; null = ungrouped"},"label":{"type":"string"},"source":{"type":"string","description":"\"external\" for a carrier you entered; \"marketplace\" for a trunk promoted from a marketplace purchase"},"status":{"type":"string","enum":["active","disabled","draft","testing","draining","fault"]},"sipHost":{"type":"string","nullable":true,"description":"Null on a marketplace trunk: the seller address is never disclosed"},"sipPort":{"type":"integer","nullable":true},"transport":{"type":"string","enum":["udp","tcp","tls"],"nullable":true},"techPrefix":{"type":"string","nullable":true},"sipAuthUsername":{"type":"string","nullable":true},"sipAuthPasswordSet":{"type":"boolean","description":"Whether a SIP password is stored. The value is only readable via GET /switch/suppliers/{id}/credentials"},"smppPasswordSet":{"type":"boolean"},"mediaMode":{"type":"string","enum":["proxy","direct"]},"defaultRatePerUnit":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"Cost per minute used when no deck row matches"},"billingIncrement":{"type":"string","nullable":true},"currency":{"type":"string","nullable":true},"capacity":{"type":"integer","nullable":true,"description":"Max concurrent channels"},"maxCps":{"type":"integer","nullable":true},"settlementMode":{"type":"string","enum":["ap","prepaid"]},"balance":{"allOf":[{"$ref":"#/components/schemas/Money"}],"description":"Prepaid credit remaining with this supplier (prepaid settlement)"},"smsDeliveryMethod":{"type":"string","enum":["http","smpp"],"nullable":true},"reachable":{"type":"boolean","nullable":true},"reachCheckedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"ipAcls":{"type":"array","items":{"$ref":"#/components/schemas/SwitchIpAcl"}},"hairpin":{"type":"object","properties":{},"additionalProperties":true,"nullable":true,"description":"Warning when this address is also one of your own customers (loopback)"},"health":{"type":"object","properties":{},"additionalProperties":true,"description":"Derived health state (what routing believes), with its counters and thresholds"}},"required":["id","supplierId","label","source","status","sipHost","sipPort","transport","techPrefix","sipAuthUsername","sipAuthPasswordSet","smppPasswordSet","mediaMode","defaultRatePerUnit","billingIncrement","currency","capacity","maxCps","settlementMode","balance","smsDeliveryMethod","reachable","reachCheckedAt","createdAt","updatedAt","ipAcls","hairpin","health"],"additionalProperties":true,"description":"A supplier (vendor) trunk. Carries every spec section-4 policy field accepted on create/update; secrets are replaced by *Set booleans."},"SwitchTrunkEndpoint":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"vendorTrunkId":{"type":"string","format":"uuid"},"role":{"type":"string","enum":["primary","backup"]},"host":{"type":"string","nullable":true,"description":"Null on a marketplace trunk"},"port":{"type":"integer","nullable":true},"transport":{"type":"string","enum":["udp","tcp","tls"]},"priority":{"type":"integer"},"weightPct":{"type":"integer","nullable":true},"enabled":{"type":"boolean"},"optionsIntervalSeconds":{"type":"integer","nullable":true},"failureThreshold":{"type":"integer"},"recoveryThreshold":{"type":"integer"},"autoDisable":{"type":"boolean"},"reachable":{"type":"boolean","nullable":true},"reachLatencyMs":{"type":"integer","nullable":true},"reachCheckedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"healthDisabledAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"health":{"type":"object","properties":{},"additionalProperties":true,"description":"Derived health state (what routing believes), with its counters and thresholds"},"flap":{"type":"object","properties":{},"additionalProperties":true,"nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","vendorTrunkId","role","host","port","transport","priority","weightPct","enabled","optionsIntervalSeconds","failureThreshold","recoveryThreshold","autoDisable","reachable","reachLatencyMs","reachCheckedAt","healthDisabledAt","health","createdAt","updatedAt"],"additionalProperties":true},"SwitchSmsEndpointTest":{"type":"object","properties":{"pass":{"type":"boolean"},"via":{"type":"string","enum":["http","smpp"]},"checks":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string"},"value":{"type":"string"},"ok":{"type":"boolean"}},"required":["label","value","ok"]}},"message":{"type":"string"}},"required":["pass","via","checks","message"]},"SwitchTrunkRate":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"vendorTrunkId":{"type":"string","format":"uuid"},"prefix":{"type":"string"},"originPrefix":{"type":"string","description":"Caller-origin prefix; \"\" = any origin"},"ratePerUnit":{"allOf":[{"$ref":"#/components/schemas/Money"}],"description":"Cost per minute"},"destinationName":{"type":"string","nullable":true},"billingIncrement":{"type":"string","nullable":true,"description":"e.g. \"6/6\"; null inherits the trunk default"},"status":{"anyOf":[{"type":"string","enum":["active","pending","superseded","archived"]},{"type":"string"}]},"effectiveFrom":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true}},"required":["id","vendorTrunkId","prefix","originPrefix","ratePerUnit","destinationName","billingIncrement","status","effectiveFrom"],"additionalProperties":true},"SwitchTrunkChangeRequest":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"vendorTrunkId":{"type":"string","format":"uuid"},"trunkLabel":{"type":"string","nullable":true},"status":{"anyOf":[{"type":"string","enum":["pending","approved","rejected","withdrawn","applied"]},{"type":"string"}]},"fields":{"type":"array","items":{"type":"string"}},"changes":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"from":{},"to":{}},"required":["field"]},"description":"Secret fields show \"(secret)\", never their value"},"patch":{"type":"object","additionalProperties":{}},"beforeValues":{"type":"object","additionalProperties":{}},"note":{"type":"string","nullable":true},"requestedBy":{"type":"string","format":"uuid"},"requestedByEmail":{"type":"string","nullable":true},"requestedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"reviewedBy":{"type":"string","format":"uuid","nullable":true},"reviewedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"reviewNote":{"type":"string","nullable":true},"appliedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true}},"required":["id","vendorTrunkId","trunkLabel","status","fields","changes","patch","beforeValues","note","requestedBy","requestedByEmail","requestedAt","reviewedBy","reviewedAt","reviewNote","appliedAt"],"additionalProperties":true},"SwitchTrunkReadiness":{"type":"object","properties":{"trunkId":{"type":"string","format":"uuid"},"exempt":{"type":"boolean"},"exemptReason":{"type":"string","nullable":true},"state":{"type":"string","enum":["ready","not_ready","exempt"]},"checks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"spec":{"type":"string"},"title":{"type":"string"},"status":{"type":"string","description":"pass, warn or fail"},"evidence":{"type":"string"},"fix":{"type":"string","enum":["supplier","contacts","endpoints","configuration","cost_deck","diagnostics","settings","routing"]}},"required":["id","spec","title","status","evidence","fix"]}},"failing":{"type":"integer"},"warning":{"type":"integer"},"grandfathered":{"type":"boolean"},"blockingEnabled":{"type":"boolean"}},"required":["trunkId","exempt","exemptReason","state","checks","failing","warning","grandfathered","blockingEnabled"]},"SwitchTrunkConfigVersion":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"version":{"type":"integer"},"source":{"type":"string","description":"Which door the change came through, e.g. update, approval, api"},"changedFields":{"type":"array","items":{"type":"string"}},"diff":{"type":"object","additionalProperties":{"type":"object","properties":{"from":{},"to":{}}},"nullable":true},"note":{"type":"string","nullable":true},"checksum":{"type":"string","nullable":true},"changeRequestId":{"type":"string","format":"uuid","nullable":true},"actorUserId":{"type":"string","format":"uuid","nullable":true},"actorEmail":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","version","source","changedFields","diff","note","checksum","changeRequestId","actorUserId","createdAt"]},"SwitchIpAcl":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"entityType":{"type":"string","enum":["customer","trunk"]},"entityId":{"type":"string","format":"uuid"},"cidr":{"type":"string"},"description":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","entityType","entityId","cidr","description","createdAt"],"additionalProperties":true},"SwitchProvider":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"accountCode":{"type":"string","nullable":true},"legalName":{"type":"string","nullable":true},"tradingName":{"type":"string","nullable":true},"providerType":{"type":"string","enum":["carrier","aggregator","mno","mvno","sip_provider"],"nullable":true},"country":{"type":"string","nullable":true},"services":{"type":"array","items":{"type":"string"},"nullable":true},"portalEmail":{"type":"string","nullable":true},"currency":{"type":"string"},"status":{"type":"string","enum":["draft","pending_approval","testing","active","suspended","terminated"]},"statusNote":{"type":"string","nullable":true},"statusChangedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"routable":{"type":"boolean","description":"Whether this provider admits new calls at all, given its status"},"contractStart":{"type":"string","nullable":true,"description":"YYYY-MM-DD"},"contractEnd":{"type":"string","nullable":true},"autoRenew":{"type":"boolean"},"rateNoticeDays":{"type":"integer","nullable":true},"disputeDays":{"type":"integer","nullable":true},"billingMode":{"type":"string","enum":["prepaid","postpaid"]},"creditLimit":{"type":"string","nullable":true,"description":"Decimal string with 2 decimal places, e.g. \"5000.00\""},"balance":{"$ref":"#/components/schemas/Money"},"paymentTermsDays":{"type":"integer","nullable":true},"invoiceCycle":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","name","accountCode","legalName","tradingName","providerType","country","services","portalEmail","currency","status","statusNote","statusChangedAt","routable","contractStart","contractEnd","autoRenew","rateNoticeDays","disputeDays","billingMode","creditLimit","balance","paymentTermsDays","invoiceCycle","createdAt","updatedAt"],"additionalProperties":true},"SwitchProviderList":{"type":"object","properties":{"accounts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"accountCode":{"type":"string","nullable":true},"legalName":{"type":"string","nullable":true},"tradingName":{"type":"string","nullable":true},"providerType":{"type":"string","enum":["carrier","aggregator","mno","mvno","sip_provider"],"nullable":true},"country":{"type":"string","nullable":true},"services":{"type":"array","items":{"type":"string"},"nullable":true},"portalEmail":{"type":"string","nullable":true},"currency":{"type":"string"},"status":{"type":"string","enum":["draft","pending_approval","testing","active","suspended","terminated"]},"statusNote":{"type":"string","nullable":true},"statusChangedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"routable":{"type":"boolean","description":"Whether this provider admits new calls at all, given its status"},"contractStart":{"type":"string","nullable":true,"description":"YYYY-MM-DD"},"contractEnd":{"type":"string","nullable":true},"autoRenew":{"type":"boolean"},"rateNoticeDays":{"type":"integer","nullable":true},"disputeDays":{"type":"integer","nullable":true},"billingMode":{"type":"string","enum":["prepaid","postpaid"]},"creditLimit":{"type":"string","nullable":true,"description":"Decimal string with 2 decimal places, e.g. \"5000.00\""},"balance":{"$ref":"#/components/schemas/Money"},"paymentTermsDays":{"type":"integer","nullable":true},"invoiceCycle":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"trunks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"supplierId":{"type":"string","format":"uuid","nullable":true,"description":"The owning provider; null = ungrouped"},"label":{"type":"string"},"source":{"type":"string","description":"\"external\" for a carrier you entered; \"marketplace\" for a trunk promoted from a marketplace purchase"},"status":{"type":"string","enum":["active","disabled","draft","testing","draining","fault"]},"sipHost":{"type":"string","nullable":true,"description":"Null on a marketplace trunk: the seller address is never disclosed"},"sipPort":{"type":"integer","nullable":true},"transport":{"type":"string","enum":["udp","tcp","tls"],"nullable":true},"techPrefix":{"type":"string","nullable":true},"sipAuthUsername":{"type":"string","nullable":true},"sipAuthPasswordSet":{"type":"boolean","description":"Whether a SIP password is stored. The value is only readable via GET /switch/suppliers/{id}/credentials"},"smppPasswordSet":{"type":"boolean"},"mediaMode":{"type":"string","enum":["proxy","direct"]},"defaultRatePerUnit":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"Cost per minute used when no deck row matches"},"billingIncrement":{"type":"string","nullable":true},"currency":{"type":"string","nullable":true},"capacity":{"type":"integer","nullable":true,"description":"Max concurrent channels"},"maxCps":{"type":"integer","nullable":true},"settlementMode":{"type":"string","enum":["ap","prepaid"]},"balance":{"allOf":[{"$ref":"#/components/schemas/Money"}],"description":"Prepaid credit remaining with this supplier (prepaid settlement)"},"smsDeliveryMethod":{"type":"string","enum":["http","smpp"],"nullable":true},"reachable":{"type":"boolean","nullable":true},"reachCheckedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"endpointCount":{"type":"integer"},"endpointsEnabled":{"type":"integer"}},"required":["id","supplierId","label","source","status","sipHost","sipPort","transport","techPrefix","sipAuthUsername","sipAuthPasswordSet","smppPasswordSet","mediaMode","defaultRatePerUnit","billingIncrement","currency","capacity","maxCps","settlementMode","balance","smsDeliveryMethod","reachable","reachCheckedAt","createdAt","updatedAt","endpointCount","endpointsEnabled"],"additionalProperties":true,"description":"A supplier (vendor) trunk. Carries every spec section-4 policy field accepted on create/update; secrets are replaced by *Set booleans."}},"trunkCount":{"type":"integer"},"activeTrunks":{"type":"integer"},"totalCapacity":{"type":"integer"}},"required":["id","name","accountCode","legalName","tradingName","providerType","country","services","portalEmail","currency","status","statusNote","statusChangedAt","routable","contractStart","contractEnd","autoRenew","rateNoticeDays","disputeDays","billingMode","creditLimit","balance","paymentTermsDays","invoiceCycle","createdAt","updatedAt","trunks","trunkCount","activeTrunks","totalCapacity"],"additionalProperties":true}},"ungrouped":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"supplierId":{"type":"string","format":"uuid","nullable":true,"description":"The owning provider; null = ungrouped"},"label":{"type":"string"},"source":{"type":"string","description":"\"external\" for a carrier you entered; \"marketplace\" for a trunk promoted from a marketplace purchase"},"status":{"type":"string","enum":["active","disabled","draft","testing","draining","fault"]},"sipHost":{"type":"string","nullable":true,"description":"Null on a marketplace trunk: the seller address is never disclosed"},"sipPort":{"type":"integer","nullable":true},"transport":{"type":"string","enum":["udp","tcp","tls"],"nullable":true},"techPrefix":{"type":"string","nullable":true},"sipAuthUsername":{"type":"string","nullable":true},"sipAuthPasswordSet":{"type":"boolean","description":"Whether a SIP password is stored. The value is only readable via GET /switch/suppliers/{id}/credentials"},"smppPasswordSet":{"type":"boolean"},"mediaMode":{"type":"string","enum":["proxy","direct"]},"defaultRatePerUnit":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"Cost per minute used when no deck row matches"},"billingIncrement":{"type":"string","nullable":true},"currency":{"type":"string","nullable":true},"capacity":{"type":"integer","nullable":true,"description":"Max concurrent channels"},"maxCps":{"type":"integer","nullable":true},"settlementMode":{"type":"string","enum":["ap","prepaid"]},"balance":{"allOf":[{"$ref":"#/components/schemas/Money"}],"description":"Prepaid credit remaining with this supplier (prepaid settlement)"},"smsDeliveryMethod":{"type":"string","enum":["http","smpp"],"nullable":true},"reachable":{"type":"boolean","nullable":true},"reachCheckedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"endpointCount":{"type":"integer"},"endpointsEnabled":{"type":"integer"}},"required":["id","supplierId","label","source","status","sipHost","sipPort","transport","techPrefix","sipAuthUsername","sipAuthPasswordSet","smppPasswordSet","mediaMode","defaultRatePerUnit","billingIncrement","currency","capacity","maxCps","settlementMode","balance","smsDeliveryMethod","reachable","reachCheckedAt","createdAt","updatedAt","endpointCount","endpointsEnabled"],"additionalProperties":true,"description":"A supplier (vendor) trunk. Carries every spec section-4 policy field accepted on create/update; secrets are replaced by *Set booleans."}}},"required":["accounts","ungrouped"]},"SwitchProviderContact":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"supplierId":{"type":"string","format":"uuid"},"role":{"type":"string","enum":["noc","rates","billing","finance","fraud","account","emergency"]},"name":{"type":"string","nullable":true},"email":{"type":"string","nullable":true},"phone":{"type":"string","nullable":true},"timezone":{"type":"string","nullable":true},"notify":{"type":"boolean"},"notes":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","supplierId","role","name","email","phone","timezone","notify","notes","createdAt","updatedAt"]},"SwitchProviderDetail":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"accountCode":{"type":"string","nullable":true},"legalName":{"type":"string","nullable":true},"tradingName":{"type":"string","nullable":true},"providerType":{"type":"string","enum":["carrier","aggregator","mno","mvno","sip_provider"],"nullable":true},"country":{"type":"string","nullable":true},"services":{"type":"array","items":{"type":"string"},"nullable":true},"portalEmail":{"type":"string","nullable":true},"currency":{"type":"string"},"status":{"type":"string","enum":["draft","pending_approval","testing","active","suspended","terminated"]},"statusNote":{"type":"string","nullable":true},"statusChangedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"routable":{"type":"boolean","description":"Whether this provider admits new calls at all, given its status"},"contractStart":{"type":"string","nullable":true,"description":"YYYY-MM-DD"},"contractEnd":{"type":"string","nullable":true},"autoRenew":{"type":"boolean"},"rateNoticeDays":{"type":"integer","nullable":true},"disputeDays":{"type":"integer","nullable":true},"billingMode":{"type":"string","enum":["prepaid","postpaid"]},"creditLimit":{"type":"string","nullable":true,"description":"Decimal string with 2 decimal places, e.g. \"5000.00\""},"balance":{"$ref":"#/components/schemas/Money"},"paymentTermsDays":{"type":"integer","nullable":true},"invoiceCycle":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"contacts":{"type":"array","items":{"$ref":"#/components/schemas/SwitchProviderContact"}},"trunks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"supplierId":{"type":"string","format":"uuid","nullable":true,"description":"The owning provider; null = ungrouped"},"label":{"type":"string"},"source":{"type":"string","description":"\"external\" for a carrier you entered; \"marketplace\" for a trunk promoted from a marketplace purchase"},"status":{"type":"string","enum":["active","disabled","draft","testing","draining","fault"]},"sipHost":{"type":"string","nullable":true,"description":"Null on a marketplace trunk: the seller address is never disclosed"},"sipPort":{"type":"integer","nullable":true},"transport":{"type":"string","enum":["udp","tcp","tls"],"nullable":true},"techPrefix":{"type":"string","nullable":true},"sipAuthUsername":{"type":"string","nullable":true},"sipAuthPasswordSet":{"type":"boolean","description":"Whether a SIP password is stored. The value is only readable via GET /switch/suppliers/{id}/credentials"},"smppPasswordSet":{"type":"boolean"},"mediaMode":{"type":"string","enum":["proxy","direct"]},"defaultRatePerUnit":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"Cost per minute used when no deck row matches"},"billingIncrement":{"type":"string","nullable":true},"currency":{"type":"string","nullable":true},"capacity":{"type":"integer","nullable":true,"description":"Max concurrent channels"},"maxCps":{"type":"integer","nullable":true},"settlementMode":{"type":"string","enum":["ap","prepaid"]},"balance":{"allOf":[{"$ref":"#/components/schemas/Money"}],"description":"Prepaid credit remaining with this supplier (prepaid settlement)"},"smsDeliveryMethod":{"type":"string","enum":["http","smpp"],"nullable":true},"reachable":{"type":"boolean","nullable":true},"reachCheckedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"endpoints":{"type":"array","items":{"$ref":"#/components/schemas/SwitchTrunkEndpoint"}}},"required":["id","supplierId","label","source","status","sipHost","sipPort","transport","techPrefix","sipAuthUsername","sipAuthPasswordSet","smppPasswordSet","mediaMode","defaultRatePerUnit","billingIncrement","currency","capacity","maxCps","settlementMode","balance","smsDeliveryMethod","reachable","reachCheckedAt","createdAt","updatedAt","endpoints"],"additionalProperties":true,"description":"A supplier (vendor) trunk. Carries every spec section-4 policy field accepted on create/update; secrets are replaced by *Set booleans."}}},"required":["id","name","accountCode","legalName","tradingName","providerType","country","services","portalEmail","currency","status","statusNote","statusChangedAt","routable","contractStart","contractEnd","autoRenew","rateNoticeDays","disputeDays","billingMode","creditLimit","balance","paymentTermsDays","invoiceCycle","createdAt","updatedAt","contacts","trunks"],"additionalProperties":true},"SwitchProviderDispute":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"supplierId":{"type":"string","format":"uuid"},"periodStart":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"periodEnd":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"ourAmount":{"type":"string","nullable":true,"description":"Decimal string with 2 decimal places, e.g. \"5000.00\""},"theirAmount":{"type":"string","nullable":true,"description":"Decimal string with 2 decimal places, e.g. \"5000.00\""},"currency":{"type":"string"},"status":{"type":"string","enum":["open","submitted","accepted","rejected","settled","withdrawn"]},"reason":{"type":"string","nullable":true},"resolution":{"type":"string","nullable":true},"invoiceRef":{"type":"string","nullable":true},"openedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"respondBy":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"closedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"daysLeft":{"type":"integer","nullable":true,"description":"Days left to respond (list only); negative = the window has passed"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","supplierId","periodStart","periodEnd","ourAmount","theirAmount","currency","status","reason","resolution","invoiceRef","openedAt","respondBy","closedAt","createdAt","updatedAt"],"additionalProperties":true},"SwitchSbcProfile":{"type":"object","properties":{"trunkId":{"type":"string","format":"uuid"},"trunkLabel":{"type":"string"},"profileLevel":{"type":"array","items":{"type":"object","properties":{"endpointId":{"type":"string","format":"uuid"},"host":{"type":"string"},"settings":{"type":"array","items":{"type":"string"}}},"required":["endpointId","host","settings"]}},"xml":{"type":"string","description":"Gateway configuration to place on the SBC"},"applyNote":{"type":"string"}},"required":["trunkId","trunkLabel","profileLevel","xml","applyNote"]},"SwitchCounterparty":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"customerId":{"type":"string","format":"uuid","nullable":true,"description":"The customer side of this counterparty"},"vendorTrunkId":{"type":"string","format":"uuid","nullable":true,"description":"The supplier side of this counterparty"},"currency":{"type":"string"},"nettingEnabled":{"type":"boolean"},"notes":{"type":"string","nullable":true},"customerLabel":{"type":"string","nullable":true},"trunkLabel":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","name","customerId","vendorTrunkId","currency","nettingEnabled","notes","createdAt","updatedAt"],"additionalProperties":true},"SwitchRatingOutcome":{"type":"object","properties":{"kind":{"type":"string","enum":["rated","no_matching_rate","not_yet_effective","expired","forbidden","rating_failed","not_billable"]},"rate":{"type":"number","description":"Present when kind = rated. May legitimately be 0."},"matchedPrefix":{"type":"string"},"deckVersion":{"type":"integer","nullable":true},"source":{"type":"string"},"destination":{"type":"string"},"effectiveFrom":{"type":"string"},"expiredAt":{"type":"string"},"reason":{"type":"string","description":"Why it is forbidden or failed"}},"required":["kind"],"description":"A price, or the reason there is none. Only kind = rated carries a rate."},"SwitchRateDeckDiff":{"type":"object","properties":{"removalMode":{"type":"string","enum":["merge","replace"]},"changeMode":{"type":"string","enum":["amendment","full_replacement"]},"live":{"type":"integer","description":"Prefixes priced on the live deck now"},"incoming":{"type":"integer","description":"Prefixes the new rows price"},"added":{"type":"integer"},"changed":{"type":"integer"},"rateChanged":{"type":"integer"},"incrementOnly":{"type":"integer","description":"Changed rows where only the billing increment moved"},"unchanged":{"type":"integer"},"removed":{"type":"integer","description":"Live prefixes the new rows do not mention"}},"required":["removalMode","changeMode","live","incoming","added","changed","rateChanged","incrementOnly","unchanged","removed"],"additionalProperties":true,"description":"What a change does to live pricing, with the biggest movers"},"SwitchRateDeck":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"supplierId":{"type":"string","format":"uuid","nullable":true,"description":"The provider who sent it; null for a deck recorded before its provider was"},"name":{"type":"string"},"currency":{"type":"string","minLength":3,"maxLength":3},"version":{"type":"integer"},"status":{"type":"string","enum":["draft","uploaded","invalid","validated","pending_approval","scheduled","active","expired","rolled_back"]},"effectiveFrom":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"expiresAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"source":{"type":"string","enum":["portal","csv","api","email","sftp"],"nullable":true},"sourceRef":{"type":"string","nullable":true},"approvedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"validation":{"type":"object","properties":{"checkedAt":{"type":"string"},"rows":{"type":"integer"},"destinations":{"type":"integer"},"errors":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true,"description":"One validation finding (code, message and the rows it concerns)"}},"warnings":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true,"description":"One validation finding (code, message and the rows it concerns)"}},"maxIncreasePct":{"type":"number"}},"required":["checkedAt","rows","destinations","errors","warnings"],"nullable":true,"description":"The last validation result; null before the deck is validated"},"supersedesId":{"type":"string","format":"uuid","nullable":true},"rolledBackAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"notes":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"rowCount":{"type":"integer"},"trunks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"label":{"type":"string"}},"required":["id","label"]},"description":"Supplier trunks the deck prices"},"mutable":{"type":"boolean","description":"Whether rows can still be edited"}},"required":["id","supplierId","name","currency","version","status","effectiveFrom","expiresAt","source","sourceRef","approvedAt","validation","supersedesId","rolledBackAt","notes","createdAt","updatedAt","rowCount","trunks","mutable"],"additionalProperties":true},"SwitchDeckSheetResult":{"type":"object","properties":{"targetLabel":{"type":"string"},"rowCount":{"type":"integer"},"currency":{"type":"string"},"warnings":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}},"diff":{"$ref":"#/components/schemas/SwitchRateDeckDiff","description":"What a change does to live pricing, with the biggest movers"},"applied":{"type":"integer","description":"Rows written (apply) or queued (scheduled apply)"},"replaced":{"type":"boolean"},"scheduled":{"type":"boolean","enum":[true],"description":"Present when a future effectiveFrom queued the sheet"},"effectiveFrom":{"type":"string"},"originScoped":{"type":"integer","description":"Origin-scoped live rows a sheet cannot express, counted not changed"},"overLimit":{"type":"boolean"},"maxRows":{"type":"integer"}},"required":["targetLabel","currency","warnings"],"additionalProperties":true},"SwitchSellDeck":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"version":{"type":"integer"},"status":{"type":"string","enum":["draft","active","superseded","archived"]},"currency":{"type":"string","minLength":3,"maxLength":3},"isSystemDefault":{"type":"boolean"},"defaultRatePerUnit":{"type":"number","nullable":true,"description":"Catch-all price for destinations the deck does not list (a JSON number)"},"charging":{"type":"object","properties":{"minimumDurationSeconds":{"type":"integer","nullable":true},"firstIntervalSeconds":{"type":"integer","nullable":true},"subsequentIntervalSeconds":{"type":"integer","nullable":true},"setupFee":{"type":"number","nullable":true,"description":"Per-call setup fee (a JSON number)"},"graceSeconds":{"type":"integer","nullable":true},"rounding":{"type":"string","enum":["up","nearest","down"],"nullable":true}},"required":["minimumDurationSeconds","firstIntervalSeconds","subsequentIntervalSeconds","setupFee","graceSeconds","rounding"]}},"required":["id","name","version","status","currency","isSystemDefault","defaultRatePerUnit","charging"],"additionalProperties":true},"SwitchSellDeckRow":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"deckId":{"type":"string","format":"uuid"},"prefix":{"type":"string"},"originPrefix":{"type":"string","description":"\"\" = any origin"},"ratePerUnit":{"$ref":"#/components/schemas/Money"},"billingIncrement":{"type":"string","nullable":true,"description":"null = inherit the trunk or customer default"},"destinationName":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","deckId","prefix","originPrefix","ratePerUnit","billingIncrement","destinationName","createdAt","updatedAt"],"additionalProperties":true},"SwitchSellRate":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"prefix":{"type":"string"},"originPrefix":{"type":"string","description":"\"\" = any origin"},"ratePerUnit":{"$ref":"#/components/schemas/Money"},"billingIncrement":{"type":"string","nullable":true,"description":"null = inherit the trunk default"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","prefix","originPrefix","ratePerUnit","billingIncrement","createdAt","updatedAt"],"additionalProperties":true},"SwitchEligibleSupplier":{"type":"object","properties":{"vendorTrunkId":{"type":"string","format":"uuid"},"label":{"type":"string"},"status":{"type":"string"},"via":{"type":"array","items":{"type":"object","properties":{"source":{"type":"string","enum":["fixed target","route group","failover group","dialplan rule"]},"groupId":{"type":"string","format":"uuid","nullable":true},"groupName":{"type":"string","nullable":true},"prefix":{"type":"string","nullable":true},"priority":{"type":"integer","nullable":true}},"required":["source","groupId","groupName","prefix","priority"]}},"defaultRatePerUnit":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"US dollars as a decimal string with exactly 6 decimal places, e.g. \"0.012500\". Do money arithmetic with a decimal type, not floating point."},"activeRateRows":{"type":"integer"},"unpriced":{"type":"boolean","description":"True when the trunk has no rates and no default: calls to it cannot be costed"},"billingIncrement":{"type":"string"}},"required":["vendorTrunkId","label","status","via","defaultRatePerUnit","activeRateRows","unpriced","billingIncrement"],"additionalProperties":true},"SwitchCostAnalysis":{"type":"object","properties":{"at":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"input":{"type":"object","properties":{},"additionalProperties":true,"description":"The destination, routed number, origin, customer, trunk and reference call length used"},"basis":{"type":"object","properties":{"resolved":{"type":"boolean"},"detail":{"type":"string"},"routingKind":{"type":"string","enum":["fixed","group","dialplan","none"]},"routingName":{"type":"string","nullable":true},"selectionMode":{"type":"string","nullable":true},"maxAttempts":{"type":"integer","nullable":true}},"required":["resolved","detail","routingKind","routingName","selectionMode","maxAttempts"],"additionalProperties":true},"sell":{"type":"object","properties":{"outcome":{"allOf":[{"$ref":"#/components/schemas/SwitchRatingOutcome"}],"nullable":true,"description":"A price, or the reason there is none. Only kind = rated carries a rate."},"billingRate":{"type":"number","nullable":true,"description":"USD as a JSON number (engine output, up to 6 decimal places)"},"matchedPrefix":{"type":"string","nullable":true},"billingIncrement":{"type":"string"}},"required":["outcome","billingRate","matchedPrefix","billingIncrement"],"additionalProperties":true},"suppliers":{"type":"array","items":{"type":"object","properties":{"vendorTrunkId":{"type":"string","format":"uuid","nullable":true},"label":{"type":"string"},"kind":{"type":"string","enum":["supplier trunk","marketplace route"]},"chainOrdinal":{"type":"integer","nullable":true,"description":"Attempt position in the failover chain; null if past the attempt ceiling"},"outcome":{"allOf":[{"$ref":"#/components/schemas/SwitchRatingOutcome"}],"nullable":true,"description":"A price, or the reason there is none. Only kind = rated carries a rate."},"billingRate":{"type":"number","nullable":true,"description":"USD as a JSON number (engine output, up to 6 decimal places)"},"source":{"type":"string","enum":["supplier deck","trunk default","marketplace listing","unpriced"]},"matchedPrefix":{"type":"string","nullable":true},"deckId":{"type":"string","format":"uuid","nullable":true},"deckVersion":{"type":"integer","nullable":true},"billingIncrement":{"type":"string"},"excluded":{"type":"object","properties":{"stage":{"type":"string"},"reason":{"type":"string"},"detail":{"type":"string"}},"required":["stage","reason","detail"],"nullable":true}},"required":["vendorTrunkId","label","kind","chainOrdinal","outcome","billingRate","source","matchedPrefix","deckId","deckVersion","billingIncrement","excluded"],"additionalProperties":true}},"selected":{"type":"object","properties":{"vendorTrunkId":{"type":"string","format":"uuid","nullable":true},"label":{"type":"string"},"kind":{"type":"string","enum":["supplier trunk","marketplace route"]},"chainOrdinal":{"type":"integer","nullable":true,"description":"Attempt position in the failover chain; null if past the attempt ceiling"},"outcome":{"allOf":[{"$ref":"#/components/schemas/SwitchRatingOutcome"}],"nullable":true,"description":"A price, or the reason there is none. Only kind = rated carries a rate."},"billingRate":{"type":"number","nullable":true,"description":"USD as a JSON number (engine output, up to 6 decimal places)"},"source":{"type":"string","enum":["supplier deck","trunk default","marketplace listing","unpriced"]},"matchedPrefix":{"type":"string","nullable":true},"deckId":{"type":"string","format":"uuid","nullable":true},"deckVersion":{"type":"integer","nullable":true},"billingIncrement":{"type":"string"},"excluded":{"type":"object","properties":{"stage":{"type":"string"},"reason":{"type":"string"},"detail":{"type":"string"}},"required":["stage","reason","detail"],"nullable":true}},"required":["vendorTrunkId","label","kind","chainOrdinal","outcome","billingRate","source","matchedPrefix","deckId","deckVersion","billingIncrement","excluded"],"additionalProperties":true,"nullable":true},"configuredMargin":{"type":"object","properties":{"kind":{"type":"string","enum":["configured_estimate"]},"perMinute":{"type":"number","nullable":true,"description":"USD as a JSON number (engine output, up to 6 decimal places)"},"perMinutePct":{"type":"number","nullable":true},"referenceCall":{"type":"object","properties":{},"additionalProperties":true,"nullable":true,"description":"Revenue, cost and margin of a call of the reference length, increment-aware (JSON numbers)"},"range":{"type":"object","properties":{},"additionalProperties":true,"nullable":true},"explain":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string"},"value":{"type":"string"},"note":{"type":"string"},"source":{"type":"string"}},"required":["label","value"]}}},"required":["kind","perMinute","perMinutePct","referenceCall","range","explain"],"additionalProperties":true},"traceId":{"type":"string","format":"uuid","description":"The route trace this analysis ran on"},"verdict":{"type":"object","properties":{},"additionalProperties":true},"sideEffects":{"type":"object","properties":{"createdCdr":{"type":"boolean","enum":[false]},"movedBalance":{"type":"boolean","enum":[false]},"consumedCapacity":{"type":"boolean","enum":[false]}},"required":["createdCdr","movedBalance","consumedCapacity"]}},"required":["at","input","basis","sell","suppliers","selected","configuredMargin","traceId","verdict","sideEffects"],"additionalProperties":true},"SwitchSessionMargin":{"type":"object","properties":{"sessionKey":{"type":"string"},"callUuid":{"type":"string","nullable":true},"at":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"destination":{"type":"string","nullable":true},"destinationName":{"type":"string","nullable":true},"customerTrunkId":{"type":"string","format":"uuid","nullable":true},"status":{"type":"string","nullable":true},"durationSeconds":{"type":"integer"},"billedSeconds":{"type":"integer","nullable":true},"billingIncrement":{"type":"string","nullable":true},"sellRate":{"type":"number","nullable":true,"description":"USD as a JSON number (engine output, up to 6 decimal places)"},"charge":{"type":"number","description":"USD as a JSON number (engine output, up to 6 decimal places)"},"bookedCost":{"type":"number","description":"USD as a JSON number (engine output, up to 6 decimal places)"},"attempts":{"type":"array","items":{"type":"object","properties":{"ordinal":{"type":"integer"},"supplier":{"type":"string","nullable":true},"vendorTrunkId":{"type":"string","format":"uuid","nullable":true},"outcome":{"type":"string"},"sipStatus":{"type":"integer","nullable":true},"won":{"type":"boolean"},"answeredSeconds":{"type":"integer","nullable":true},"buyRate":{"type":"number","nullable":true,"description":"USD as a JSON number (engine output, up to 6 decimal places)"},"costBasis":{"type":"string","enum":["booked","derived","none"]},"derivedCost":{"type":"number","nullable":true,"description":"USD as a JSON number (engine output, up to 6 decimal places)"}},"required":["ordinal","supplier","vendorTrunkId","outcome","sipStatus","won","answeredSeconds","buyRate","costBasis","derivedCost"]}},"attemptCost":{"type":"number","description":"USD as a JSON number (engine output, up to 6 decimal places)"},"margin":{"type":"number","description":"USD as a JSON number (engine output, up to 6 decimal places)"},"flags":{"type":"array","items":{"type":"string"}}},"required":["sessionKey","callUuid","at","destination","destinationName","customerTrunkId","status","durationSeconds","billedSeconds","billingIncrement","sellRate","charge","bookedCost","attempts","attemptCost","margin","flags"],"additionalProperties":true},"SwitchRouteGroup":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"operatorId":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"enabled":{"type":"boolean"},"failoverSipCodes":{"type":"array","items":{"type":"integer"},"description":"SIP results that move the call to the next supplier"},"maxAttempts":{"type":"integer","description":"1 to 6"},"selectionMode":{"type":"string","enum":["priority","least_cost","weighted"],"description":"How the first supplier is picked; failover is always sequential"},"failoverTimeoutSeconds":{"type":"integer","nullable":true,"description":"null = the platform budget"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","operatorId","name","description","enabled","failoverSipCodes","maxAttempts","selectionMode","failoverTimeoutSeconds","createdAt","updatedAt"],"additionalProperties":true},"SwitchDialplan":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"operatorId":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"enabled":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","operatorId","name","description","enabled","createdAt","updatedAt"],"additionalProperties":true},"SwitchRouteTrace":{"type":"object","properties":{"traceId":{"type":"string","format":"uuid"},"at":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"saved":{"type":"boolean"},"savedNote":{"type":"string","nullable":true},"input":{"type":"object","properties":{"to":{"type":"string"},"cli":{"type":"string","nullable":true},"type":{"type":"string","enum":["voice","sms"]},"subAccountId":{"type":"string","format":"uuid","nullable":true},"subAccountLabel":{"type":"string","nullable":true},"customerTrunkId":{"type":"string","format":"uuid","nullable":true},"customerTrunkLabel":{"type":"string","nullable":true}},"required":["to","cli","type","subAccountId","subAccountLabel","customerTrunkId","customerTrunkLabel"]},"verdict":{"type":"object","properties":{"routes":{"type":"boolean","description":"Would the call be carried?"},"sipCode":{"type":"integer","nullable":true,"description":"What the customer's switch would receive"},"reason":{"type":"string","nullable":true},"summary":{"type":"string"}},"required":["routes","sipCode","reason","summary"]},"steps":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true},"description":"Each decision stage with its result"},"number":{"type":"object","properties":{"dialled":{"type":"string"},"digits":{"type":"string"},"afterTechPrefix":{"type":"string"},"translated":{"type":"string"},"country":{"type":"string","nullable":true}},"required":["dialled","digits","afterTechPrefix","translated","country"]},"outCli":{"type":"string","nullable":true},"sell":{"allOf":[{"$ref":"#/components/schemas/SwitchRatingOutcome"}],"nullable":true,"description":"A price, or the reason there is none. Only kind = rated carries a rate."},"sellBillingRate":{"type":"number","nullable":true,"description":"USD as a JSON number (engine output, up to 6 decimal places)"},"candidates":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true},"description":"Suppliers in the chain, in attempt order, with buy rate, capacity and margin"},"excluded":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true},"description":"Suppliers considered and not used, each with the reason"},"selected":{"type":"object","properties":{},"additionalProperties":true,"nullable":true},"duration":{"type":"object","properties":{"seconds":{"type":"integer"},"boundBy":{"type":"string","enum":["balance","platform","trunk"]}},"required":["seconds","boundBy"],"nullable":true},"sideEffects":{"type":"object","properties":{"createdCdr":{"type":"boolean","enum":[false]},"movedBalance":{"type":"boolean","enum":[false]},"consumedCapacity":{"type":"boolean","enum":[false]}},"required":["createdCdr","movedBalance","consumedCapacity"]}},"required":["traceId","at","saved","savedNote","input","verdict","steps","number","outCli","sell","sellBillingRate","candidates","excluded","selected","duration","sideEffects"],"additionalProperties":true},"SwitchPayment":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"amount":{"$ref":"#/components/schemas/Money"},"method":{"type":"string","nullable":true},"reference":{"type":"string","nullable":true},"paidAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","amount","method","reference","paidAt","createdAt"],"additionalProperties":true},"SwitchInvoice":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customerId":{"type":"string","format":"uuid"},"invoiceNumber":{"type":"string","description":"Sequential per operator, gap-free"},"periodStart":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"periodEnd":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"issueDate":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"dueDate":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"currency":{"type":"string","minLength":3,"maxLength":3},"subtotal":{"$ref":"#/components/schemas/Money"},"tax":{"$ref":"#/components/schemas/Money"},"total":{"$ref":"#/components/schemas/Money"},"amountPaid":{"$ref":"#/components/schemas/Money"},"status":{"type":"string","enum":["draft","open","partial","paid","overdue","void"]},"overdue":{"type":"boolean"},"notes":{"type":"string","nullable":true},"replacesInvoiceId":{"type":"string","format":"uuid","nullable":true},"sentAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"sendCount":{"type":"integer"},"customerLabel":{"type":"string","nullable":true,"description":"On list rows"}},"required":["id","customerId","invoiceNumber","periodStart","periodEnd","issueDate","dueDate","currency","subtotal","tax","total","amountPaid","status","overdue","notes"],"additionalProperties":true},"SwitchInvoiceDetail":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customerId":{"type":"string","format":"uuid"},"invoiceNumber":{"type":"string","description":"Sequential per operator, gap-free"},"periodStart":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"periodEnd":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"issueDate":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"dueDate":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"currency":{"type":"string","minLength":3,"maxLength":3},"subtotal":{"$ref":"#/components/schemas/Money"},"tax":{"$ref":"#/components/schemas/Money"},"total":{"$ref":"#/components/schemas/Money"},"amountPaid":{"$ref":"#/components/schemas/Money"},"status":{"type":"string","enum":["draft","open","partial","paid","overdue","void"]},"overdue":{"type":"boolean"},"notes":{"type":"string","nullable":true},"replacesInvoiceId":{"type":"string","format":"uuid","nullable":true},"sentAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"sendCount":{"type":"integer"},"customerLabel":{"type":"string","nullable":true,"description":"On list rows"},"lines":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true},"description":"Invoice lines in print order"},"payments":{"type":"array","items":{"$ref":"#/components/schemas/SwitchPayment"}},"customer":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"label":{"type":"string"},"source":{"type":"string","nullable":true},"currency":{"type":"string"}},"required":["id","label","source","currency"],"nullable":true},"countryBreakdown":{"type":"object","properties":{},"additionalProperties":true,"description":"Voice usage on this invoice by destination country (derived, read-only)"},"billingProfile":{"type":"object","properties":{},"additionalProperties":true,"nullable":true,"description":"The billing identity frozen onto the document at issue"},"identityFrozen":{"type":"boolean"},"exclusions":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true},"description":"Usage consciously left unbilled on this run, with the reason"},"replaces":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"invoiceNumber":{"type":"string"},"status":{"type":"string","enum":["draft","open","partial","paid","overdue","void"]}},"required":["id","invoiceNumber","status"],"nullable":true},"replacedBy":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"invoiceNumber":{"type":"string"},"status":{"type":"string","enum":["draft","open","partial","paid","overdue","void"]}},"required":["id","invoiceNumber","status"],"nullable":true}},"required":["id","customerId","invoiceNumber","periodStart","periodEnd","issueDate","dueDate","currency","subtotal","tax","total","amountPaid","status","overdue","notes","lines","payments","customer","countryBreakdown","billingProfile","identityFrozen","exclusions","replaces","replacedBy"],"additionalProperties":true},"SwitchInvoicePreview":{"type":"object","properties":{"customer":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"label":{"type":"string"},"legalName":{"type":"string"},"currency":{"type":"string"}},"required":["id","label","legalName","currency"]},"period":{"type":"object","properties":{"start":{"type":"string"},"end":{"type":"string"},"timezone":{"type":"string"},"label":{"type":"string"}},"required":["start","end","timezone","label"]},"dueDate":{"type":"string"},"paymentTermsDays":{"type":"integer"},"currency":{"type":"string"},"usage":{"type":"object","properties":{},"additionalProperties":true,"description":"Billable, rated-at-zero, by-trunk and by-channel usage"},"broughtForward":{"type":"object","properties":{},"additionalProperties":true},"unrated":{"type":"object","properties":{},"additionalProperties":true,"description":"Usage that could not be priced. Blocks issue unless excluded with a reason."},"lines":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}},"charges":{"type":"number","description":"US dollars as a JSON number rounded to 6 decimals (a computed figure, not a ledger string)"},"credits":{"type":"object","properties":{},"additionalProperties":true},"tax":{"type":"object","properties":{},"additionalProperties":true},"total":{"type":"number","description":"US dollars as a JSON number rounded to 6 decimals (a computed figure, not a ledger string)"},"provenance":{"type":"object","properties":{},"additionalProperties":true},"reviewToken":{"type":"string","description":"Pass to POST /switch/invoices to issue exactly what was reviewed"}},"required":["customer","period","dueDate","paymentTermsDays","currency","usage","broughtForward","unrated","lines","charges","credits","tax","total","provenance"],"additionalProperties":true},"SwitchCreditNote":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customerId":{"type":"string","format":"uuid"},"creditNoteNumber":{"type":"string"},"invoiceId":{"type":"string","format":"uuid","nullable":true},"amount":{"$ref":"#/components/schemas/Money"},"reason":{"type":"string","nullable":true},"status":{"type":"string","description":"issued (open credit) or applied"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"customerLabel":{"type":"string","nullable":true}},"required":["id","customerId","creditNoteNumber","invoiceId","amount","reason","status","createdAt"],"additionalProperties":true},"SwitchPayable":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"vendorTrunkId":{"type":"string","format":"uuid"},"payableNumber":{"type":"string"},"periodStart":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"periodEnd":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"issueDate":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"dueDate":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"currency":{"type":"string","minLength":3,"maxLength":3},"subtotal":{"$ref":"#/components/schemas/Money"},"total":{"$ref":"#/components/schemas/Money"},"amountPaid":{"$ref":"#/components/schemas/Money"},"status":{"type":"string","enum":["draft","open","partial","paid","overdue","void"]},"notes":{"type":"string","nullable":true},"overdue":{"type":"boolean"},"trunkLabel":{"type":"string","nullable":true,"description":"On list rows"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","vendorTrunkId","payableNumber","periodStart","periodEnd","issueDate","dueDate","currency","subtotal","total","amountPaid","status","notes","createdAt","updatedAt"],"additionalProperties":true},"SwitchCdr":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"kind":{"type":"string","enum":["voice","sms"]},"direction":{"type":"string"},"from":{"type":"string","nullable":true},"to":{"type":"string","nullable":true},"cli":{"type":"string","nullable":true},"status":{"type":"string"},"sipCode":{"type":"integer","nullable":true},"hangupCause":{"type":"string","nullable":true},"durationSeconds":{"type":"integer","nullable":true},"billedSeconds":{"type":"integer","nullable":true},"segments":{"type":"integer","nullable":true},"pddMs":{"type":"integer","nullable":true},"callGroupId":{"type":"string","nullable":true,"description":"Shared by every failover attempt of one call"},"customer":{"type":"string","nullable":true},"supplier":{"type":"string","nullable":true},"revenue":{"type":"number","description":"US dollars as a JSON number rounded to 6 decimals (a computed figure, not a ledger string)"},"cost":{"type":"number","description":"US dollars as a JSON number rounded to 6 decimals (a computed figure, not a ledger string)"},"margin":{"type":"number","description":"US dollars as a JSON number rounded to 6 decimals (a computed figure, not a ledger string)"},"sellRatePerUnit":{"type":"number","nullable":true,"description":"null when the call could not be rated (distinct from a real 0)"},"buyRatePerUnit":{"type":"number","nullable":true,"description":"US dollars as a JSON number rounded to 6 decimals (a computed figure, not a ledger string)"},"ratingState":{"type":"string","nullable":true},"mos":{"type":"number","nullable":true},"jitterMs":{"type":"number","nullable":true},"packetLossPct":{"type":"number","nullable":true},"mediaMode":{"type":"string","nullable":true},"codec":{"type":"string","nullable":true},"q850Cause":{"type":"integer","nullable":true},"destinationName":{"type":"string","nullable":true},"riskScore":{"type":"number","nullable":true},"attestation":{"type":"string","nullable":true},"customerTrunkId":{"type":"string","format":"uuid","nullable":true},"attemptCount":{"type":"integer"},"invoiceId":{"type":"string","format":"uuid","nullable":true}},"required":["id","createdAt","kind","direction","from","to","cli","status","sipCode","hangupCause","durationSeconds","billedSeconds","segments","pddMs","callGroupId","customer","supplier","revenue","cost","margin","sellRatePerUnit","buyRatePerUnit","ratingState","mos","jitterMs","packetLossPct","mediaMode","codec","q850Cause","destinationName"],"additionalProperties":true},"SwitchCdrExport":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"phase":{"type":"string","description":"queued, running, completed or failed"},"status":{"type":"string"},"requestedScope":{"type":"string","nullable":true},"requestedAt":{"type":"string"},"recordCount":{"type":"integer","nullable":true,"description":"Only set once completed"},"numbersMasked":{"type":"boolean"},"addressesMasked":{"type":"boolean"},"truncated":{"type":"boolean"},"error":{"type":"string","nullable":true},"completedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"downloadable":{"type":"boolean"},"downloadUrl":{"type":"string","nullable":true,"description":"GET /billing/exports/{id}/download once completed. No server path is ever returned."},"rowCount":{"type":"integer","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"queryId":{"type":"string","nullable":true}},"required":["id","phase","status","requestedScope","requestedAt","recordCount","numbersMasked","addressesMasked"],"additionalProperties":true},"SwitchCdrView":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"service":{"type":"string","enum":["voice","sms"]},"filters":{"type":"object","additionalProperties":{}},"columns":{"type":"array","items":{"type":"string"}},"sort":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"direction":{"type":"string","enum":["asc","desc"]}},"required":["field","direction"]}},"isDefault":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","name","service","filters","columns","sort","isDefault","createdAt","updatedAt"],"additionalProperties":true},"SwitchFraudSettings":{"type":"object","properties":{"fraudEnabled":{"type":"boolean"},"fraudBlockScore":{"type":"integer","minimum":1,"maximum":100,"description":"Risk score at or above which a call is refused"},"fraudAlertScore":{"type":"integer","minimum":1,"maximum":100,"description":"Risk score at or above which a call is flagged"},"highRiskPrefixes":{"type":"array","items":{"type":"string"}}},"required":["fraudEnabled","fraudBlockScore","fraudAlertScore","highRiskPrefixes"]},"SwitchIssue":{"type":"object","properties":{"key":{"type":"string"},"ref":{"type":"string","description":"Quotable reference, e.g. OPS-3F9A1C22"},"detector":{"type":"string"},"severity":{"type":"string","enum":["critical","warning","review"]},"actionable":{"type":"boolean"},"status":{"type":"string","enum":["open_unacknowledged","open_acknowledged","resolved"]},"title":{"type":"string"},"summary":{"type":"string"},"reason":{"type":"string"},"trigger":{"type":"string"},"recovery":{"type":"string"},"objectName":{"type":"string","nullable":true},"subjects":{"type":"object","properties":{},"additionalProperties":true,"description":"The customer, trunks, supplier and destination the issue is about"},"evidence":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string"},"value":{"type":"string"}},"required":["label","value"]}},"firstDetectedAt":{"type":"string"},"lastDetectedAt":{"type":"string"},"detections":{"type":"integer"},"acknowledgedAt":{"type":"string","nullable":true},"resolvedAt":{"type":"string","nullable":true},"resolvedVia":{"type":"string","enum":["operator","recovery","dismissed"],"nullable":true},"dismissRule":{"type":"string","nullable":true,"description":"What would reopen the issue if it were dismissed"}},"required":["key","ref","detector","severity","actionable","status","title","summary","reason","trigger","recovery","objectName","subjects","evidence","firstDetectedAt","lastDetectedAt","detections","acknowledgedAt","resolvedAt","resolvedVia","dismissRule"],"additionalProperties":true},"SwitchTeamMember":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"email":{"type":"string"},"contactName":{"type":"string","nullable":true},"role":{"type":"string"},"roleLabel":{"type":"string"},"status":{"anyOf":[{"type":"string","enum":["active","suspended"]},{"type":"string"}]},"customerIds":{"type":"array","items":{"type":"string","format":"uuid"},"nullable":true},"trunkIds":{"type":"array","items":{"type":"string","format":"uuid"},"nullable":true},"note":{"type":"string","nullable":true},"permissions":{"type":"array","items":{"type":"string"}},"scopeSummary":{"type":"object","properties":{"customers":{"type":"string"},"trunks":{"type":"string"}},"required":["customers","trunks"]},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","userId","email","contactName","role","roleLabel","status","customerIds","trunkIds","note","permissions","scopeSummary","createdAt","updatedAt"],"additionalProperties":true},"SwitchApproval":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","description":"pending, approved, rejected, expired..."},"permission":{"type":"string"},"requestedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","status","requestedAt"],"additionalProperties":true},"SwitchDncHonorSetting":{"type":"object","properties":{"scope":{"type":"string","enum":["customer","trunk"]},"id":{"type":"string","format":"uuid"},"label":{"type":"string"},"value":{"type":"boolean","nullable":true,"description":"The setting itself; null on a trunk means it inherits from its customer"},"inherited":{"type":"boolean","nullable":true},"customerLabel":{"type":"string","nullable":true},"effective":{"type":"boolean","description":"Whether calls are actually checked against Do Not Call"},"decidedBy":{"type":"string","enum":["customer","trunk"],"description":"Which level decided `effective`"},"mode":{"type":"string","enum":["off","warn","enforce"],"description":"The platform setting for Switch calls: off = not checked; warn = matches are recorded but the call proceeds; enforce = matches are refused"},"trunkOverrides":{"type":"object","properties":{"on":{"type":"integer"},"off":{"type":"integer"}},"required":["on","off"],"description":"Customer only: trunks that set their own value instead of inheriting"}},"required":["scope","id","label","value","inherited","customerLabel","effective","decidedBy","mode"]},"PricingDestination":{"type":"object","properties":{"slug":{"type":"string","description":"URL slug from the country name, e.g. \"pakistan\""},"country":{"type":"string"},"countryCode":{"type":"string","description":"E.164 country calling code, digits only"},"routes":{"type":"integer","description":"Live routes that price at least one number type"},"lowest":{"type":"string","description":"Lowest mobile, fixed or country-wide rate"},"lowestBand":{"type":"string","enum":["mobile","fixed","countryWide"],"description":"`mobile` and `fixed`: rate-sheet rows named for that number type. `countryWide`: the bare country row (or a single-price listing), which prices every number without a more specific row."},"unit":{"type":"string","enum":["min","msg"],"description":"Per minute (voice) or per message (SMS)"}},"required":["slug","country","countryCode","routes","lowest","lowestBand","unit"]},"PricingDestinationDetail":{"type":"object","properties":{"slug":{"type":"string","description":"URL slug from the country name, e.g. \"pakistan\""},"country":{"type":"string"},"countryCode":{"type":"string","description":"E.164 country calling code, digits only"},"routes":{"type":"integer","description":"Live routes that price at least one number type"},"lowest":{"type":"string","description":"Lowest mobile, fixed or country-wide rate"},"lowestBand":{"type":"string","enum":["mobile","fixed","countryWide"],"description":"`mobile` and `fixed`: rate-sheet rows named for that number type. `countryWide`: the bare country row (or a single-price listing), which prices every number without a more specific row."},"unit":{"type":"string","enum":["min","msg"],"description":"Per minute (voice) or per message (SMS)"},"type":{"type":"string","enum":["voice","sms"]},"highest":{"type":"string","description":"Highest route \"from\" price in the destination"},"bands":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","enum":["mobile","fixed","countryWide"],"description":"`mobile` and `fixed`: rate-sheet rows named for that number type. `countryWide`: the bare country row (or a single-price listing), which prices every number without a more specific row."},"from":{"type":"string","description":"USD, 6-decimal string, e.g. \"0.020370\""},"routes":{"type":"integer"}},"required":["key","from","routes"]},"description":"Lowest rate per number type"},"operators":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"from":{"type":"string","description":"USD, 6-decimal string, e.g. \"0.020370\""},"routes":{"type":"integer"}},"required":["name","from","routes"]},"description":"Mobile operators broken out on at least two routes, cheapest first, at most 12"},"cliTypes":{"type":"array","items":{"type":"object","properties":{"cliType":{"type":"string"},"routes":{"type":"integer"}},"required":["cliType","routes"]},"description":"Caller-ID handling the sellers state (voice only)"},"increments":{"type":"array","items":{"type":"object","properties":{"increment":{"type":"string"},"routes":{"type":"integer"}},"required":["increment","routes"]},"description":"Billing increments, e.g. \"1/1\" (voice only)"},"routesWithStatedAsr":{"type":"integer","description":"Routes whose seller states an ASR"},"otherBreakouts":{"type":"integer","description":"Named breakouts that are not a headline number type (toll-free, premium, cities)"},"topRoutes":{"type":"array","items":{"type":"object","properties":{"rank":{"type":"integer"},"from":{"type":"string","description":"USD, 6-decimal string, e.g. \"0.020370\""},"mobileFrom":{"type":"string","nullable":true,"description":"USD, 6-decimal string, e.g. \"0.020370\""},"cliType":{"type":"string"},"billingIncrement":{"type":"string","nullable":true},"routeType":{"type":"string","description":"Quality tier the route is listed under"},"statedAsr":{"type":"string","nullable":true,"description":"Seller-stated ASR %, not measured"},"statedAcd":{"type":"string","nullable":true,"description":"Seller-stated ACD in seconds, not measured"}},"required":["rank","from","mobileFrom","cliType","billingIncrement","routeType","statedAsr","statedAcd"]},"description":"The five cheapest routes, as anonymous facts"},"related":{"type":"array","items":{"$ref":"#/components/schemas/PricingDestination"},"description":"Destinations in the same world numbering zone"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["slug","country","countryCode","routes","lowest","lowestBand","unit","type","highest","bands","operators","cliTypes","increments","routesWithStatedAsr","otherBreakouts","topRoutes","related","updatedAt"]},"SystemHealth":{"type":"object","properties":{"components":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"status":{"type":"string","enum":["operational","degraded","down"]}},"required":["name","status"]}},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["components","updatedAt"]},"UsComplianceProfile":{"type":"object","properties":{"userId":{"type":"string","format":"uuid"},"legalBusinessName":{"type":"string"},"contactName":{"type":"string"},"contactEmail":{"type":"string"},"contactPhone":{"type":"string","nullable":true},"frn":{"type":"string","description":"FCC Registration Number"},"filer499Id":{"type":"string","description":"FCC Form 499 Filer ID"},"ocn":{"type":"string","description":"Operating Company Number"},"rmdRegistered":{"type":"boolean","description":"Listed in the FCC Robocall Mitigation Database"},"rmdReference":{"type":"string","nullable":true},"signsOwnTraffic":{"type":"boolean","description":"Signs its own STIR/SHAKEN attestations"},"stirShakenCert":{"type":"string","nullable":true},"attestationLevel":{"type":"string","enum":["A","B","C"],"nullable":true},"termsAcceptedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"submittedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["userId","legalBusinessName","contactName","contactEmail","contactPhone","frn","filer499Id","ocn","rmdRegistered","rmdReference","signsOwnTraffic","stirShakenCert","attestationLevel","termsAcceptedAt","submittedAt","updatedAt"]},"Notification":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"type":{"type":"string","description":"Machine-readable kind, e.g. webhook_failing, connection, route_check_failed"},"title":{"type":"string"},"message":{"type":"string"},"read":{"type":"boolean"},"data":{"type":"object","additionalProperties":{},"nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"severity":{"type":"string","enum":["info","warning","critical"],"description":"critical = something is broken and needs your action (a failing route, a suspension, traffic stopped)"},"link":{"type":"string","nullable":true,"description":"Dashboard path the notification opens, when it has one"},"occurrences":{"type":"integer","description":"How many events this notification groups (repeats update one notification instead of adding more)"},"lastEventAt":{"type":"string","format":"date-time","description":"When a grouped notification was last updated; null if never","nullable":true}},"required":["id","userId","type","title","message","read","data","createdAt","severity","link","occurrences","lastEventAt"]},"NotificationEmailPrefs":{"type":"object","properties":{"actionEmail":{"type":"boolean","description":"Email me about issues that need action: at most one email every 4 hours listing unread critical notifications"}},"required":["actionEmail"]},"SupportTicket":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid","nullable":true},"guestEmail":{"type":"string","nullable":true},"category":{"type":"string","description":"Ticket category, e.g. billing_dispute, technical_support, other"},"subject":{"type":"string"},"status":{"type":"string","enum":["open","in_progress","resolved","closed"]},"relatedRouteId":{"type":"string","format":"uuid","nullable":true},"relatedPurchaseId":{"type":"string","format":"uuid","nullable":true},"assignedTo":{"type":"string","format":"uuid","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"resolvedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true}},"required":["id","userId","guestEmail","category","subject","status","relatedRouteId","relatedPurchaseId","assignedTo","createdAt","resolvedAt"]},"SupportTicketMessage":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"authorId":{"type":"string","format":"uuid","nullable":true},"message":{"type":"string"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"authorName":{"type":"string","nullable":true}},"required":["id","authorId","message","createdAt"]},"StatusIncident":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"impact":{"type":"string","enum":["none","minor","major","critical"]},"status":{"type":"string","enum":["investigating","identified","monitoring","resolved"]},"componentIds":{"type":"array","items":{"type":"string"}},"startedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"resolvedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"updates":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["investigating","identified","monitoring","resolved"]},"body":{"type":"string"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","status","body","createdAt"]}}},"required":["id","title","impact","status","componentIds","startedAt","resolvedAt","updates"]},"StatusPage":{"type":"object","properties":{"generatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"overall":{"type":"object","properties":{"state":{"type":"string","enum":["operational","degraded","partial_outage","major_outage","maintenance"]},"message":{"type":"string"}},"required":["state","message"]},"groups":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"components":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"state":{"type":"string","enum":["operational","degraded","partial_outage","major_outage","maintenance"]},"uptime90d":{"type":"number","nullable":true,"description":"Percent over 90 days; null when there is no data"},"dataSince":{"type":"string","nullable":true},"days":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string","description":"YYYY-MM-DD"},"state":{"anyOf":[{"type":"string","enum":["operational","degraded","partial_outage","major_outage","maintenance"]},{"type":"string","enum":["no_data"]}]},"uptimePct":{"type":"number","nullable":true},"downtimeMinutes":{"type":"number","nullable":true},"incidents":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"impact":{"type":"string","enum":["none","minor","major","critical"]}},"required":["id","title","impact"]}}},"required":["date","state","uptimePct","downtimeMinutes","incidents"]}}},"required":["id","name","description","state","uptime90d","dataSince","days"]}}},"required":["id","name","components"]}},"activeIncidents":{"type":"array","items":{"$ref":"#/components/schemas/StatusIncident"}},"scheduledMaintenance":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"body":{"type":"string"},"componentIds":{"type":"array","items":{"type":"string"}},"scheduledStart":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"scheduledEnd":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"status":{"type":"string","enum":["scheduled","in_progress","completed"]}},"required":["id","title","body","componentIds","scheduledStart","scheduledEnd","status"]}},"pastIncidents":{"type":"array","items":{"$ref":"#/components/schemas/StatusIncident"}}},"required":["generatedAt","overall","groups","activeIncidents","scheduledMaintenance","pastIncidents"]},"WhitelistedIp":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"ipAddress":{"type":"string","description":"IPv4/IPv6 address, optionally with a CIDR suffix"},"label":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","userId","ipAddress","label","createdAt"]},"Interconnection":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"purchaseId":{"type":"string","format":"uuid"},"type":{"type":"string","enum":["sip","smpp","api"]},"buyerEndpoint":{"type":"object","additionalProperties":{},"nullable":true,"description":"Your own connection settings and credentials"},"sellerEndpoint":{"enum":["null"],"nullable":true,"description":"Always null: the seller endpoint is never shown to buyers"},"status":{"type":"string","enum":["active","inactive"]},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","purchaseId","type","buyerEndpoint","sellerEndpoint","status","createdAt","updatedAt"]},"ConnectionProfile":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"contactName":{"type":"string","nullable":true},"companyName":{"type":"string","nullable":true},"jobTitle":{"type":"string","nullable":true},"avatarUrl":{"type":"string","nullable":true},"logoUrl":{"type":"string","nullable":true},"country":{"type":"string","nullable":true},"verified":{"type":"boolean"},"memberSince":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","contactName","companyName","country","verified"]},"SubAccount":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"label":{"type":"string"},"externalRef":{"type":"string","nullable":true},"balance":{"$ref":"#/components/schemas/Money"},"status":{"type":"string","enum":["draft","active","suspended","closed"]},"markupPct":{"type":"string","nullable":true,"description":"Markup percent as a 3-decimal string; null = operator default"},"dailySpendCap":{"type":"string","nullable":true,"description":"null = operator default; \"0.00\" = unlimited"},"maxConcurrentCalls":{"type":"integer","nullable":true},"creditLimit":{"type":"string","description":"Postpaid credit, \"0.00\" = strict prepaid"},"currency":{"type":"string","minLength":3,"maxLength":3,"description":"Display currency for statements"},"portalEmail":{"type":"string","nullable":true},"autoSuspended":{"type":"boolean","description":"Suspended automatically by a daily cap, lifts itself"},"sipUsername":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","label","externalRef","balance","status","markupPct","dailySpendCap","maxConcurrentCalls","creditLimit","currency","portalEmail","autoSuspended","sipUsername","createdAt","updatedAt"]},"SubAccountCreated":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"label":{"type":"string"},"externalRef":{"type":"string","nullable":true},"balance":{"$ref":"#/components/schemas/Money"},"status":{"type":"string","enum":["draft","active","suspended","closed"]},"markupPct":{"type":"string","nullable":true,"description":"Markup percent as a 3-decimal string; null = operator default"},"dailySpendCap":{"type":"string","nullable":true,"description":"null = operator default; \"0.00\" = unlimited"},"maxConcurrentCalls":{"type":"integer","nullable":true},"creditLimit":{"type":"string","description":"Postpaid credit, \"0.00\" = strict prepaid"},"currency":{"type":"string","minLength":3,"maxLength":3,"description":"Display currency for statements"},"portalEmail":{"type":"string","nullable":true},"autoSuspended":{"type":"boolean","description":"Suspended automatically by a daily cap, lifts itself"},"sipUsername":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"apiKey":{"type":"string","description":"The sub-account API key. Returned ONCE."},"apiKeyPrefix":{"type":"string"},"sipPassword":{"type":"string","description":"The SIP password. Returned ONCE."}},"required":["id","label","externalRef","balance","status","markupPct","dailySpendCap","maxConcurrentCalls","creditLimit","currency","portalEmail","autoSuspended","sipUsername","createdAt","updatedAt","apiKey","apiKeyPrefix","sipPassword"]},"ApplicationSettings":{"type":"object","properties":{"operatorId":{"type":"string","format":"uuid"},"defaultMarkupPct":{"type":"string"},"defaultBillingIncrement":{"type":"string"},"minMarginPct":{"type":"string"},"subLowBalanceThreshold":{"type":"string","description":"\"0.00\" disables low-balance alerts"},"defaultDailySpendCap":{"type":"string","nullable":true,"description":"US dollars as a decimal string with 2 decimal places, e.g. \"50.00\""},"defaultMaxConcurrentCalls":{"type":"integer","nullable":true},"brandName":{"type":"string","nullable":true},"brandColor":{"type":"string","nullable":true},"brandLogoUrl":{"type":"string","nullable":true},"requireTrunkApproval":{"type":"boolean"},"requireTrunkReadiness":{"type":"boolean"}},"required":["operatorId","defaultMarkupPct","defaultBillingIncrement","minMarginPct","subLowBalanceThreshold","defaultDailySpendCap","defaultMaxConcurrentCalls","brandName","brandColor","brandLogoUrl","requireTrunkApproval","requireTrunkReadiness"],"additionalProperties":true},"RevshareNumber":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"number":{"type":"string"},"country":{"type":"string","nullable":true},"countryCode":{"type":"string","nullable":true},"carrier":{"type":"string","nullable":true},"rangeLabel":{"type":"string","nullable":true},"groupKey":{"type":"string"},"status":{"type":"string","enum":["available","taken","retired"]},"ratePerMin":{"allOf":[{"$ref":"#/components/schemas/Money"}],"description":"What you earn per minute at the best payment term"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","number","country","countryCode","carrier","rangeLabel","groupKey","status","ratePerMin","createdAt"]},"RevshareTaking":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"numberId":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"paymentTerm":{"type":"string","enum":["1_1","7_1","15_15"],"description":"Settlement term: earnings held 1, 7 or 15 days, then requestable any day; sets the rate (88%, 95%, 100%)"},"effectiveRate":{"allOf":[{"$ref":"#/components/schemas/Money"}],"description":"What you earn per minute on this number"},"ivrConfigId":{"type":"string","format":"uuid","nullable":true},"ivrMode":{"type":"string","enum":["single","split","geo"]},"status":{"type":"string","enum":["active","released"]},"callsCount":{"type":"integer"},"minutesTotal":{"type":"string"},"earningsTotal":{"$ref":"#/components/schemas/Money"},"lastCallAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"takenAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"releasedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true}},"required":["id","numberId","userId","paymentTerm","effectiveRate","ivrConfigId","ivrMode","status","callsCount","minutesTotal","earningsTotal","lastCallAt","takenAt","releasedAt"]},"RevsharePayout":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"amount":{"$ref":"#/components/schemas/Money"},"cryptoAsset":{"type":"string","nullable":true},"network":{"type":"string","nullable":true},"address":{"type":"string","nullable":true},"term":{"type":"string","enum":["1_1","7_1","15_15"],"description":"Settlement term: earnings held 1, 7 or 15 days, then requestable any day; sets the rate (88%, 95%, 100%)"},"status":{"type":"string","enum":["requested","approved","paid","rejected"]},"txRef":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"paidAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true}},"required":["id","amount","cryptoAsset","network","address","term","status","txRef","createdAt","paidAt"]},"RevshareIvrConfig":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"takingId":{"type":"string","format":"uuid","nullable":true},"kind":{"type":"string","enum":["default_music","upload","tts"]},"name":{"type":"string","nullable":true},"assetPath":{"type":"string","nullable":true},"assetMime":{"type":"string","nullable":true,"description":"Set when audio exists; stream it from the preview endpoint"},"ttsText":{"type":"string","nullable":true},"ttsVoiceId":{"type":"string","nullable":true},"status":{"type":"string","enum":["draft","active"]},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","userId","takingId","kind","name","assetPath","assetMime","ttsText","ttsVoiceId","status","createdAt"]},"RevshareIvrSet":{"type":"object","properties":{"mode":{"type":"string","enum":["single","split","geo"]},"variants":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"ivrConfigId":{"type":"string","format":"uuid"},"name":{"type":"string"},"kind":{"type":"string","enum":["default_music","upload","tts"],"nullable":true},"weightPct":{"type":"integer","nullable":true},"originIso":{"type":"string","nullable":true},"originCountry":{"type":"string","nullable":true},"enabled":{"type":"boolean","nullable":true}},"required":["id","ivrConfigId","name","kind","weightPct","originIso","originCountry","enabled"]}}},"required":["mode","variants"]},"RevshareDeliverySetting":{"type":"object","properties":{"mode":{"type":"string","enum":["greeting","switch","inherit"]},"host":{"type":"string","nullable":true},"port":{"type":"integer"},"transport":{"type":"string","enum":["udp","tcp"]},"prefix":{"type":"string","nullable":true},"numberFormat":{"type":"string","enum":["e164","plus","national"]},"maxChannels":{"type":"integer","nullable":true},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true}},"required":["mode","host","port","transport","prefix","numberFormat","maxChannels","updatedAt"]},"RevshareInterconnect":{"type":"object","properties":{"egressIps":{"type":"array","items":{"type":"string"},"description":"Our calls (signalling and media) come from these addresses: allow all of them"},"signallingPort":{"type":"integer"},"transports":{"type":"array","items":{"type":"string"}},"mediaIps":{"type":"array","items":{"type":"string"}},"rtpPortRange":{"type":"string"},"codecs":{"type":"array","items":{"type":"string"}},"dtmf":{"type":"string"},"ringTimeoutSec":{"type":"integer"},"callerId":{"type":"string"}},"required":["egressIps","signallingPort","transports","mediaIps","rtpPortRange","codecs","dtmf","ringTimeoutSec","callerId"]},"RevshareDeliveryTest":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"takingId":{"type":"string","format":"uuid","nullable":true},"dialled":{"type":"string"},"host":{"type":"string"},"port":{"type":"integer"},"transport":{"type":"string"},"answered":{"type":"boolean"},"sipCode":{"type":"integer","nullable":true},"reason":{"type":"string","nullable":true},"pddMs":{"type":"integer","nullable":true},"answerMs":{"type":"integer","nullable":true},"paths":{"type":"array","items":{"type":"object","properties":{"egressIp":{"type":"string","nullable":true},"answered":{"type":"boolean"},"sipCode":{"type":"integer","nullable":true},"reason":{"type":"string","nullable":true},"pddMs":{"type":"number","nullable":true},"answerMs":{"type":"number","nullable":true}},"required":["egressIp","answered","sipCode","reason","pddMs","answerMs"]}},"at":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","takingId","dialled","host","port","transport","answered","sipCode","reason","pddMs","answerMs","paths","at"]},"RevshareTestAllowance":{"type":"object","properties":{"perDay":{"type":"integer"},"perMonth":{"type":"integer"},"usedToday":{"type":"integer"},"usedThisMonth":{"type":"integer"},"remainingToday":{"type":"integer"},"remainingThisMonth":{"type":"integer"}},"required":["perDay","perMonth","usedToday","usedThisMonth","remainingToday","remainingThisMonth"]},"RevshareDeliverySettings":{"type":"object","properties":{"accountDefault":{"$ref":"#/components/schemas/RevshareDeliverySetting"},"overrides":{"type":"array","items":{"type":"object","properties":{"mode":{"type":"string","enum":["greeting","switch","inherit"]},"host":{"type":"string","nullable":true},"port":{"type":"integer"},"transport":{"type":"string","enum":["udp","tcp"]},"prefix":{"type":"string","nullable":true},"numberFormat":{"type":"string","enum":["e164","plus","national"]},"maxChannels":{"type":"integer","nullable":true},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"takingId":{"type":"string","format":"uuid"}},"required":["mode","host","port","transport","prefix","numberFormat","maxChannels","updatedAt","takingId"]}},"interconnect":{"$ref":"#/components/schemas/RevshareInterconnect"},"enabled":{"type":"boolean","description":"Whether delivery to your own switch is switched on for the platform"}},"required":["accountDefault","overrides","interconnect","enabled"]},"RevshareTakingDelivery":{"type":"object","properties":{"override":{"type":"object","properties":{"mode":{"type":"string","enum":["greeting","switch","inherit"]},"host":{"type":"string","nullable":true},"port":{"type":"integer"},"transport":{"type":"string","enum":["udp","tcp"]},"prefix":{"type":"string","nullable":true},"numberFormat":{"type":"string","enum":["e164","plus","national"]},"maxChannels":{"type":"integer","nullable":true},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true}},"required":["mode","host","port","transport","prefix","numberFormat","maxChannels","updatedAt"],"description":"This number's own setting; mode `inherit` when it follows the account default"},"accountDefault":{"$ref":"#/components/schemas/RevshareDeliverySetting"},"effective":{"type":"object","properties":{"mode":{"type":"string","enum":["greeting","switch"]},"source":{"type":"string","enum":["number","account","none"],"description":"Where the effective setting comes from: this number, the account default, or neither (our greeting)"},"host":{"type":"string","nullable":true},"port":{"type":"integer"},"transport":{"type":"string","enum":["udp","tcp"]}},"required":["mode","source","host","port","transport"],"additionalProperties":true},"recent":{"type":"array","items":{"type":"object","properties":{"outcome":{"type":"string","enum":["delivered","fallback","caller_hung_up"]},"reason":{"type":"string","nullable":true},"sipCode":{"type":"integer","nullable":true},"durationSec":{"type":"integer"},"at":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["outcome","reason","sipCode","durationSec","at"]},"description":"Last 10 delivery outcomes, newest first"},"interconnect":{"$ref":"#/components/schemas/RevshareInterconnect"}},"required":["override","accountDefault","effective","recent","interconnect"]},"RevshareLiveAccess":{"type":"object","properties":{"days":{"type":"integer"},"since":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"generatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"totals":{"type":"object","properties":{"calls":{"type":"integer"},"lastHourCalls":{"type":"integer"},"originCountries":{"type":"integer"},"destinationCountries":{"type":"integer"},"lastCallAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true}},"required":["calls","lastHourCalls","originCountries","destinationCountries","lastCallAt"]},"topOrigins":{"type":"array","items":{"type":"object","properties":{"iso":{"type":"string","nullable":true},"country":{"type":"string"},"calls":{"type":"integer"},"lastAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["iso","country","calls","lastAt"]}},"topDestinations":{"type":"array","items":{"type":"object","properties":{"iso":{"type":"string","nullable":true},"country":{"type":"string"},"calls":{"type":"integer"},"lastAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["iso","country","calls","lastAt"]}},"byType":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","enum":["mobile","fixed","premium","special","satellite","toll_free","unknown"]},"calls":{"type":"integer"}},"required":["type","calls"]}},"pairs":{"type":"array","items":{"type":"object","properties":{"fromIso":{"type":"string","nullable":true},"fromCountry":{"type":"string"},"fromLat":{"type":"number","nullable":true},"fromLng":{"type":"number","nullable":true},"toIso":{"type":"string","nullable":true},"toCountry":{"type":"string"},"toLat":{"type":"number","nullable":true},"toLng":{"type":"number","nullable":true},"calls":{"type":"integer"},"lastHour":{"type":"integer"},"lastAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["fromIso","fromCountry","fromLat","fromLng","toIso","toCountry","toLat","toLng","calls","lastHour","lastAt"]}},"rows":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"startedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"originPrefix":{"type":"string","description":"Leading digits of the caller, never the full number"},"originIso":{"type":"string","nullable":true},"originCountry":{"type":"string","nullable":true},"originNetwork":{"type":"string","nullable":true},"originType":{"type":"string","enum":["mobile","fixed","premium","special","satellite","toll_free","unknown"]},"destPrefix":{"type":"string","description":"Leading digits of the pool number, at least 4 digits hidden"},"destIso":{"type":"string","nullable":true},"destCountry":{"type":"string","nullable":true},"destNetwork":{"type":"string","nullable":true},"numberType":{"type":"string","enum":["mobile","fixed","premium","special","satellite","toll_free","unknown"]},"durationSec":{"type":"integer","nullable":true},"destFree":{"type":"integer","nullable":true,"description":"Numbers starting with destPrefix still free to take"}},"required":["id","startedAt","originPrefix","originIso","originCountry","originNetwork","originType","destPrefix","destIso","destCountry","destNetwork","numberType","durationSec","destFree"]}},"truncated":{"type":"boolean"}},"required":["days","since","generatedAt","totals","topOrigins","topDestinations","byType","pairs","rows","truncated"]}},"responses":{"BadRequest":{"description":"`VALIDATION_ERROR`, `INVALID_INPUT` or `BAD_REQUEST`. For `VALIDATION_ERROR`, `error.details` is an array of `{ path, message }`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Unauthorized":{"description":"`UNAUTHORIZED`: missing, invalid, expired or revoked credential.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Forbidden":{"description":"`FORBIDDEN`: not allowed: a scoped key lacks the scope, or the endpoint is session-only.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"NotFound":{"description":"`NOT_FOUND`: no such resource on your account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Conflict":{"description":"`CONFLICT` (or a code-specific 409): the change clashes with existing state.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"RateLimited":{"description":"`RATE_LIMITED`: slow down and retry after the `Retry-After` seconds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"ServerError":{"description":"`INTERNAL_ERROR`: unexpected failure. Quote `X-Request-Id` to support.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"ApprovalRequired":{"description":"Switch only: an approval policy holds this change for a second person. Nothing has been applied; approve it under Switch > Approvals.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"approvalRequired":{"type":"boolean","enum":[true]},"approvalRequestId":{"type":"string","format":"uuid","nullable":true},"permission":{"type":"string"},"expiresAt":{"type":"string","format":"date-time"},"message":{"type":"string"}}}}}}}}}},"paths":{"/api/v1/health":{"get":{"operationId":"getHealth","tags":["System"],"summary":"Check that the API is up","description":"Liveness probe. Answers 200 `{ status: \"ok\" }` while this node can reach its database, and 503 `{ status: \"unavailable\", reason: \"database_unreachable\" }` (with `success: false`) when it cannot.\n\n**Auth:** none (public endpoint).","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"status":{"type":"string","enum":["ok"]},"timestamp":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"version":{"type":"string"}},"required":["status","timestamp","version"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"public","security":[],"x-px-example":{"path":{},"query":{}}}},"/api/v1/health/status":{"get":{"operationId":"getHealthStatus","tags":["System"],"summary":"Get component health for the platform","description":"API, database, cache and call switch health, recomputed at most every 10 seconds.\n\n**Auth:** none (public endpoint).","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SystemHealth"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"public","security":[],"x-px-example":{"path":{},"query":{}}}},"/api/v1/account":{"get":{"operationId":"getAccount","tags":["Account"],"summary":"Get your account profile","description":"Profile, balance and account state. Secrets are never included.\n\n**Auth:** API key or JWT. Scoped keys need `account:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/AccountProfile"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}},"put":{"operationId":"putAccount","tags":["Account"],"summary":"Update your account profile","description":"Every field is optional; send only what changes. An empty string clears an optional text field. Session only because it can change the payout destination.\n\n**Auth:** dashboard session (JWT) only. API keys are refused with 403 so a leaked key can never perform this action.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/AccountProfile"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"session","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"companyName":{"type":"string","maxLength":255},"contactName":{"type":"string","minLength":1,"maxLength":255},"companyLogoUrl":{"type":"string","maxLength":400000},"jobTitle":{"type":"string","maxLength":120},"avatarUrl":{"type":"string","maxLength":400000},"phone":{"type":"string","maxLength":20},"country":{"type":"string","maxLength":2},"timezone":{"type":"string","maxLength":50},"taxId":{"type":"string","maxLength":64},"taxCountry":{"type":"string","maxLength":2},"payoutMethod":{"anyOf":[{"type":"string","enum":["crypto","wire"]},{"type":"string","enum":[""]}]},"payoutCryptoToken":{"type":"string","maxLength":20},"payoutCryptoNetwork":{"type":"string","maxLength":40},"payoutCryptoAddress":{"type":"string","maxLength":120},"payoutWireDetails":{"type":"string","maxLength":2000},"emailNotificationsOptOut":{"type":"boolean"}}}}}},"x-px-example":{"path":{},"query":{},"body":{"companyName":"Acme","contactName":"<contactName>"}}}},"/api/v1/account/activity":{"get":{"operationId":"getAccountActivity","tags":["Account"],"summary":"List recent security activity","description":"The latest 50 security events on the account (sign-ins, password and key changes), newest first.\n\n**Auth:** API key or JWT. Scoped keys need `account:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/AccountActivityEvent"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/account/export":{"get":{"operationId":"getAccountExport","tags":["Account"],"summary":"Export all your account data","description":"A data-protection export of everything held about the account. JSON by default (served as an attachment); `format=xlsx` returns a workbook with one sheet per dataset.\n\n**Auth:** API key or JWT. Scoped keys need `account:read`.","responses":{"200":{"description":"The export, one key per dataset. With format=xlsx the body is an .xlsx workbook instead.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","additionalProperties":{}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"format","in":"query","required":false,"schema":{"type":"string","enum":["json","xlsx","excel"]}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/account/balance":{"get":{"operationId":"getAccountBalance","tags":["Account"],"summary":"Get your balance and test credit","description":"**Auth:** API key or JWT. Scoped keys need `account:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/AccountBalance"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/account/switch-subscription":{"get":{"operationId":"getAccountSwitchSubscription","tags":["Account"],"summary":"Get your Switch plan and trial status","description":"Works without a Switch plan: this is how an account finds out it has none.\n\n**Auth:** API key or JWT. Scoped keys need `account:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/AccountSwitchEntitlement"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/account/api-usage":{"get":{"operationId":"getAccountApiUsage","tags":["API usage"],"summary":"Get API usage for your account or one key","description":"Request volume, error rate, p95 latency, per-day counts and top endpoints over a trailing window (default 7 days, max 90). Pass `keyId` to see one API key; omit it for all traffic including dashboard sessions.\n\n**Auth:** API key or JWT. Scoped keys need `account:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/ApiUsage"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"days","in":"query","required":false,"description":"Trailing window in days (1-90)","schema":{"type":"integer","minimum":1,"maximum":90,"default":7}},{"name":"keyId","in":"query","required":false,"description":"Only requests made with this API key (one of yours)","schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/account/api-keys":{"post":{"operationId":"postAccountApiKeys","tags":["API keys"],"summary":"Create an API key","description":"Returns the full key ONCE in `key`. Omit `scopes` for a full-access key; a scoped key can reach only the operations whose scope it holds. Scopes can be narrowed later but never broadened, so include everything the integration needs. A security email is sent to the account owner.\n\n**Auth:** dashboard session (JWT) only. API keys are refused with 403 so a leaked key can never perform this action.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/CreatedApiKey"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"session","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":100},"scopes":{"type":"array","items":{"type":"string","enum":["voice:send","sms:send","dialer:write","routes:read","account:read","purchases:write","offers:write","billing:write","numbers:read","numbers:write","account:write","routes:write","cdr:numbers","application:write","switch:manage","verify:write","webhooks:write","greetings:read","greetings:write","revshare:read","revshare:write"]},"minItems":1},"environment":{"type":"string","enum":["live","test"]},"expiresAt":{"type":"string","format":"date-time","nullable":true}},"required":["label"]}}}},"x-px-example":{"path":{},"query":{},"body":{"label":"Acme"}}},"get":{"operationId":"getAccountApiKeys","tags":["API keys"],"summary":"List your API keys","description":"Active (non-revoked) keys with their prefix, scopes and last use. Never includes a secret.\n\n**Auth:** dashboard session (JWT) only. API keys are refused with 403 so a leaked key can never perform this action.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/ApiKey"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"session","security":[{"bearerAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/account/api-keys/{id}":{"patch":{"operationId":"patchAccountApiKeysById","tags":["API keys"],"summary":"Rename an API key or narrow its scopes","description":"Scopes may only be tightened: any scope not already on the key is rejected with VALIDATION_ERROR.\n\n**Auth:** dashboard session (JWT) only. API keys are refused with 403 so a leaked key can never perform this action.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/ApiKey"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"session","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":100},"scopes":{"type":"array","items":{"type":"string","enum":["voice:send","sms:send","dialer:write","routes:read","account:read","purchases:write","offers:write","billing:write","numbers:read","numbers:write","account:write","routes:write","cdr:numbers","application:write","switch:manage","verify:write","webhooks:write","greetings:read","greetings:write","revshare:read","revshare:write"]},"minItems":1}}}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"label":"Acme","scopes":["voice:send"]}}},"delete":{"operationId":"deleteAccountApiKeysById","tags":["API keys"],"summary":"Revoke an API key","description":"Takes effect immediately; requests with the key then get 401.\n\n**Auth:** dashboard session (JWT) only. API keys are refused with 403 so a leaked key can never perform this action.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/Message"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"session","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/account/webhooks":{"get":{"operationId":"getAccountWebhooks","tags":["Webhooks"],"summary":"List your webhook endpoints","description":"Secrets are redacted to their last 4 characters.\n\n**Auth:** API key or JWT. Scoped keys need `account:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/Webhook"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}},"post":{"operationId":"postAccountWebhooks","tags":["Webhooks"],"summary":"Create a webhook endpoint","description":"The signing secret is returned ONCE in `secret`. URLs must be https and resolve to a public address. Works from a dashboard session, or with an API key that was created with the `webhooks:write` permission. A full-access key does not include `webhooks:write`: it has to be chosen explicitly, so keys issued before this permission existed cannot manage endpoints.\n\nEach delivery is a POST of `{ event, data, timestamp }` with headers `X-Webhook-Event`, `X-Webhook-Id` (the delivery id), `X-PX-Timestamp` (Unix seconds at send time) and two signatures: `X-PX-Signature: v1=<hex HMAC-SHA256 of \"<timestamp>.<raw body>\">` (verify this one, and reject timestamps more than 5 minutes old to stop replays) and the legacy `X-Webhook-Signature: sha256=<hex HMAC-SHA256 of the raw body>`, kept during the transition.\n\n**Auth:** API key or JWT. Scoped keys need `webhooks:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/WebhookWithSecret"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"webhooks:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"events":{"type":"array","items":{"type":"string","enum":["call.completed","call.ringing","call.answered","call.gathered","sms.sent","sms.dlr","sms.delivered","sms.failed","campaign.started","campaign.completed","topup.confirmed","balance.low","offer.received","route.purchased","sub_account.balance_low","sub_account.suspended","sub_account.resumed","sub_account.topup_requested","number.call.received","number.sms.received","number.voicemail.received","verification.approved","verification.expired","invoice.created","invoice.issued","invoice.sent","invoice.voided","invoice.reissued","invoice.payment","credit_note.issued","payable.created","netting.run","sell_rate.changed","cost_rate.scheduled","cost_rate.activated","cost_rate.rolled_back","sub_account.margin_below_floor","revshare.call.received","revshare.number.taken","revshare.number.released","ping"]},"minItems":1}},"required":["url","events"]}}}},"x-px-example":{"path":{},"query":{},"body":{"url":"https://example.com/webhooks/packetexchange","events":["call.completed"]}}}},"/api/v1/account/webhooks/{id}":{"patch":{"operationId":"patchAccountWebhooksById","tags":["Webhooks"],"summary":"Update a webhook endpoint","description":"Change the URL, the subscribed events or `isActive`. The signing secret and delivery history are kept. Works from a dashboard session, or with an API key that was created with the `webhooks:write` permission. A full-access key does not include `webhooks:write`: it has to be chosen explicitly, so keys issued before this permission existed cannot manage endpoints.\n\n**Auth:** API key or JWT. Scoped keys need `webhooks:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/Webhook"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"webhooks:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"events":{"type":"array","items":{"type":"string","enum":["call.completed","call.ringing","call.answered","call.gathered","sms.sent","sms.dlr","sms.delivered","sms.failed","campaign.started","campaign.completed","topup.confirmed","balance.low","offer.received","route.purchased","sub_account.balance_low","sub_account.suspended","sub_account.resumed","sub_account.topup_requested","number.call.received","number.sms.received","number.voicemail.received","verification.approved","verification.expired","invoice.created","invoice.issued","invoice.sent","invoice.voided","invoice.reissued","invoice.payment","credit_note.issued","payable.created","netting.run","sell_rate.changed","cost_rate.scheduled","cost_rate.activated","cost_rate.rolled_back","sub_account.margin_below_floor","revshare.call.received","revshare.number.taken","revshare.number.released","ping"]},"minItems":1},"isActive":{"type":"boolean"}}}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"url":"https://example.com/webhooks/packetexchange","events":["call.completed"]}}},"delete":{"operationId":"deleteAccountWebhooksById","tags":["Webhooks"],"summary":"Delete a webhook endpoint","description":"Removes the endpoint, its secret and its delivery history. Events stop immediately. Works from a dashboard session, or with an API key that was created with the `webhooks:write` permission. A full-access key does not include `webhooks:write`: it has to be chosen explicitly, so keys issued before this permission existed cannot manage endpoints.\n\n**Auth:** API key or JWT. Scoped keys need `webhooks:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"deleted":{"type":"boolean","enum":[true]}},"required":["id","deleted"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"webhooks:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/account/webhooks/{id}/rotate-secret":{"post":{"operationId":"postAccountWebhooksByIdRotateSecret","tags":["Webhooks"],"summary":"Rotate a webhook signing secret","description":"Issues a new secret, returned once. Deliveries are signed with it from this moment (including pending retries); there is no overlap window, so update your receiver at the same time. Works from a dashboard session, or with an API key that was created with the `webhooks:write` permission. A full-access key does not include `webhooks:write`: it has to be chosen explicitly, so keys issued before this permission existed cannot manage endpoints.\n\n**Auth:** API key or JWT. Scoped keys need `webhooks:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"url":{"type":"string","format":"uri"},"secretLast4":{"type":"string","description":"Last 4 characters of the signing secret, to tell secrets apart"},"events":{"type":"array","items":{"type":"string","enum":["call.completed","call.ringing","call.answered","call.gathered","sms.sent","sms.dlr","sms.delivered","sms.failed","campaign.started","campaign.completed","topup.confirmed","balance.low","offer.received","route.purchased","sub_account.balance_low","sub_account.suspended","sub_account.resumed","sub_account.topup_requested","number.call.received","number.sms.received","number.voicemail.received","verification.approved","verification.expired","invoice.created","invoice.issued","invoice.sent","invoice.voided","invoice.reissued","invoice.payment","credit_note.issued","payable.created","netting.run","sell_rate.changed","cost_rate.scheduled","cost_rate.activated","cost_rate.rolled_back","sub_account.margin_below_floor","revshare.call.received","revshare.number.taken","revshare.number.released","ping"]}},"isActive":{"type":"boolean","description":"False when you disabled it, or after sustained delivery failures"},"failureCount":{"type":"integer","description":"Consecutive failed deliveries; resets on success"},"lastDeliveryAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"secret":{"type":"string","description":"The signing secret. Returned ONCE; store it now."},"message":{"type":"string"}},"required":["id","url","secretLast4","events","isActive","failureCount","lastDeliveryAt","createdAt","updatedAt","secret","message"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"webhooks:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/account/webhooks/{id}/test":{"post":{"operationId":"postAccountWebhooksByIdTest","tags":["Webhooks"],"summary":"Send a test ping to a webhook endpoint","description":"Queues a `ping` delivery, signed like any other, usually delivered within 15 seconds.\n\n**Auth:** API key or JWT. Scoped keys need `account:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"202":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["pending","sending","delivered","failed"]},"event":{"type":"string","enum":["ping"]}},"required":["id","status","event"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/account/webhooks/{id}/deliveries":{"get":{"operationId":"getAccountWebhooksByIdDeliveries","tags":["Webhooks"],"summary":"List deliveries for one webhook endpoint","description":"**Auth:** API key or JWT. Scoped keys need `account:read`.","responses":{"200":{"description":"One page of results, newest first.","content":{"application/json":{"schema":{"type":"object","required":["success","data","nextCursor","hasMore"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/WebhookDelivery"}},"nextCursor":{"type":"string","nullable":true,"description":"Pass as `cursor` to fetch the next page; null on the last page."},"hasMore":{"type":"boolean","description":"True when another page exists."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"cursor","in":"query","required":false,"description":"The `nextCursor` from the previous page","schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":20}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/account/webhooks/deliveries":{"get":{"operationId":"getAccountWebhooksDeliveries","tags":["Webhooks"],"summary":"List webhook deliveries across all your endpoints","description":"Newest first. Filter by endpoint, status or event. Includes the endpoint URL on each row.\n\n**Auth:** API key or JWT. Scoped keys need `account:read`.","responses":{"200":{"description":"One page of results, newest first.","content":{"application/json":{"schema":{"type":"object","required":["success","data","nextCursor","hasMore"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/WebhookDelivery"}},"nextCursor":{"type":"string","nullable":true,"description":"Pass as `cursor` to fetch the next page; null on the last page."},"hasMore":{"type":"boolean","description":"True when another page exists."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"cursor","in":"query","required":false,"description":"The `nextCursor` from the previous page","schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"webhookId","in":"query","required":false,"description":"Only deliveries to this endpoint","schema":{"type":"string","format":"uuid"}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["pending","sending","delivered","failed"]}},{"name":"event","in":"query","required":false,"description":"Only this event name, e.g. call.completed","schema":{"type":"string","maxLength":80}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/account/webhooks/deliveries/{deliveryId}":{"get":{"operationId":"getAccountWebhooksDeliveriesByDeliveryId","tags":["Webhooks"],"summary":"Get one webhook delivery, with its payload","description":"**Auth:** API key or JWT. Scoped keys need `account:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Also sent as the X-Webhook-Id header. Automatic retries reuse it (de-duplicate on it); a manual resend is a new delivery with a new id."},"webhookId":{"type":"string","format":"uuid","description":"Present on the account-wide list"},"url":{"type":"string","description":"The endpoint URL, on the account-wide list"},"event":{"type":"string"},"status":{"type":"string","enum":["pending","sending","delivered","failed"]},"httpStatus":{"type":"integer","nullable":true,"description":"Response code your server returned on the last attempt"},"attempts":{"type":"integer","description":"Attempts so far (max 5, with attempts^2-minute backoff)"},"lastError":{"type":"string","nullable":true},"nextRetryAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"deliveredAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"payload":{"type":"object","additionalProperties":{},"description":"The exact JSON body that was (or will be) POSTed"}},"required":["id","event","status","httpStatus","attempts","lastError","nextRetryAt","createdAt","deliveredAt","payload"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"deliveryId","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"deliveryId":"<deliveryId>"},"query":{}}}},"/api/v1/account/webhooks/deliveries/{deliveryId}/resend":{"post":{"operationId":"postAccountWebhooksDeliveriesByDeliveryIdResend","tags":["Webhooks"],"summary":"Resend a webhook delivery","description":"Queues a NEW delivery with the same event and payload to the same endpoint, signed with a fresh timestamp. The original delivery is left as it was, so the history shows both. The new delivery has its own id (X-Webhook-Id); the payload is byte-identical, so de-duplicate on your own event data if you need exactly-once processing. The endpoint must be active.\n\n**Auth:** API key or JWT. Scoped keys need `account:write`.\n\n**Rate limit:** 30 requests per minute per caller.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"202":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/WebhookDelivery"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:write","x-rate-limit":{"max":30,"window":"minute"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"deliveryId","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"deliveryId":"<deliveryId>"},"query":{}}}},"/api/v1/account/alerts":{"get":{"operationId":"getAccountAlerts","tags":["Account"],"summary":"Get your spend alert settings","description":"Defaults (no thresholds, email on) when nothing has been saved.\n\n**Auth:** API key or JWT. Scoped keys need `account:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/AccountSpendAlerts"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}},"put":{"operationId":"putAccountAlerts","tags":["Account"],"summary":"Update your spend alert settings","description":"Send at least one field. Thresholds are USD amounts; null removes one.\n\n**Auth:** API key or JWT. Scoped keys need `account:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/AccountSpendAlerts"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"lowBalanceThreshold":{"type":"number","minimum":0,"nullable":true},"dailySpendCap":{"type":"number","minimum":0,"nullable":true},"notifyEmail":{"type":"boolean"}}}}}},"x-px-example":{"path":{},"query":{},"body":{"lowBalanceThreshold":1,"dailySpendCap":1}}}},"/api/v1/account/destination-alerts":{"get":{"operationId":"getAccountDestinationAlerts","tags":["Account"],"summary":"List the destinations you follow","description":"You hear about new listings, lower prices and routes reaching International CLI for each one: in-app, plus one daily email.\n\n**Auth:** API key or JWT. Scoped keys need `account:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/AccountDestinationAlert"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}},"post":{"operationId":"postAccountDestinationAlerts","tags":["Account"],"summary":"Follow a destination","description":"One country (not a multi-country deck) and Voice or SMS. Following one you already follow returns it unchanged. Buying a route follows its destination unless the purchase sends alertsForDestination: false.\n\n**Auth:** API key or JWT. Scoped keys need `account:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/AccountDestinationAlert"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"country":{"type":"string","minLength":1,"maxLength":100},"trafficType":{"type":"string","enum":["voice","sms"]}},"required":["country","trafficType"]}}}},"x-px-example":{"path":{},"query":{},"body":{"country":"United Kingdom","trafficType":"voice"}}}},"/api/v1/account/destination-alerts/{id}":{"delete":{"operationId":"deleteAccountDestinationAlertsById","tags":["Account"],"summary":"Stop following a destination","description":"**Auth:** API key or JWT. Scoped keys need `account:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"}},"required":["id"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/routes":{"get":{"operationId":"getRoutes","tags":["Marketplace routes"],"summary":"Browse the route marketplace","description":"Public. Every row is anonymous: no seller name, id or endpoint. Listing rows carry `trend` (calls per day, last 7 UTC days, oldest first; null with no traffic) and every row `listingTrend` (the listing's own series; on rows=network it is the whole listing, not that network). Signed-in callers get the full `stats` block; anonymous callers get counts only. Money fields are 6-decimal USD strings. Each row carries `measured` (ASR, ACD, NER and PDD measured from real calls, or null) beside the seller-stated `expectedAsr`/`expectedAcd`/`expectedPdd`; anonymous callers get the attempt count as a band and no buyer count. Sort by measured quality with `sort=measured_asr_desc|measured_asr_asc|measured_acd_desc|measured_acd_asc|ner_desc|ner_asc`, or `quality_desc` (measured NER then ASR where measured, else stated ASR): listings with measured figures come first. Every view is ordered by `verification` tier first (International CLI, NCLI, Qualified, Untested), then by the chosen sort; `verification=cli|ncli|connected|not_verified` narrows to one tier (voice routes only). Omitted, every tier is listed. `originPolicy=dual` lists routes with a separate caller ID origin price (for example a lower price for an EEA caller ID), `originPolicy=origin_only` routes that take only caller IDs from their origin group; `stats.originFacets` counts each option.\n\n**Auth:** optional. Works anonymously; a token or API key personalises the answer.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/MarketplaceRoute"}},"nextCursor":{"type":"string","nullable":true},"hasMore":{"type":"boolean"},"total":{"type":"integer","description":"Routes matching the filters across all pages"},"stats":{"$ref":"#/components/schemas/MarketplaceStats"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"optional","security":[{},{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"type","in":"query","required":false,"schema":{"type":"string","enum":["voice","sms"]}},{"name":"country","in":"query","required":false,"schema":{"type":"string"}},{"name":"countryCode","in":"query","required":false,"schema":{"type":"string"}},{"name":"cliType","in":"query","required":false,"schema":{"type":"string","enum":["full_cli","local_cli","mixed_cli","ncli","partial_cli"]}},{"name":"lineType","in":"query","required":false,"schema":{"type":"string","enum":["mobile_and_fixed","mobile","fixed"]}},{"name":"routeType","in":"query","required":false,"schema":{"type":"string","enum":["direct","premium","standard","ncli"]}},{"name":"minPrice","in":"query","required":false,"schema":{"type":"string"}},{"name":"maxPrice","in":"query","required":false,"schema":{"type":"string"}},{"name":"minAsr","in":"query","required":false,"schema":{"type":"string"}},{"name":"minAcd","in":"query","required":false,"schema":{"type":"string"}},{"name":"maxPdd","in":"query","required":false,"schema":{"type":"string"}},{"name":"minScore","in":"query","required":false,"schema":{"type":"integer","minimum":0,"maximum":100}},{"name":"minCapacity","in":"query","required":false,"schema":{"type":"integer","minimum":0}},{"name":"billing","in":"query","required":false,"schema":{"type":"string","enum":["per_second","per_minute"]}},{"name":"wholesale","in":"query","required":false,"schema":{"type":"string","enum":["true","false"]}},{"name":"callcenter","in":"query","required":false,"schema":{"type":"string","enum":["true","false"]}},{"name":"retail","in":"query","required":false,"schema":{"type":"string","enum":["true","false"]}},{"name":"otp","in":"query","required":false,"schema":{"type":"string","enum":["true","false"]}},{"name":"openRtp","in":"query","required":false,"schema":{"type":"string","enum":["true","false"]}},{"name":"dialer","in":"query","required":false,"schema":{"type":"string","enum":["true","false"]}},{"name":"a2p","in":"query","required":false,"schema":{"type":"string","enum":["true","false"]}},{"name":"bundlesOnly","in":"query","required":false,"schema":{"type":"string","enum":["true","false"]}},{"name":"verification","in":"query","required":false,"schema":{"type":"string","enum":["cli","ncli","connected","not_verified"]}},{"name":"originPolicy","in":"query","required":false,"schema":{"type":"string","enum":["any","dual","origin_only"]}},{"name":"originGroup","in":"query","required":false,"schema":{"type":"string","pattern":"^[A-Za-z0-9_]{1,16}$"}},{"name":"search","in":"query","required":false,"schema":{"type":"string"}},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["price_asc","price_desc","asr_desc","asr_asc","acd_desc","acd_asc","pdd_asc","pdd_desc","capacity_desc","created_desc","country_asc","score_desc","score_asc","measured_asr_desc","measured_asr_asc","measured_acd_desc","measured_acd_asc","ner_desc","ner_asc","quality_desc"]}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"x-px-example":{"path":{},"query":{}}},"post":{"operationId":"postRoutes","tags":["Marketplace routes"],"summary":"List a new route for sale","description":"**Auth:** API key or JWT. Scoped keys need `routes:write`.\n\n**Rate limit:** 30 requests per minute per caller.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/OwnRoute"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:write","x-rate-limit":{"max":30,"window":"minute"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"type":{"type":"string","enum":["voice","sms"]},"country":{"type":"string","minLength":1,"maxLength":100},"countryCode":{"type":"string","pattern":"^\\d{1,3}$"},"prefix":{"type":"array","items":{"type":"string","minLength":1,"maxLength":15},"maxItems":100},"destinationName":{"type":"string","minLength":1,"maxLength":255},"pricePerUnit":{"type":"string","pattern":"^\\d{1,6}\\.\\d{1,6}$"},"cliType":{"type":"string","enum":["full_cli","local_cli","mixed_cli","ncli","partial_cli"]},"lineType":{"type":"string","enum":["mobile_and_fixed","mobile","fixed"]},"capacity":{"type":"integer","exclusiveMinimum":true,"minimum":0,"maximum":1000000},"expectedAsr":{"type":"string","pattern":"^(\\d{1,5}(\\.\\d{1,2})?)?$"},"expectedAcd":{"type":"string","pattern":"^(\\d{1,5}(\\.\\d{1,2})?)?$"},"expectedPdd":{"type":"string","pattern":"^(\\d{1,5}(\\.\\d{1,2})?)?$"},"minAsr":{"type":"string","pattern":"^(\\d{1,5}(\\.\\d{1,2})?)?$","nullable":true},"minAcd":{"type":"integer","minimum":0,"nullable":true},"billingIncrement":{"type":"string","pattern":"^\\d{1,4}\\/\\d{1,4}$"},"routeType":{"type":"string","enum":["direct","premium","standard","ncli"]},"wholesaleCompatible":{"type":"boolean","default":true},"callcenterCompatible":{"type":"boolean","default":true},"dialerCompatible":{"type":"boolean","default":true},"retailCompatible":{"type":"boolean","default":true},"otpCompatible":{"type":"boolean","default":true},"openRtp":{"type":"boolean","default":false},"visibility":{"type":"string","enum":["public","private"],"default":"public"},"jingleEnabled":{"type":"boolean","default":false},"jingleApiUrl":{"type":"string","format":"uri","nullable":true},"smsDeliveryUrl":{"type":"string","format":"uri","nullable":true},"smsDeliveryMethod":{"type":"string","enum":["http","smpp","http_form"]},"smsApiKey":{"type":"string","maxLength":256,"nullable":true},"smppHost":{"type":"string","nullable":true},"smppPort":{"type":"integer","minimum":1,"maximum":65535,"nullable":true},"smppSystemId":{"type":"string","nullable":true},"smppPassword":{"type":"string","maxLength":64,"nullable":true},"smppBindType":{"type":"string","enum":["transceiver","transmitter"],"nullable":true},"smppSystemType":{"type":"string","maxLength":13,"nullable":true},"smppTps":{"type":"integer","minimum":1,"maximum":1000,"nullable":true},"smppSourceTon":{"type":"integer","minimum":0,"maximum":6,"nullable":true},"smppSourceNpi":{"type":"integer","minimum":0,"maximum":18,"nullable":true},"smppDestTon":{"type":"integer","minimum":0,"maximum":6,"nullable":true},"smppDestNpi":{"type":"integer","minimum":0,"maximum":18,"nullable":true},"jingleSipIp":{"type":"string","nullable":true},"sipPort":{"type":"integer","minimum":1,"maximum":65535,"nullable":true},"sipAuthUsername":{"type":"string","maxLength":128,"nullable":true},"sipAuthPassword":{"type":"string","maxLength":128,"nullable":true},"techPrefix":{"type":"string","pattern":"^[0-9#*]{1,20}$","nullable":true},"numberFormat":{"anyOf":[{"type":"object","properties":{"mode":{"type":"string","enum":["international"]}},"required":["mode"]},{"type":"object","properties":{"mode":{"type":"string","enum":["international_plus"]}},"required":["mode"]},{"type":"object","properties":{"mode":{"type":"string","enum":["national"]},"nationalPrefix":{"type":"string","pattern":"^[0-9#*]{0,10}$"}},"required":["mode","nationalPrefix"]},{"type":"object","properties":{"mode":{"type":"string","enum":["custom"]},"strip":{"type":"integer","minimum":0,"maximum":10},"add":{"type":"string","pattern":"^[0-9#*]{0,20}$"}},"required":["mode","strip","add"]}],"nullable":true},"fixedCli":{"type":"string","pattern":"^\\+?[0-9]{4,16}$","nullable":true},"cliFormat":{"type":"string","enum":["plus","digits"],"nullable":true},"originPolicy":{"type":"string","enum":["any","dual","origin_only"]},"originGroup":{"type":"string","pattern":"^[A-Za-z0-9_]{1,16}$","nullable":true},"callerIdRequired":{"type":"boolean"},"t38Support":{"type":"boolean","default":false},"supportedCodecs":{"type":"array","items":{"type":"string","maxLength":30},"maxItems":20},"maxCallDuration":{"type":"integer","exclusiveMinimum":true,"minimum":0},"smsType":{"type":"string","enum":["a2p","p2p","both"]},"smsDlrSupport":{"type":"boolean"},"smsConcatSupport":{"type":"boolean"},"smsSenderIdType":{"type":"string","enum":["alphanumeric","numeric","preregistered"]},"smsContentRestrictions":{"type":"string"},"smsRouteQuality":{"type":"string","enum":["hq","direct","aggregator","sim"],"nullable":true},"smsSenderIdBehavior":{"type":"string","enum":["alphanumeric_preserved","numeric_long","overwritten","not_guaranteed"],"nullable":true},"smsDlrLevel":{"type":"string","enum":["real_operator","intermediate","submit_only","none"],"nullable":true},"smsDlrPercent":{"type":"string","pattern":"^(\\d{1,5}(\\.\\d{1,2})?)?$","nullable":true},"smsUnicodeSupport":{"type":"boolean","nullable":true},"smsAcceptedTraffic":{"type":"array","items":{"type":"string","enum":["wholesale","transactional","otp","marketing","promo_shortcode"]},"nullable":true},"timeOfDayPricing":{"type":"object","additionalProperties":{"type":"string"}},"notes":{"type":"string","maxLength":2000}},"required":["type","country","countryCode","prefix","destinationName","pricePerUnit","cliType","capacity","billingIncrement","routeType"]}}}},"x-px-example":{"path":{},"query":{},"body":{"type":"voice","country":"United Kingdom","countryCode":"GB","prefix":["44"],"destinationName":"<destinationName>","pricePerUnit":"<pricePerUnit>","cliType":"full_cli","capacity":1,"billingIncrement":"<billingIncrement>","routeType":"direct"}}}},"/api/v1/routes/stats":{"get":{"operationId":"getRoutesStats","tags":["Marketplace routes"],"summary":"Get marketplace totals for a filter","description":"Same filters as the listing. Anonymous callers get counts only; price, ASR, score and capacity figures need a signed-in caller.\n\n**Auth:** optional. Works anonymously; a token or API key personalises the answer.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/MarketplaceStats"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"optional","security":[{},{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"type","in":"query","required":false,"schema":{"type":"string","enum":["voice","sms"]}},{"name":"country","in":"query","required":false,"schema":{"type":"string"}},{"name":"countryCode","in":"query","required":false,"schema":{"type":"string"}},{"name":"cliType","in":"query","required":false,"schema":{"type":"string","enum":["full_cli","local_cli","mixed_cli","ncli","partial_cli"]}},{"name":"lineType","in":"query","required":false,"schema":{"type":"string","enum":["mobile_and_fixed","mobile","fixed"]}},{"name":"routeType","in":"query","required":false,"schema":{"type":"string","enum":["direct","premium","standard","ncli"]}},{"name":"minPrice","in":"query","required":false,"schema":{"type":"string"}},{"name":"maxPrice","in":"query","required":false,"schema":{"type":"string"}},{"name":"minAsr","in":"query","required":false,"schema":{"type":"string"}},{"name":"minAcd","in":"query","required":false,"schema":{"type":"string"}},{"name":"maxPdd","in":"query","required":false,"schema":{"type":"string"}},{"name":"minScore","in":"query","required":false,"schema":{"type":"integer","minimum":0,"maximum":100}},{"name":"minCapacity","in":"query","required":false,"schema":{"type":"integer","minimum":0}},{"name":"billing","in":"query","required":false,"schema":{"type":"string","enum":["per_second","per_minute"]}},{"name":"wholesale","in":"query","required":false,"schema":{"type":"string","enum":["true","false"]}},{"name":"callcenter","in":"query","required":false,"schema":{"type":"string","enum":["true","false"]}},{"name":"retail","in":"query","required":false,"schema":{"type":"string","enum":["true","false"]}},{"name":"otp","in":"query","required":false,"schema":{"type":"string","enum":["true","false"]}},{"name":"openRtp","in":"query","required":false,"schema":{"type":"string","enum":["true","false"]}},{"name":"dialer","in":"query","required":false,"schema":{"type":"string","enum":["true","false"]}},{"name":"a2p","in":"query","required":false,"schema":{"type":"string","enum":["true","false"]}},{"name":"bundlesOnly","in":"query","required":false,"schema":{"type":"string","enum":["true","false"]}},{"name":"verification","in":"query","required":false,"schema":{"type":"string","enum":["cli","ncli","connected","not_verified"]}},{"name":"originPolicy","in":"query","required":false,"schema":{"type":"string","enum":["any","dual","origin_only"]}},{"name":"originGroup","in":"query","required":false,"schema":{"type":"string","pattern":"^[A-Za-z0-9_]{1,16}$"}},{"name":"search","in":"query","required":false,"schema":{"type":"string"}},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["price_asc","price_desc","asr_desc","asr_asc","acd_desc","acd_asc","pdd_asc","pdd_desc","capacity_desc","created_desc","country_asc","score_desc","score_asc","measured_asr_desc","measured_asr_asc","measured_acd_desc","measured_acd_asc","ner_desc","ner_asc","quality_desc"]}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/routes/price-number":{"get":{"operationId":"getRoutesPriceNumber","tags":["Marketplace routes"],"summary":"Price a phone number across the marketplace","description":"Every buyer-visible route that serves the number, at the rate it would actually charge for it, cheapest first. A route with a rate sheet is priced by its longest matching active prefix (if that row is blocked the route does not serve the number); a single-price route serves it when a listed prefix, or failing that its country code, starts the number. This is the public list price: negotiated prices and private grants are not applied. SMS prices are by destination network on routes that price a country per mobile network: `network` says which network `rate` is for and `countryRate` is the price for other or unknown networks. The network is determined from the number's range (ported numbers may be priced at the network the range belongs to). The number is normalised to digits (a leading 00 is dropped). At most 100 routes are returned; `total` counts all of them. An embargoed destination returns no routes and `notice: \"sanctioned\"`. Seller identities are never included.\n\n**Auth:** optional. Works anonymously; a token or API key personalises the answer.\n\n**Rate limit:** 30 requests per minute per caller.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/PriceNumberResult"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"optional","x-rate-limit":{"max":30,"window":"minute"},"security":[{},{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"number","in":"query","required":true,"description":"A full number or dial code, any formatting","schema":{"type":"string","minLength":1,"maxLength":32}},{"name":"type","in":"query","required":false,"schema":{"type":"string","enum":["voice","sms"],"default":"voice"}}],"x-px-example":{"path":{},"query":{"number":"+447700900123"}}}},"/api/v1/routes/market-feed":{"get":{"operationId":"getRoutesMarketFeed","tags":["Marketplace routes"],"summary":"Recent market events (ticker)","description":"New listings, verification results per destination network and list-price changes on the public marketplace, newest first, at most two per listing. Anonymous: no seller identity, only the platform listing reference. Cached for a minute.\n\n**Auth:** none (public endpoint).\n\n**Rate limit:** 60 requests per minute per caller.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"events":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","enum":["listed","verified_cli","verified_ncli","verified","price_drop","price_rise"]},"at":{"type":"string","format":"date-time","description":"Truncated to the minute"},"routeId":{"type":"string","format":"uuid"},"listingRef":{"type":"string"},"type":{"type":"string","enum":["voice","sms"]},"destination":{"type":"string"},"countryCode":{"type":"string","nullable":true},"network":{"type":"string","nullable":true,"description":"Destination network (verification events)"},"tier":{"type":"string","enum":["cli","ncli","connected","not_verified"],"nullable":true},"price":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"US dollars as a decimal string with exactly 6 decimal places, e.g. \"0.012500\". Do money arithmetic with a decimal type, not floating point."},"previousPrice":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"US dollars as a decimal string with exactly 6 decimal places, e.g. \"0.012500\". Do money arithmetic with a decimal type, not floating point."}},"required":["kind","at","routeId","listingRef","type","destination","countryCode","network","tier","price","previousPrice"]}},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["events","updatedAt"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"public","x-rate-limit":{"max":60,"window":"minute"},"security":[],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":50,"default":20}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/routes/countries":{"get":{"operationId":"getRoutesCountries","tags":["Marketplace routes"],"summary":"List destinations on the marketplace","description":"Every country with at least one live public route, with its route count, A to Z.\n\n**Auth:** none (public endpoint).","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"country":{"type":"string"},"countryCode":{"type":"string"},"count":{"type":"integer"}},"required":["country","countryCode","count"]}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"public","security":[],"x-px-example":{"path":{},"query":{}}}},"/api/v1/routes/{id}":{"get":{"operationId":"getRoutesById","tags":["Marketplace routes"],"summary":"Get a route","description":"Public for live public routes. The seller gets the full owner view; a granted buyer sees a private route; any other signed-in caller gets an access stub for a private route. Carries `measured` (quality measured from real calls, or null) and `routeChecks` (the last 7 days of route checks, or null).\n\n**Auth:** optional. Works anonymously; a token or API key personalises the answer.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"anyOf":[{"$ref":"#/components/schemas/MarketplaceRoute"},{"$ref":"#/components/schemas/OwnRoute"},{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"destinationName":{"type":"string","description":"The listing name. For anyone but the seller it is GENERATED by the platform from its own data, never the seller's text: \"<Country> <Operator?> <Mobile|Fixed|All Networks>\" for one destination (e.g. \"Niger Mobile\", \"Kenya Safaricom Mobile\"), \"A-Z Voice · <tier> · <CLI> · Ref XXXX\" or \"A-Z SMS · <quality> · Ref XXXX\" for an A-Z bundle. The seller sees the name they gave it."},"listingRef":{"type":"string","description":"Anonymous short reference of the listing (4 characters, e.g. \"7K2Q\"): stable for the life of the listing, unique enough to tell two same-named listings apart, and derived from the listing alone (it says nothing about the seller). Absent on your own listings."},"country":{"type":"string"},"countryCode":{"type":"string"},"type":{"type":"string","enum":["voice","sms"]},"visibility":{"type":"string","enum":["private"]},"accessRequired":{"type":"boolean","enum":[true]},"accessRequestPending":{"type":"boolean"}},"required":["id","destinationName","listingRef","country","countryCode","type","visibility","accessRequired","accessRequestPending"],"description":"Returned instead of the route when it is private and you have not been granted access"}]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"optional","security":[{},{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}},"put":{"operationId":"putRoutesById","tags":["Marketplace routes"],"summary":"Update a route you listed","description":"The price of an ACTIVE route cannot change in place (400 VALIDATION_ERROR): schedule the change with POST /routes/{id}/rate-changes/flat, or pause the route first. On a paused route a price increase pauses buyers who pay the list rate until they accept it (see POST /purchases/{id}/accept-rate).\n\n**Auth:** API key or JWT. Scoped keys need `routes:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/OwnRoute"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"type":{"type":"string","enum":["voice","sms"]},"country":{"type":"string","minLength":1,"maxLength":100},"countryCode":{"type":"string","pattern":"^\\d{1,3}$"},"prefix":{"type":"array","items":{"type":"string","minLength":1,"maxLength":15},"maxItems":100},"destinationName":{"type":"string","minLength":1,"maxLength":255},"pricePerUnit":{"type":"string","pattern":"^\\d{1,6}\\.\\d{1,6}$"},"cliType":{"type":"string","enum":["full_cli","local_cli","mixed_cli","ncli","partial_cli"]},"lineType":{"type":"string","enum":["mobile_and_fixed","mobile","fixed"]},"capacity":{"type":"integer","exclusiveMinimum":true,"minimum":0,"maximum":1000000},"expectedAsr":{"type":"string","pattern":"^(\\d{1,5}(\\.\\d{1,2})?)?$"},"expectedAcd":{"type":"string","pattern":"^(\\d{1,5}(\\.\\d{1,2})?)?$"},"expectedPdd":{"type":"string","pattern":"^(\\d{1,5}(\\.\\d{1,2})?)?$"},"minAsr":{"type":"string","pattern":"^(\\d{1,5}(\\.\\d{1,2})?)?$","nullable":true},"minAcd":{"type":"integer","minimum":0,"nullable":true},"billingIncrement":{"type":"string","pattern":"^\\d{1,4}\\/\\d{1,4}$"},"routeType":{"type":"string","enum":["direct","premium","standard","ncli"]},"wholesaleCompatible":{"type":"boolean","default":true},"callcenterCompatible":{"type":"boolean","default":true},"dialerCompatible":{"type":"boolean","default":true},"retailCompatible":{"type":"boolean","default":true},"otpCompatible":{"type":"boolean","default":true},"openRtp":{"type":"boolean","default":false},"visibility":{"type":"string","enum":["public","private"],"default":"public"},"jingleEnabled":{"type":"boolean","default":false},"jingleApiUrl":{"type":"string","format":"uri","nullable":true},"smsDeliveryUrl":{"type":"string","format":"uri","nullable":true},"smsDeliveryMethod":{"type":"string","enum":["http","smpp","http_form"]},"smsApiKey":{"type":"string","maxLength":256,"nullable":true},"smppHost":{"type":"string","nullable":true},"smppPort":{"type":"integer","minimum":1,"maximum":65535,"nullable":true},"smppSystemId":{"type":"string","nullable":true},"smppPassword":{"type":"string","maxLength":64,"nullable":true},"smppBindType":{"type":"string","enum":["transceiver","transmitter"],"nullable":true},"smppSystemType":{"type":"string","maxLength":13,"nullable":true},"smppTps":{"type":"integer","minimum":1,"maximum":1000,"nullable":true},"smppSourceTon":{"type":"integer","minimum":0,"maximum":6,"nullable":true},"smppSourceNpi":{"type":"integer","minimum":0,"maximum":18,"nullable":true},"smppDestTon":{"type":"integer","minimum":0,"maximum":6,"nullable":true},"smppDestNpi":{"type":"integer","minimum":0,"maximum":18,"nullable":true},"jingleSipIp":{"type":"string","nullable":true},"sipPort":{"type":"integer","minimum":1,"maximum":65535,"nullable":true},"sipAuthUsername":{"type":"string","maxLength":128,"nullable":true},"sipAuthPassword":{"type":"string","maxLength":128,"nullable":true},"techPrefix":{"type":"string","pattern":"^[0-9#*]{1,20}$","nullable":true},"numberFormat":{"anyOf":[{"type":"object","properties":{"mode":{"type":"string","enum":["international"]}},"required":["mode"]},{"type":"object","properties":{"mode":{"type":"string","enum":["international_plus"]}},"required":["mode"]},{"type":"object","properties":{"mode":{"type":"string","enum":["national"]},"nationalPrefix":{"type":"string","pattern":"^[0-9#*]{0,10}$"}},"required":["mode","nationalPrefix"]},{"type":"object","properties":{"mode":{"type":"string","enum":["custom"]},"strip":{"type":"integer","minimum":0,"maximum":10},"add":{"type":"string","pattern":"^[0-9#*]{0,20}$"}},"required":["mode","strip","add"]}],"nullable":true},"fixedCli":{"type":"string","pattern":"^\\+?[0-9]{4,16}$","nullable":true},"cliFormat":{"type":"string","enum":["plus","digits"],"nullable":true},"originPolicy":{"type":"string","enum":["any","dual","origin_only"]},"originGroup":{"type":"string","pattern":"^[A-Za-z0-9_]{1,16}$","nullable":true},"callerIdRequired":{"type":"boolean"},"t38Support":{"type":"boolean","default":false},"supportedCodecs":{"type":"array","items":{"type":"string","maxLength":30},"maxItems":20},"maxCallDuration":{"type":"integer","exclusiveMinimum":true,"minimum":0},"smsType":{"type":"string","enum":["a2p","p2p","both"]},"smsDlrSupport":{"type":"boolean"},"smsConcatSupport":{"type":"boolean"},"smsSenderIdType":{"type":"string","enum":["alphanumeric","numeric","preregistered"]},"smsContentRestrictions":{"type":"string"},"smsRouteQuality":{"type":"string","enum":["hq","direct","aggregator","sim"],"nullable":true},"smsSenderIdBehavior":{"type":"string","enum":["alphanumeric_preserved","numeric_long","overwritten","not_guaranteed"],"nullable":true},"smsDlrLevel":{"type":"string","enum":["real_operator","intermediate","submit_only","none"],"nullable":true},"smsDlrPercent":{"type":"string","pattern":"^(\\d{1,5}(\\.\\d{1,2})?)?$","nullable":true},"smsUnicodeSupport":{"type":"boolean","nullable":true},"smsAcceptedTraffic":{"type":"array","items":{"type":"string","enum":["wholesale","transactional","otp","marketing","promo_shortcode"]},"nullable":true},"timeOfDayPricing":{"type":"object","additionalProperties":{"type":"string"}},"notes":{"type":"string","maxLength":2000},"status":{"type":"string","enum":["active","paused"]}}}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"type":"voice","country":"United Kingdom"}}},"delete":{"operationId":"deleteRoutesById","tags":["Marketplace routes"],"summary":"Delete a route you listed","description":"Restorable for `restoreWindowDays` via POST /routes/{id}/restore.\n\n**Auth:** API key or JWT. Scoped keys need `routes:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"message":{"type":"string"},"restorable":{"type":"boolean","enum":[true]},"restoreWindowDays":{"type":"integer"}},"required":["message","restorable","restoreWindowDays"],"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/routes/{id}/verification":{"get":{"operationId":"getRoutesByIdVerification","tags":["Marketplace routes"],"summary":"Per-network verification of a route","description":"Each network row with its tier, signal bars (0-4), last proven time and caller-ID mark, plus the last 20 check and caller-ID results. Visible where GET /routes/:id is. Call counts per row are for signed-in callers only. No dialled numbers or buyer identities.\n\n**Auth:** optional. Works anonymously; a token or API key personalises the answer.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{},"additionalProperties":true,"description":"{ routeId, listingRef, tier, networks: [{ network, kind, tier, signal, routeStatus, cliStatus, lastProvenAt, cliTestedAt, attempts7d, answered7d }], recent: [{ at, kind: check|caller_id_test, result: pass|fail|inconclusive|pending, network, detail }] }"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"optional","security":[{},{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/routes/{id}/test-history":{"get":{"operationId":"getRoutesByIdTestHistory","tags":["Marketplace routes"],"summary":"Test history of your route","description":"Your own listing only. Test calls (with `captureId` for GET /routes/test-captures/:captureId), checks, caller-ID tests, the latest endpoint probe, check suspensions and reinstatements, and per-network warn / grace / delist, newest first. `by` is you, buyer or platform; a buyer is never named.\n\n**Auth:** API key or JWT. Scoped keys need `routes:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"events":{"type":"array","items":{"type":"object","properties":{"at":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"kind":{"type":"string","enum":["test_call","check","caller_id_test","endpoint_probe","network_state"]},"result":{"type":"string"},"sipCode":{"type":"integer","nullable":true},"by":{"type":"string","enum":["you","buyer","platform"]},"network":{"type":"string","nullable":true},"detail":{"type":"string","nullable":true},"captureId":{"type":"string","format":"uuid","nullable":true}},"required":["at","kind","result","sipCode","by","network","detail","captureId"]}}},"required":["events"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":50}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/routes/autopilot/draft":{"post":{"operationId":"postRoutesAutopilotDraft","tags":["Marketplace routes"],"summary":"Draft a listing from a rate sheet","description":"Upload a CSV or Excel sheet (multipart field `file`, optional `note`). Returns a proposed listing and the questions a sheet cannot answer. Writes nothing.\n\n**Auth:** API key or JWT. Scoped keys need `routes:write`.\n\n**Rate limit:** 10 requests per minute per caller.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{},"additionalProperties":true,"description":"A proposed listing form plus open questions"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:write","x-rate-limit":{"max":10,"window":"minute"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","description":"CSV or Excel rate sheet (binary)"},"note":{"type":"string","maxLength":500}},"required":["file"]}}}},"x-px-example":{"path":{},"query":{}}}},"/api/v1/routes/probe-endpoint":{"post":{"operationId":"postRoutesProbeEndpoint","tags":["Marketplace routes"],"summary":"Test an endpoint before listing a route","description":"Sends a real SIP probe (voice), SMPP bind (SMS over SMPP) or URL check (SMS over HTTP) to the details you enter. Nothing is stored.\n\n**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.\n\n**Rate limit:** 20 requests per minute per caller.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/ConnectivityTestResult"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-rate-limit":{"max":20,"window":"minute"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"type":{"type":"string","enum":["voice","sms"]},"jingleSipIp":{"type":"string","maxLength":255,"nullable":true},"sipPort":{"type":"integer","minimum":1,"maximum":65535,"nullable":true},"techPrefix":{"type":"string","maxLength":24,"nullable":true},"smsDeliveryUrl":{"type":"string","maxLength":2048,"nullable":true},"smsDeliveryMethod":{"type":"string","enum":["http","smpp","http_form"],"nullable":true},"smsApiKey":{"type":"string","maxLength":256,"nullable":true,"description":"API key for smsDeliveryMethod \"http_form\" (form-encoded HTTP API, key in the URL; smsDeliveryUrl is the API base URL). Checked with one read-only call, never stored here, no message sent"},"smppHost":{"type":"string","maxLength":255,"nullable":true},"smppPort":{"type":"integer","minimum":1,"maximum":65535,"nullable":true},"smppSystemId":{"type":"string","maxLength":16,"nullable":true,"description":"Short account code your SMS supplier issued (max 16 chars). An email address is rejected."},"smppPassword":{"type":"string","maxLength":64,"nullable":true,"description":"Used for one bind attempt, never stored"},"smppBindType":{"type":"string","enum":["transceiver","transmitter"],"nullable":true},"smppSystemType":{"type":"string","maxLength":13,"nullable":true}},"required":["type"]}}}},"x-px-example":{"path":{},"query":{},"body":{"type":"voice"}}}},"/api/v1/routes/probe-endpoint/confirm":{"post":{"operationId":"postRoutesProbeEndpointConfirm","tags":["Marketplace routes"],"summary":"Follow an endpoint test that is waiting on the edge record","description":"A test from your own sending address can return `traceCheck` when the call engine heard nothing back: a switch that only answers \"100 Trying\" shows up in our edge's record a minute or two later. Call this with the token (about every 10 seconds) to get the re-judged result; `traceCheck` disappears once the answer is final. Reads our record only and sends nothing.\n\n**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.\n\n**Rate limit:** 30 requests per minute per caller.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/ConnectivityTestResult"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-rate-limit":{"max":30,"window":"minute"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string","format":"uuid"}},"required":["token"]}}}},"x-px-example":{"path":{},"query":{},"body":{"token":"<token>"}}}},"/api/v1/routes/probe-endpoint/live":{"post":{"operationId":"postRoutesProbeEndpointLive","tags":["Marketplace routes"],"summary":"POST /api/v1/routes/probe-endpoint/live","description":"**Auth:** API key or JWT. Scoped keys need `routes:write`.\n\n**Rate limit:** 20 requests per minute per caller.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":" Response shape not documented yet: the standard `{ \"success\": true, \"data\": ... }` envelope."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:write","x-rate-limit":{"max":20,"window":"minute"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/routes/probe-endpoint/live/{probeId}":{"get":{"operationId":"getRoutesProbeEndpointLiveByProbeId","tags":["Marketplace routes"],"summary":"GET /api/v1/routes/probe-endpoint/live/{probeId}","description":"**Auth:** API key or JWT. Scoped keys need `routes:read`.\n\n**Rate limit:** 120 requests per minute per caller.","responses":{"200":{"description":" Response shape not documented yet: the standard `{ \"success\": true, \"data\": ... }` envelope."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:read","x-rate-limit":{"max":120,"window":"minute"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"probeId","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"probeId":"<probeId>"},"query":{}}}},"/api/v1/routes/callguard":{"get":{"operationId":"getRoutesCallguard","tags":["Marketplace routes"],"summary":"List your call-centre routes and their call screening","description":"**Auth:** API key or JWT. Scoped keys need `routes:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"routeId":{"type":"string","format":"uuid"},"name":{"type":"string"},"country":{"type":"string"},"enabled":{"type":"boolean"},"consentAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"status":{"type":"string","enum":["active","paused","suspended","pending_review"]}},"required":["routeId","name","country","enabled","consentAt","status"],"additionalProperties":true}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/routes/{id}/screening":{"get":{"operationId":"getRoutesByIdScreening","tags":["Marketplace routes"],"summary":"Get call screening settings, stats and flagged calls","description":"**Auth:** API key or JWT. Scoped keys need `routes:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{},"additionalProperties":true,"description":"Screening config, statistics and the flagged calls"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}},"patch":{"operationId":"patchRoutesByIdScreening","tags":["Marketplace routes"],"summary":"Turn call screening on or off for a route","description":"Only for call-centre voice routes. Turning it on records your recording consent.\n\n**Auth:** API key or JWT. Scoped keys need `routes:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{},"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean"}},"required":["enabled"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"enabled":true}}}},"/api/v1/routes/{id}/screening/test":{"post":{"operationId":"postRoutesByIdScreeningTest","tags":["Marketplace routes"],"summary":"Classify a sample transcript with call screening","description":"**Auth:** API key or JWT. Scoped keys need `routes:write`.\n\n**Rate limit:** 20 requests per minute per caller.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{},"additionalProperties":true,"description":"The classification the transcript would receive"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:write","x-rate-limit":{"max":20,"window":"minute"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"transcript":{"type":"string","minLength":1,"maxLength":20000}},"required":["transcript"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"transcript":"<transcript>"}}}},"/api/v1/routes/listing-presets":{"get":{"operationId":"getRoutesListingPresets","tags":["Marketplace routes"],"summary":"List your saved listing presets","description":"**Auth:** API key or JWT. Scoped keys need `routes:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"presets":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"values":{"type":"object","additionalProperties":{}}},"required":["name","values"]}}},"required":["presets"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}},"put":{"operationId":"putRoutesListingPresets","tags":["Marketplace routes"],"summary":"Save a listing preset","description":"Upserts by name; keeps your 12 most recent presets.\n\n**Auth:** API key or JWT. Scoped keys need `routes:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"presets":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"values":{"type":"object","additionalProperties":{}}},"required":["name","values"]}}},"required":["presets"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":60},"values":{"type":"object","additionalProperties":{}}},"required":["name","values"]}}}},"x-px-example":{"path":{},"query":{},"body":{"name":"Acme","values":{}}}}},"/api/v1/routes/listing-presets/{name}":{"delete":{"operationId":"deleteRoutesListingPresetsByName","tags":["Marketplace routes"],"summary":"Delete a listing preset","description":"**Auth:** API key or JWT. Scoped keys need `routes:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"presets":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"values":{"type":"object","additionalProperties":{}}},"required":["name","values"]}}},"required":["presets"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"name":"<name>"},"query":{}}}},"/api/v1/routes/{id}/split-preview":{"get":{"operationId":"getRoutesByIdSplitPreview","tags":["Marketplace routes"],"summary":"Preview the listings publishing a deck will create","description":"**Auth:** API key or JWT. Scoped keys need `routes:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{},"additionalProperties":true,"description":"Per-country listings that publishing would produce"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/routes/deleted":{"get":{"operationId":"getRoutesDeleted","tags":["Marketplace routes"],"summary":"List your recently deleted routes","description":"**Auth:** API key or JWT. Scoped keys need `routes:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"routes":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"kind":{"type":"string","enum":["single","blend"]},"type":{"type":"string","enum":["voice","sms"]},"country":{"type":"string"},"countryCode":{"type":"string","description":"E.164 country calling code, digits only"},"prefix":{"type":"array","items":{"type":"string"},"description":"Dial prefixes the route covers"},"destinationName":{"type":"string","description":"The listing name. For anyone but the seller it is GENERATED by the platform from its own data, never the seller's text: \"<Country> <Operator?> <Mobile|Fixed|All Networks>\" for one destination (e.g. \"Niger Mobile\", \"Kenya Safaricom Mobile\"), \"A-Z Voice · <tier> · <CLI> · Ref XXXX\" or \"A-Z SMS · <quality> · Ref XXXX\" for an A-Z bundle. The seller sees the name they gave it."},"cliType":{"type":"string","enum":["full_cli","ncli","partial_cli","local_cli","mixed_cli"]},"routeType":{"type":"string","enum":["direct","premium","standard","ncli"],"description":"Quality tier"},"pricePerUnit":{"allOf":[{"$ref":"#/components/schemas/Money"}],"description":"USD per minute (voice) or per message segment (SMS). On an A-Z deck (rateCount > 0) the per-destination rates apply instead."},"billingIncrement":{"type":"string","nullable":true,"description":"First/subsequent increment in seconds, e.g. \"60/60\""},"capacity":{"type":"integer","description":"Channels (voice) or messages per second (SMS)"},"expectedAsr":{"type":"string","nullable":true,"description":"Seller-stated ASR %. The measured figure is in `measured.asr`"},"expectedAcd":{"type":"string","nullable":true,"description":"Seller-stated ACD in seconds"},"expectedPdd":{"type":"string","nullable":true,"description":"Seller-stated PDD in seconds"},"minAcd":{"type":"integer","nullable":true},"minAsr":{"type":"string","nullable":true,"description":"Decimal as a string, e.g. \"92.50\""},"visibility":{"type":"string","enum":["public","private"]},"status":{"type":"string","enum":["active","paused","suspended","pending_review"]},"wholesaleCompatible":{"type":"boolean"},"callcenterCompatible":{"type":"boolean"},"dialerCompatible":{"type":"boolean"},"retailCompatible":{"type":"boolean"},"otpCompatible":{"type":"boolean"},"notes":{"type":"string","nullable":true},"smsType":{"type":"string","enum":["a2p","p2p","both"],"nullable":true},"exchangeScore":{"type":"integer","nullable":true,"description":"Exchange Score 1-100, null until the route has carried real traffic. Uses the measured ASR, NER, ACD and PDD in place of the stated ones when the listing has recent measured figures"},"lastQcAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"measured":{"allOf":[{"$ref":"#/components/schemas/MeasuredRouteQuality"}],"nullable":true,"description":"Measured quality from real calls; null until the listing has enough traffic from enough buyers"},"routeChecks":{"allOf":[{"$ref":"#/components/schemas/RouteCheckRecord"}],"nullable":true,"description":"Route checks on this listing in the last 7 days. Null when there were none."},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"sellerId":{"type":"string","format":"uuid","description":"Your own account id"},"isOwner":{"type":"boolean","enum":[true]},"parentRouteId":{"type":"string","format":"uuid","nullable":true},"isBundle":{"type":"boolean"},"jingleSipIp":{"type":"string","nullable":true,"description":"Your SIP endpoint"},"sipPort":{"type":"integer","nullable":true},"techPrefix":{"type":"string","nullable":true},"sipAuthUsername":{"type":"string","nullable":true},"sipAuthPasswordSet":{"type":"boolean","description":"A SIP digest password is stored (never returned)"},"smsDeliveryMethod":{"type":"string","enum":["http","smpp","http_form"],"nullable":true},"smsDeliveryUrl":{"type":"string","nullable":true},"smppHost":{"type":"string","nullable":true},"smppPort":{"type":"integer","nullable":true},"smppSystemId":{"type":"string","nullable":true},"smppPasswordSet":{"type":"boolean","description":"An SMPP password, or on an http_form route the API key, is stored (never returned)"},"endpointReachable":{"type":"boolean","nullable":true},"endpointCheckedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"sellerProfile":{"allOf":[{"$ref":"#/components/schemas/MarketplaceSellerProfile"}],"nullable":true,"description":"Trust signals only. The marketplace never names the seller behind a listing."},"rateCount":{"type":"integer"}},"additionalProperties":true,"description":"A route you listed, as only you (the seller) see it. Passwords are never returned."}},"restoreWindowDays":{"type":"integer"}},"required":["routes","restoreWindowDays"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/routes/{id}/restore":{"post":{"operationId":"postRoutesByIdRestore","tags":["Marketplace routes"],"summary":"Restore a deleted route","description":"The route comes back paused and private; publish it again when ready.\n\n**Auth:** API key or JWT. Scoped keys need `routes:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"],"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/routes/my-endpoints":{"get":{"operationId":"getRoutesMyEndpoints","tags":["Marketplace routes"],"summary":"List your saved SIP endpoints","description":"**Auth:** API key or JWT. Scoped keys need `routes:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","nullable":true},"ip":{"type":"string"},"label":{"type":"string","nullable":true},"routeCount":{"type":"integer","description":"How many of your routes use this IP"},"usedBy":{"type":"string","nullable":true,"description":"Name of the newest route using this IP"}},"required":["ip"],"additionalProperties":true}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}},"post":{"operationId":"postRoutesMyEndpoints","tags":["Marketplace routes"],"summary":"Save a SIP endpoint","description":"**Auth:** API key or JWT. Scoped keys need `routes:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid","nullable":true},"ip":{"type":"string"},"label":{"type":"string","nullable":true},"routeCount":{"type":"integer","description":"How many of your routes use this IP"},"usedBy":{"type":"string","nullable":true,"description":"Name of the newest route using this IP"}},"required":["ip"],"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"ip":{"type":"string"},"label":{"type":"string","maxLength":60,"nullable":true}},"required":["ip"]}}}},"x-px-example":{"path":{},"query":{},"body":{"ip":"203.0.113.10"}}}},"/api/v1/routes/my-endpoints/{id}":{"patch":{"operationId":"patchRoutesMyEndpointsById","tags":["Marketplace routes"],"summary":"Label a saved SIP endpoint","description":"Sets the label shown next to the IP in \"My IPs\" and in the SIP endpoint pickers, so a seller with several switches can tell them apart. The label is trimmed, control and bidirectional-override characters are removed, and it is cut to 60 characters; an empty string or null clears it. Only saved endpoints (those with an `id` in GET /routes/my-endpoints) can be labelled; an unknown id, or someone else's, answers 404.\n\n**Auth:** API key or JWT. Scoped keys need `routes:write`.\n\n**Rate limit:** 60 requests per minute per caller.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"ip":{"type":"string"},"label":{"type":"string","nullable":true}},"required":["id","ip","label"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:write","x-rate-limit":{"max":60,"window":"minute"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string","maxLength":60,"nullable":true,"description":"The new label; \"\" or null clears it"}},"required":["label"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"label":"Acme"}}},"delete":{"operationId":"deleteRoutesMyEndpointsById","tags":["Marketplace routes"],"summary":"Remove a saved SIP endpoint","description":"**Auth:** API key or JWT. Scoped keys need `routes:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{},"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/routes/resolve":{"get":{"operationId":"getRoutesResolve","tags":["Marketplace routes"],"summary":"Preview which route would carry a destination","description":"Resolves as your account (including private routes you bought). `price` is a 6-decimal USD string.\n\n**Auth:** API key or JWT. Scoped keys need `routes:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"strategy":{"type":"string","enum":["cheapest","best_quality","balanced"]},"selected":{"allOf":[{"$ref":"#/components/schemas/ResolvedRoute"}],"nullable":true},"alternatives":{"type":"array","items":{"$ref":"#/components/schemas/ResolvedRoute"}},"count":{"type":"integer"}},"required":["strategy","selected","alternatives","count"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"to","in":"query","required":true,"description":"Destination number or prefix","schema":{"type":"string"}},{"name":"type","in":"query","required":false,"schema":{"type":"string","enum":["voice","sms"],"default":"voice"}},{"name":"strategy","in":"query","required":false,"schema":{"type":"string","enum":["cheapest","best_quality","balanced"],"default":"balanced"}}],"x-px-example":{"path":{},"query":{"to":"+447700900123"}}}},"/api/v1/routes/{id}/test":{"post":{"operationId":"postRoutesByIdTest","tags":["Marketplace routes"],"summary":"Test connectivity to your route endpoint","description":"Sends a real SIP probe to the route endpoint from every one of our media addresses.\n\n**Auth:** API key or JWT. Scoped keys need `routes:write`.\n\n**Rate limit:** 20 requests per minute per caller.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/ConnectivityTestResult"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:write","x-rate-limit":{"max":20,"window":"minute"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}},"x-px-billable":{"kind":"traffic","note":"Places a real test call over the route."}}},"/api/v1/routes/test-captures/{captureId}":{"get":{"operationId":"getRoutesTestCapturesByCaptureId","tags":["Marketplace routes"],"summary":"GET /api/v1/routes/test-captures/{captureId}","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":" Response shape not documented yet: the standard `{ \"success\": true, \"data\": ... }` envelope."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"captureId","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"captureId":"<captureId>"},"query":{}}}},"/api/v1/routes/{id}/sip-trace":{"post":{"operationId":"postRoutesByIdSipTrace","tags":["Marketplace routes"],"summary":"Capture a SIP trace of a test call on a route","description":"For the seller or an active buyer. Optionally dials a real `number`. Buyers receive the trace with seller addresses masked.\n\n**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.\n\n**Rate limit:** 10 requests per minute per caller.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{},"additionalProperties":true,"description":"The SIP ladder: messages, timings and the final response"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-rate-limit":{"max":10,"window":"minute"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"number":{"type":"string"}}}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"number":"+447700900123"}},"x-px-billable":{"kind":"traffic","note":"Places a real test call over the route."}}},"/api/v1/routes/{id}/price-history":{"get":{"operationId":"getRoutesByIdPriceHistory","tags":["Marketplace routes"],"summary":"Get a route's price history","description":"For the seller and buyers of the route. Newest first.\n\n**Auth:** API key or JWT. Scoped keys need `routes:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"routeId":{"type":"string","format":"uuid"},"oldPrice":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"US dollars as a decimal string with exactly 6 decimal places, e.g. \"0.012500\". Do money arithmetic with a decimal type, not floating point."},"newPrice":{"$ref":"#/components/schemas/Money"},"changedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","routeId","oldPrice","newPrice","changedAt"],"additionalProperties":true}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/routes/{id}/stats":{"get":{"operationId":"getRoutesByIdStats","tags":["Marketplace routes"],"summary":"Get traffic and revenue stats for your route","description":"**Auth:** API key or JWT. Scoped keys need `routes:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"activePurchases":{"type":"integer"},"volume":{"type":"object","additionalProperties":{"type":"object","properties":{"minutesOrMessages":{"type":"number"},"revenue":{"type":"number"}},"required":["minutesOrMessages","revenue"]},"description":"Keyed 24h, 7d, 30d. revenue is USD (display figure, 2 decimals)"},"measuredAsr":{"type":"number","nullable":true},"measuredAcd":{"type":"number","nullable":true},"recentOffers":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"proposedPrice":{"$ref":"#/components/schemas/Money"},"agreedPrice":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"US dollars as a decimal string with exactly 6 decimal places, e.g. \"0.012500\". Do money arithmetic with a decimal type, not floating point."},"status":{"type":"string"},"lastActor":{"type":"string"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","proposedPrice","agreedPrice","status","lastActor","createdAt","updatedAt"]}}},"required":["activePurchases","volume","measuredAsr","measuredAcd","recentOffers"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/routes/my/list":{"get":{"operationId":"getRoutesMyList","tags":["Marketplace routes"],"summary":"List the routes you sell","description":"Two modes. Cursor mode (only `cursor`, `limit`, `includeChildren`): newest first, A-Z deck children hidden unless `includeChildren=true`. Paged mode (any of `offset`, `search`, `type`, `status`, `visibility`, `live`, `hiddenReason`, `scope`, `endpoint`, `deck`, `sort`, `dir`): up to 200 rows a page, with `total`, and each row carries `origin` (its endpoint, your label for it, and the deck and rate sheet it came from). `scope=listings` lists every row a buyer could see as a listing (single routes and deck children); `hiddenReason` lists exactly the routes counted under that reason by GET /routes/my/listing-health. `search` matches the route name, country, endpoint IP or host, your IP label, the deck name and a route id prefix; a number such as `+44` is a dial code (country code or coverage prefix). `endpoint` and `deck` take a group `key` from GET /routes/my/groups.\n\n**Auth:** API key or JWT. Scoped keys need `routes:read`.","responses":{"200":{"description":"Success. The result fields sit beside `success`, not under `data`.","content":{"application/json":{"schema":{"type":"object","required":["success","data","nextCursor","hasMore"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"kind":{"type":"string","enum":["single","blend"]},"type":{"type":"string","enum":["voice","sms"]},"country":{"type":"string"},"countryCode":{"type":"string","description":"E.164 country calling code, digits only"},"prefix":{"type":"array","items":{"type":"string"},"description":"Dial prefixes the route covers"},"destinationName":{"type":"string","description":"The listing name. For anyone but the seller it is GENERATED by the platform from its own data, never the seller's text: \"<Country> <Operator?> <Mobile|Fixed|All Networks>\" for one destination (e.g. \"Niger Mobile\", \"Kenya Safaricom Mobile\"), \"A-Z Voice · <tier> · <CLI> · Ref XXXX\" or \"A-Z SMS · <quality> · Ref XXXX\" for an A-Z bundle. The seller sees the name they gave it."},"cliType":{"type":"string","enum":["full_cli","ncli","partial_cli","local_cli","mixed_cli"]},"routeType":{"type":"string","enum":["direct","premium","standard","ncli"],"description":"Quality tier"},"pricePerUnit":{"allOf":[{"$ref":"#/components/schemas/Money"}],"description":"USD per minute (voice) or per message segment (SMS). On an A-Z deck (rateCount > 0) the per-destination rates apply instead."},"billingIncrement":{"type":"string","nullable":true,"description":"First/subsequent increment in seconds, e.g. \"60/60\""},"capacity":{"type":"integer","description":"Channels (voice) or messages per second (SMS)"},"expectedAsr":{"type":"string","nullable":true,"description":"Seller-stated ASR %. The measured figure is in `measured.asr`"},"expectedAcd":{"type":"string","nullable":true,"description":"Seller-stated ACD in seconds"},"expectedPdd":{"type":"string","nullable":true,"description":"Seller-stated PDD in seconds"},"minAcd":{"type":"integer","nullable":true},"minAsr":{"type":"string","nullable":true,"description":"Decimal as a string, e.g. \"92.50\""},"visibility":{"type":"string","enum":["public","private"]},"status":{"type":"string","enum":["active","paused","suspended","pending_review"]},"wholesaleCompatible":{"type":"boolean"},"callcenterCompatible":{"type":"boolean"},"dialerCompatible":{"type":"boolean"},"retailCompatible":{"type":"boolean"},"otpCompatible":{"type":"boolean"},"notes":{"type":"string","nullable":true},"smsType":{"type":"string","enum":["a2p","p2p","both"],"nullable":true},"exchangeScore":{"type":"integer","nullable":true,"description":"Exchange Score 1-100, null until the route has carried real traffic. Uses the measured ASR, NER, ACD and PDD in place of the stated ones when the listing has recent measured figures"},"lastQcAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"measured":{"allOf":[{"$ref":"#/components/schemas/MeasuredRouteQuality"}],"nullable":true,"description":"Measured quality from real calls; null until the listing has enough traffic from enough buyers"},"routeChecks":{"allOf":[{"$ref":"#/components/schemas/RouteCheckRecord"}],"nullable":true,"description":"Route checks on this listing in the last 7 days. Null when there were none."},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"sellerId":{"type":"string","format":"uuid","description":"Your own account id"},"isOwner":{"type":"boolean","enum":[true]},"parentRouteId":{"type":"string","format":"uuid","nullable":true},"isBundle":{"type":"boolean"},"jingleSipIp":{"type":"string","nullable":true,"description":"Your SIP endpoint"},"sipPort":{"type":"integer","nullable":true},"techPrefix":{"type":"string","nullable":true},"sipAuthUsername":{"type":"string","nullable":true},"sipAuthPasswordSet":{"type":"boolean","description":"A SIP digest password is stored (never returned)"},"smsDeliveryMethod":{"type":"string","enum":["http","smpp","http_form"],"nullable":true},"smsDeliveryUrl":{"type":"string","nullable":true},"smppHost":{"type":"string","nullable":true},"smppPort":{"type":"integer","nullable":true},"smppSystemId":{"type":"string","nullable":true},"smppPasswordSet":{"type":"boolean","description":"An SMPP password, or on an http_form route the API key, is stored (never returned)"},"endpointReachable":{"type":"boolean","nullable":true},"endpointCheckedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"sellerProfile":{"allOf":[{"$ref":"#/components/schemas/MarketplaceSellerProfile"}],"nullable":true,"description":"Trust signals only. The marketplace never names the seller behind a listing."},"rateCount":{"type":"integer"},"revenue30d":{"type":"number","description":"USD seller credit over 30 days (display figure, 2 decimals)"},"liveChannels":{"type":"integer"},"childCount":{"type":"integer","description":"Per-country child listings created from this deck"},"origin":{"$ref":"#/components/schemas/MyRouteOrigin","description":"Paged mode only: where the route terminates and where it came from"}},"required":["id","kind","type","country","countryCode","prefix","destinationName","cliType","routeType","pricePerUnit","billingIncrement","capacity","expectedAsr","expectedAcd","expectedPdd","minAcd","minAsr","visibility","status","wholesaleCompatible","callcenterCompatible","dialerCompatible","retailCompatible","otpCompatible","notes","exchangeScore","lastQcAt","createdAt","updatedAt","sellerId","parentRouteId","isBundle","jingleSipIp","sipPort","techPrefix","sipAuthUsername","sipAuthPasswordSet","smsDeliveryUrl","smppHost","smppPort","smppSystemId","smppPasswordSet","endpointReachable","endpointCheckedAt","revenue30d","liveChannels","childCount"],"description":"A route you listed, as only you (the seller) see it. Passwords are never returned."}},"nextCursor":{"type":"string","nullable":true,"description":"Cursor mode only; always null in paged mode"},"hasMore":{"type":"boolean"},"total":{"type":"integer","description":"Paged mode only: rows matching the filters across all pages"},"offset":{"type":"integer","description":"Paged mode only"},"limit":{"type":"integer","description":"Paged mode only (max 200)"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"cursor","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","required":false,"description":"Cursor mode: default 25, max 100. Paged mode: default 50, max 200.","schema":{"type":"integer","minimum":1,"maximum":200}},{"name":"includeChildren","in":"query","required":false,"description":"Include the per-country children of A-Z decks","schema":{"type":"string","enum":["true","false","1","0"]}},{"name":"search","in":"query","required":false,"schema":{"type":"string","maxLength":100}},{"name":"type","in":"query","required":false,"schema":{"type":"string","enum":["voice","sms"]}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["active","paused","pending_review","suspended"]}},{"name":"visibility","in":"query","required":false,"schema":{"type":"string","enum":["public","private"]}},{"name":"live","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"string","enum":["true","false"]}]}},{"name":"hiddenReason","in":"query","required":false,"schema":{"type":"string","enum":["sms_no_delivery","voice_no_endpoint"]}},{"name":"scope","in":"query","required":false,"schema":{"type":"string","enum":["listings","decks"]}},{"name":"endpoint","in":"query","required":false,"schema":{"type":"string","minLength":1,"maxLength":255}},{"name":"deck","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"string","enum":["~single"]}]}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"maximum":1000000}},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["created","name","country","type","price","status"]}},{"name":"dir","in":"query","required":false,"schema":{"type":"string","enum":["asc","desc"]}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/routes/sms-endpoint-gap":{"get":{"operationId":"getRoutesSmsEndpointGap","tags":["Marketplace routes"],"summary":"Count your SMS routes hidden for lack of an endpoint","description":"**Auth:** API key or JWT. Scoped keys need `routes:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"count":{"type":"integer"}},"required":["count"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/routes/sms-endpoint/bulk":{"post":{"operationId":"postRoutesSmsEndpointBulk","tags":["Marketplace routes"],"summary":"Set one delivery endpoint on all your endpoint-less SMS routes","description":"An SMPP method runs a real bind first; if it fails nothing changes and `error.details` carries the reason and the addresses to whitelist.\n\n**Auth:** API key or JWT. Scoped keys need `routes:write`.\n\n**Rate limit:** 6 requests per minute per caller.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"updated":{"type":"integer"},"method":{"type":"string","enum":["http","smpp"]},"bind":{"type":"string"}},"required":["updated","method"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:write","x-rate-limit":{"max":6,"window":"minute"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"method":{"type":"string","enum":["http","smpp"]},"smsDeliveryUrl":{"type":"string"},"smppHost":{"type":"string"},"smppPort":{"type":"integer"},"smppSystemId":{"type":"string"},"smppPassword":{"type":"string"},"smppBindType":{"type":"string","enum":["transceiver","transmitter"]},"smppSystemType":{"type":"string"},"routeIds":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Narrow to these routes; never widens the set"}},"required":["method"]}}}},"x-px-example":{"path":{},"query":{},"body":{"method":"http"}}}},"/api/v1/lookup/{number}":{"get":{"operationId":"getLookupByNumber","tags":["Number lookup"],"summary":"Look up a phone number","description":"Validates and formats an E.164 number and tells you what its prefix is on the exchange: country, line type (mobile, fixed, toll free, premium), the network where the rate decks agree, whether it is a blocked or high-risk destination, and the cheapest live public price to reach it by voice and by SMS (the same logic as `GET /routes/price-number`).\n\nSMS prices are by destination network where the route prices per network: `pricing.sms.network` says which network the price is for and `pricing.sms.countryRate` is the price for other or unknown networks. The network is determined from the number's range (ported numbers may be priced at the network the range belongs to).\n\n**Prefix-based.** No carrier HLR query is made, so the answer cannot tell you whether the number is in service or has been ported. It is free, needs no key (a scoped key needs `routes:read`), and is limited to 60 lookups a minute per caller. Send the number in international format (`+447700900123` or `00447700900123`; spaces and dashes are ignored). A malformed number answers 200 with `valid: false` and a `reason`.\n\n**Auth:** optional. Works anonymously; a token or API key personalises the answer.\n\n**Rate limit:** 60 requests per minute per caller.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/NumberLookup"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"optional","x-rate-limit":{"max":60,"window":"minute"},"security":[{},{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"number","in":"path","required":true,"schema":{"type":"string","description":"The number in international format; URL-encode the leading + as %2B or omit it"}}],"x-px-example":{"path":{"number":"<number>"},"query":{}}}},"/api/v1/routes/my/listing-health":{"get":{"operationId":"getRoutesMyListingHealth","tags":["Marketplace routes"],"summary":"Count your listed routes that are live, and why the rest are hidden","description":"Answers \"why does my route count differ from the marketplace?\". `listed` counts your active, public routes (A-Z deck parents excluded); `live` counts the ones buyers can see, using the marketplace's own filters, so the two numbers cannot disagree with the board. Each reason carries a count, a label and the fix. The routes behind `sms_no_delivery` and `voice_no_endpoint` can be listed with GET /routes/my/list?hiddenReason=<key> and fixed in one call with POST /routes/my/bulk-sms-delivery or /routes/my/bulk-sip-endpoint.\n\n**Auth:** API key or JWT. Scoped keys need `routes:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/ListingHealth"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/routes/my/bulk-sms-delivery":{"post":{"operationId":"postRoutesMyBulkSmsDelivery","tags":["Marketplace routes"],"summary":"Set one SMS delivery method on many of your SMS routes","description":"Applies one delivery method (SMPP or HTTP) to a selection of your SMS routes: an explicit `routeIds` list, or every route matching `filter` (at most 5,000). Only your own live routes are touched; each route that is not eligible is returned in `skipped` with a reason. Send `dryRun: true` first to see how many would change: nothing is probed or written. On a real run the endpoint is checked ONCE for the whole batch: SMPP gets a real bind (no message is sent) and HTTP gets a URL check. If the bind is refused NO route is changed and the call answers 400 VALIDATION_ERROR with `error.details` = `{ kind: \"smpp_bind_failed\", host, port, systemId, bindType, reason, whitelistIps, failoverIps }`: `whitelistIps` is the one SMS source address your SMSC must allow (every bind and message leaves from it); `failoverIps` are used only while that address is down, so allowing them is optional. A field that fails validation answers 400 with one `{ path, message }` per field. All routes change in one transaction.\n\n**Auth:** API key or JWT. Scoped keys need `routes:write`.\n\n**Rate limit:** 10 requests per minute per caller.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/BulkEndpointResult"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:write","x-rate-limit":{"max":10,"window":"minute"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"routeIds":{"type":"array","items":{"type":"string","format":"uuid"},"minItems":1,"maxItems":5000,"description":"An explicit selection of your route ids (max 5000). Send this OR filter, not both."},"filter":{"type":"object","properties":{"search":{"type":"string","maxLength":100},"type":{"type":"string","enum":["voice","sms"]},"status":{"type":"string","enum":["active","paused","pending_review","suspended"]},"visibility":{"type":"string","enum":["public","private"]},"live":{"anyOf":[{"type":"boolean"},{"type":"string","enum":["true","false"]}]},"hiddenReason":{"type":"string","enum":["sms_no_delivery","voice_no_endpoint"]},"scope":{"type":"string","enum":["listings","decks"]},"endpoint":{"type":"string","minLength":1,"maxLength":255},"deck":{"anyOf":[{"type":"string","format":"uuid"},{"type":"string","enum":["~single"]}]}},"description":"\"Every route matching this filter\", re-derived on the server with the same rules as GET /routes/my/list (scope defaults to listings). Refused when it matches more than 5,000 routes."},"dryRun":{"type":"boolean","description":"Count and classify only: nothing is probed or written, and the answer carries wouldUpdate"},"delivery":{"type":"object","properties":{"smsDeliveryMethod":{"type":"string","enum":["http","smpp","http_form"]},"smsDeliveryUrl":{"type":"string","format":"uri","nullable":true},"smppHost":{"type":"string","nullable":true},"smppPort":{"type":"integer","minimum":1,"maximum":65535,"nullable":true},"smppSystemId":{"type":"string","nullable":true},"smppPassword":{"type":"string","maxLength":64,"nullable":true},"smppBindType":{"type":"string","enum":["transceiver","transmitter"],"nullable":true},"smppSystemType":{"type":"string","maxLength":13,"nullable":true},"smsApiKey":{"type":"string","maxLength":256,"nullable":true}},"description":"The SMS delivery method to set, validated exactly as PUT /routes/{id} validates it. It must be complete: smsDeliveryMethod \"smpp\" needs smppHost and smppSystemId; \"http\" needs smsDeliveryUrl; \"http_form\" needs smsDeliveryUrl (the API base URL) and smsApiKey. A blank smppPassword keeps each route's stored one; null clears it."}},"required":["delivery"]}}}},"x-px-example":{"path":{},"query":{},"body":{"delivery":{"smsDeliveryMethod":"http","smsDeliveryUrl":"https://example.com/webhooks/packetexchange"}}}}},"/api/v1/routes/my/bulk-sip-endpoint":{"post":{"operationId":"postRoutesMyBulkSipEndpoint","tags":["Marketplace routes"],"summary":"Set one SIP endpoint on many of your voice routes","description":"Applies one SIP endpoint (IP or host, port, technical prefix and optional digest credentials) to a selection of your voice routes: an explicit `routeIds` list, or every route matching `filter` (at most 5,000). Only your own live routes are touched; routes that are not eligible, or that would duplicate another of your listings on the same IP and tech prefix (same country and prefixes), are returned in `skipped`. Send `dryRun: true` first to see how many would change. An invalid, private or reserved address, or one of our own addresses, is refused outright (400, on `jingleSipIp`). Otherwise one SIP probe is sent to the endpoint; if it gets no answer the call answers 400 VALIDATION_ERROR with `error.details` = `{ kind: \"sip_probe_failed\", message, checks }` and nothing changes. Repeat with `confirmUnreachable: true` to apply anyway (a single-route edit never probes, so bulk is never stricter). The IP is also added to your saved endpoints. All routes change in one transaction.\n\n**Auth:** API key or JWT. Scoped keys need `routes:write`.\n\n**Rate limit:** 10 requests per minute per caller.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/BulkEndpointResult"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:write","x-rate-limit":{"max":10,"window":"minute"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"routeIds":{"type":"array","items":{"type":"string","format":"uuid"},"minItems":1,"maxItems":5000,"description":"An explicit selection of your route ids (max 5000). Send this OR filter, not both."},"filter":{"type":"object","properties":{"search":{"type":"string","maxLength":100},"type":{"type":"string","enum":["voice","sms"]},"status":{"type":"string","enum":["active","paused","pending_review","suspended"]},"visibility":{"type":"string","enum":["public","private"]},"live":{"anyOf":[{"type":"boolean"},{"type":"string","enum":["true","false"]}]},"hiddenReason":{"type":"string","enum":["sms_no_delivery","voice_no_endpoint"]},"scope":{"type":"string","enum":["listings","decks"]},"endpoint":{"type":"string","minLength":1,"maxLength":255},"deck":{"anyOf":[{"type":"string","format":"uuid"},{"type":"string","enum":["~single"]}]}},"description":"\"Every route matching this filter\", re-derived on the server with the same rules as GET /routes/my/list (scope defaults to listings). Refused when it matches more than 5,000 routes."},"dryRun":{"type":"boolean","description":"Count and classify only: nothing is probed or written, and the answer carries wouldUpdate"},"delivery":{"type":"object","properties":{"jingleSipIp":{"type":"string","nullable":true},"sipPort":{"type":"integer","minimum":1,"maximum":65535,"nullable":true},"techPrefix":{"type":"string","pattern":"^[0-9#*]{1,20}$","nullable":true},"sipAuthUsername":{"type":"string","maxLength":128,"nullable":true},"sipAuthPassword":{"type":"string","maxLength":128,"nullable":true}},"description":"The SIP endpoint to set, validated exactly as PUT /routes/{id} validates it. jingleSipIp is required. A blank sipAuthPassword keeps each route's stored one; null clears it."},"confirmUnreachable":{"type":"boolean","description":"Apply even though the SIP probe got no answer (the first attempt is refused with the probe's diagnosis in error.details)"}},"required":["delivery"]}}}},"x-px-example":{"path":{},"query":{},"body":{"delivery":{"jingleSipIp":"<jingleSipIp>","sipPort":1}}}}},"/api/v1/routes/my/summary":{"get":{"operationId":"getRoutesMySummary","tags":["Marketplace routes"],"summary":"Your selling overview in one read","description":"Counts of your listings (total, listed, live, hidden, paused, suspended, inReview, private, held), needs-you items each with a reason code, count, up to 10 route ids and a deep link, and seller earnings windows (credit ledger: today UTC, last 7 and 30 days).\n\n**Auth:** API key or JWT. Scoped keys need `routes:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"counts":{"type":"object","properties":{"total":{"type":"integer"},"listed":{"type":"integer"},"live":{"type":"integer"},"hidden":{"type":"integer"},"paused":{"type":"integer"},"suspended":{"type":"integer"},"inReview":{"type":"integer"},"private":{"type":"integer"},"held":{"type":"integer"}},"required":["total","listed","live","hidden","paused","suspended","inReview","private","held"]},"needsYou":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","enum":["suspended","held","voice_no_endpoint","sms_no_delivery","voice_endpoint_unreachable","smpp_bind_failed","network_warning","network_delisted","access_requests","offers_your_turn"]},"count":{"type":"integer"},"routeIds":{"type":"array","items":{"type":"string","format":"uuid"}},"severity":{"type":"string","enum":["warning","danger"]},"href":{"type":"string","nullable":true}},"required":["code","count","routeIds","severity","href"]}},"earnings":{"type":"object","properties":{"today":{"$ref":"#/components/schemas/Money"},"last7d":{"$ref":"#/components/schemas/Money"},"last30d":{"$ref":"#/components/schemas/Money"}},"required":["today","last7d","last30d"]},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["counts","needsYou","earnings","updatedAt"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/routes/my/groups":{"get":{"operationId":"getRoutesMyGroups","tags":["Marketplace routes"],"summary":"Group the routes you sell by endpoint or by A-Z deck","description":"Your routes matching the same filters as GET /routes/my/list (paged mode), grouped by `by=endpoint` (the SIP IP, SMSC host or delivery URL host, with your label for the IP) or `by=deck` (the A-Z deck a route was split out of, with the rate sheet behind it). Each group has total, live and hidden counts. List a group's routes with GET /routes/my/list?endpoint=<key> or ?deck=<key>; the bulk actions accept the same keys in `filter`. Only your own routes are counted.\n\n**Auth:** API key or JWT. Scoped keys need `routes:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/MyRoutesGroups"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"search","in":"query","required":false,"schema":{"type":"string","maxLength":100}},{"name":"type","in":"query","required":false,"schema":{"type":"string","enum":["voice","sms"]}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["active","paused","pending_review","suspended"]}},{"name":"visibility","in":"query","required":false,"schema":{"type":"string","enum":["public","private"]}},{"name":"live","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"string","enum":["true","false"]}]}},{"name":"hiddenReason","in":"query","required":false,"schema":{"type":"string","enum":["sms_no_delivery","voice_no_endpoint"]}},{"name":"scope","in":"query","required":false,"schema":{"type":"string","enum":["listings","decks"]}},{"name":"endpoint","in":"query","required":false,"schema":{"type":"string","minLength":1,"maxLength":255}},{"name":"deck","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"string","enum":["~single"]}]}},{"name":"by","in":"query","required":true,"schema":{"type":"string","enum":["endpoint","deck"]}}],"x-px-example":{"path":{},"query":{"by":"endpoint"}}}},"/api/v1/routes/my/sending-address":{"get":{"operationId":"getRoutesMySendingAddress","tags":["Marketplace routes"],"summary":"GET /api/v1/routes/my/sending-address","description":"**Auth:** API key or JWT. Scoped keys need `routes:read`.","responses":{"200":{"description":" Response shape not documented yet: the standard `{ \"success\": true, \"data\": ... }` envelope."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/routes/my/endpoint-status":{"get":{"operationId":"getRoutesMyEndpointStatus","tags":["Marketplace routes"],"summary":"Check whether your switches are refusing our calls","description":"One entry per SIP endpoint (IP or host) used by your active voice routes. `refusing` is true when we have evidence your switch is turning our calls away: calls we sent it in the last 6 hours answered with SIP 401, 403 or 407 (at least 3 of them, and at least half of the calls that got an answer), or our own test call to it was barred or refused from some of our addresses (`partial`, with the refused addresses in `refusedIps` when known). `evidence` is that finding in one sentence, `routeId` is a route on the endpoint you can test from, and `since` is when the current incident was first seen. `allow` lists the addresses to allow on your switch: every one of `egressIps`, for SIP on `sipPort` (UDP and TCP) and RTP media on the UDP `rtpPortRange`, the same values GET /sip/network-info publishes. Only your own endpoints and your own calls are counted.\n\n**Auth:** API key or JWT. Scoped keys need `routes:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/EndpointStatus"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/routes/{id}/buyers":{"get":{"operationId":"getRoutesByIdBuyers","tags":["Marketplace routes"],"summary":"List the buyers of your route","description":"Owner only: anyone other than the route's seller gets 403 FORBIDDEN. One row per buyer, identified only by a pseudonym scoped to this route (the same \"Buyer #3F2A\" that appears on offers for the route), so it cannot be matched to an account or across your other routes. No account id, name, company, email, IP or dialled number is returned. Figures cover the last 30 days; for an A-Z deck they include its per-country listings. `status` is the buyer's current relationship (ended = cancelled; ended buyers with no traffic in the window are left out). `asr30d` and `calls30d` are voice only, counted per call attempt group, and null until a call has been measured. Sorted by revenue.\n\n**Auth:** API key or JWT. Scoped keys need `routes:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"windowDays":{"type":"integer"},"unit":{"type":"string","enum":["minutes","messages"]},"buyers":{"type":"array","items":{"type":"object","properties":{"buyer":{"type":"string","description":"Pseudonym, stable per route"},"status":{"type":"string","enum":["active","paused","pending_review","ended"]},"volume30d":{"type":"number"},"revenue30d":{"type":"number","description":"USD (display figure, 2 decimals)"},"asr30d":{"type":"number","nullable":true},"calls30d":{"type":"integer","nullable":true}},"required":["buyer","status","volume30d","revenue30d","asr30d","calls30d"]}}},"required":["windowDays","unit","buyers"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/routes/{id}/buyers/sms-review/{reviewId}":{"post":{"operationId":"postRoutesByIdBuyersSmsReviewByReviewId","tags":["Marketplace routes"],"summary":"POST /api/v1/routes/{id}/buyers/sms-review/{reviewId}","description":"**Auth:** API key or JWT. Scoped keys need `routes:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":" Response shape not documented yet: the standard `{ \"success\": true, \"data\": ... }` envelope."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"reviewId","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>","reviewId":"<reviewId>"},"query":{}}}},"/api/v1/routes/{id}/readiness":{"get":{"operationId":"getRoutesByIdReadiness","tags":["Marketplace routes"],"summary":"GET /api/v1/routes/{id}/readiness","description":"**Auth:** API key or JWT. Scoped keys need `routes:read`.","responses":{"200":{"description":" Response shape not documented yet: the standard `{ \"success\": true, \"data\": ... }` envelope."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/routes/{id}/buyer-preview":{"get":{"operationId":"getRoutesByIdBuyerPreview","tags":["Marketplace routes"],"summary":"GET /api/v1/routes/{id}/buyer-preview","description":"**Auth:** API key or JWT. Scoped keys need `routes:read`.","responses":{"200":{"description":" Response shape not documented yet: the standard `{ \"success\": true, \"data\": ... }` envelope."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/routes/{id}/rate-increments":{"get":{"operationId":"getRoutesByIdRateIncrements","tags":["Marketplace routes"],"summary":"Show the billing increments your rate sheet sets","description":"Owner only: anyone other than the route's seller gets 403 FORBIDDEN. Groups the route's active rate rows by billing increment (e.g. 1/1 on some destinations, 60/60 on others). Rows with a null increment inherit `fallback`, the route-level increment.\n\n**Auth:** API key or JWT. Scoped keys need `routes:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"mix":{"type":"array","items":{"type":"object","properties":{"increment":{"type":"string","nullable":true,"description":"e.g. \"60/60\"; null = the row uses the route fallback"},"destinations":{"type":"integer","description":"Active rate rows with this increment"}},"required":["increment","destinations"]}},"fallback":{"type":"string","nullable":true,"description":"The route-level billing increment"}},"required":["mix","fallback"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/routes/{id}/rate-sheets":{"post":{"operationId":"postRoutesByIdRateSheets","tags":["Rate sheets"],"summary":"Upload a rate sheet to a route","description":"Multipart upload (field `file`, CSV or Excel). Creates an import to preview, diff and apply; nothing is priced until you apply it.\n\n**Auth:** API key or JWT. Scoped keys need `routes:write`.\n\n**Rate limit:** 10 requests per minute per caller.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"routeId":{"type":"string","format":"uuid"},"filename":{"type":"string"},"fileType":{"type":"string"},"status":{"type":"string"},"rowCount":{"type":"integer","nullable":true},"columnMapping":{},"previewRows":{},"warnings":{},"currency":{"type":"string","nullable":true},"fxRate":{"type":"string","nullable":true},"errorMessage":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"appliedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"rawSample":{},"summary":{},"confidence":{}},"required":["id","routeId","filename","fileType","status","rowCount","currency","fxRate","errorMessage","createdAt","appliedAt"],"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:write","x-rate-limit":{"max":10,"window":"minute"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","description":"CSV or Excel rate sheet (binary)"}},"required":["file"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{}}},"get":{"operationId":"getRoutesByIdRateSheets","tags":["Rate sheets"],"summary":"List rate-sheet imports for a route","description":"**Auth:** API key or JWT. Scoped keys need `routes:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/RateSheetImport"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/routes/{id}/rate-sheets/quick":{"post":{"operationId":"postRoutesByIdRateSheetsQuick","tags":["Rate sheets"],"summary":"Upload and apply a rate sheet in one step","description":"Applies straight away when the sheet reads unambiguously; otherwise returns `outcome: \"review\"` with the reasons.\n\n**Auth:** API key or JWT. Scoped keys need `routes:write`.\n\n**Rate limit:** 10 requests per minute per caller.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"outcome":{"type":"string"}},"required":["outcome"],"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:write","x-rate-limit":{"max":10,"window":"minute"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","description":"CSV or Excel rate sheet (binary)"}},"required":["file"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/routes/{id}/rate-sheets/{importId}":{"get":{"operationId":"getRoutesByIdRateSheetsByImportId","tags":["Rate sheets"],"summary":"Get a rate-sheet import","description":"**Auth:** API key or JWT. Scoped keys need `routes:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"routeId":{"type":"string","format":"uuid"},"filename":{"type":"string"},"fileType":{"type":"string"},"status":{"type":"string"},"rowCount":{"type":"integer","nullable":true},"columnMapping":{},"previewRows":{},"warnings":{},"currency":{"type":"string","nullable":true},"fxRate":{"type":"string","nullable":true},"errorMessage":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"appliedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"rawSample":{}},"required":["id","routeId","filename","fileType","status","rowCount","currency","fxRate","errorMessage","createdAt","appliedAt"],"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"importId","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>","importId":"<importId>"},"query":{}}}},"/api/v1/routes/{id}/rate-sheets/{importId}/preview":{"post":{"operationId":"postRoutesByIdRateSheetsByImportIdPreview","tags":["Rate sheets"],"summary":"Preview a rate-sheet import","description":"**Auth:** API key or JWT. Scoped keys need `routes:write`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{},"additionalProperties":true,"description":"Parsed rows as they would be priced"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"importId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"fxRate":{"type":"number","exclusiveMinimum":true,"minimum":0,"description":"Multiply source rates by this to convert to USD"},"mapping":{"description":"Column mapping override"},"overrides":{"type":"object","additionalProperties":{"type":"object","properties":{"rate":{"type":"string","maxLength":32}}}},"defaultIncrement":{"type":"string","pattern":"^\\d{1,3}\\/\\d{1,3}$","nullable":true},"increaseEffectiveAt":{"anyOf":[{"type":"string","enum":["now"]},{"type":"string","format":"date-time"}],"nullable":true,"description":"When the sheet's increases take effect: \"now\", an ISO instant, or omitted for the default notice period (diff and apply only)"}}}}}},"x-px-example":{"path":{"id":"<id>","importId":"<importId>"},"query":{},"body":{"fxRate":1,"mapping":"<mapping>"}}}},"/api/v1/routes/{id}/rate-sheets/{importId}/diff":{"post":{"operationId":"postRoutesByIdRateSheetsByImportIdDiff","tags":["Rate sheets"],"summary":"Compare a rate-sheet import with the live deck","description":"**Auth:** API key or JWT. Scoped keys need `routes:write`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{},"additionalProperties":true,"description":"Added, changed and removed rows"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"importId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"fxRate":{"type":"number","exclusiveMinimum":true,"minimum":0,"description":"Multiply source rates by this to convert to USD"},"mapping":{"description":"Column mapping override"},"overrides":{"type":"object","additionalProperties":{"type":"object","properties":{"rate":{"type":"string","maxLength":32}}}},"defaultIncrement":{"type":"string","pattern":"^\\d{1,3}\\/\\d{1,3}$","nullable":true},"increaseEffectiveAt":{"anyOf":[{"type":"string","enum":["now"]},{"type":"string","format":"date-time"}],"nullable":true,"description":"When the sheet's increases take effect: \"now\", an ISO instant, or omitted for the default notice period (diff and apply only)"}}}}}},"x-px-example":{"path":{"id":"<id>","importId":"<importId>"},"query":{},"body":{"fxRate":1,"mapping":"<mapping>"}}}},"/api/v1/routes/{id}/rate-sheets/{importId}/apply":{"post":{"operationId":"postRoutesByIdRateSheetsByImportIdApply","tags":["Rate sheets"],"summary":"Apply a rate-sheet import","description":"Rate increases put list-rate buyers on hold until they accept the new rate.\n\n**Auth:** API key or JWT. Scoped keys need `routes:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"applied":{"type":"integer"},"added":{"type":"integer"},"changed":{"type":"integer"},"removed":{"type":"integer"},"droppedBlocked":{"type":"integer"},"diff":{}},"required":["applied","added","changed","removed","droppedBlocked"],"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"importId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"fxRate":{"type":"number","exclusiveMinimum":true,"minimum":0,"description":"Multiply source rates by this to convert to USD"},"mapping":{"description":"Column mapping override"},"overrides":{"type":"object","additionalProperties":{"type":"object","properties":{"rate":{"type":"string","maxLength":32}}}},"defaultIncrement":{"type":"string","pattern":"^\\d{1,3}\\/\\d{1,3}$","nullable":true},"increaseEffectiveAt":{"anyOf":[{"type":"string","enum":["now"]},{"type":"string","format":"date-time"}],"nullable":true,"description":"When the sheet's increases take effect: \"now\", an ISO instant, or omitted for the default notice period (diff and apply only)"}}}}}},"x-px-example":{"path":{"id":"<id>","importId":"<importId>"},"query":{},"body":{"fxRate":1,"mapping":"<mapping>"}}}},"/api/v1/routes/{id}/rate-sheets/{importId}/rollback":{"post":{"operationId":"postRoutesByIdRateSheetsByImportIdRollback","tags":["Rate sheets"],"summary":"Roll a route back to an earlier rate-sheet import","description":"**Auth:** API key or JWT. Scoped keys need `routes:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"applied":{"type":"integer"},"added":{"type":"integer"},"changed":{"type":"integer"},"removed":{"type":"integer"},"droppedBlocked":{"type":"integer"},"diff":{}},"required":["applied","added","changed","removed","droppedBlocked"],"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"importId","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>","importId":"<importId>"},"query":{}}}},"/api/v1/routes/{id}/rate-sheets/{importId}/reapply":{"post":{"operationId":"postRoutesByIdRateSheetsByImportIdReapply","tags":["Rate sheets"],"summary":"Reapply a rate-sheet import with new settings","description":"**Auth:** API key or JWT. Scoped keys need `routes:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"applied":{"type":"integer"},"added":{"type":"integer"},"changed":{"type":"integer"},"removed":{"type":"integer"},"droppedBlocked":{"type":"integer"},"diff":{}},"required":["applied","added","changed","removed","droppedBlocked"],"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"importId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"fxRate":{"type":"number","exclusiveMinimum":true,"minimum":0,"description":"Multiply source rates by this to convert to USD"},"mapping":{"description":"Column mapping override"},"overrides":{"type":"object","additionalProperties":{"type":"object","properties":{"rate":{"type":"string","maxLength":32}}}},"defaultIncrement":{"type":"string","pattern":"^\\d{1,3}\\/\\d{1,3}$","nullable":true},"increaseEffectiveAt":{"anyOf":[{"type":"string","enum":["now"]},{"type":"string","format":"date-time"}],"nullable":true,"description":"When the sheet's increases take effect: \"now\", an ISO instant, or omitted for the default notice period (diff and apply only)"}}}}}},"x-px-example":{"path":{"id":"<id>","importId":"<importId>"},"query":{},"body":{"fxRate":1,"mapping":"<mapping>"}}}},"/api/v1/routes/{id}/publish-by-country":{"post":{"operationId":"postRoutesByIdPublishByCountry","tags":["Rate sheets"],"summary":"Publish an A-Z deck as per-country listings","description":"**Auth:** API key or JWT. Scoped keys need `routes:write`.\n\n**Rate limit:** 6 requests per minute per caller.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{},"additionalProperties":true,"description":"The listings created"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:write","x-rate-limit":{"max":6,"window":"minute"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"perCarrier":{"type":"boolean"}}}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"perCarrier":true}}}},"/api/v1/routes/{id}/collapse-bundle":{"post":{"operationId":"postRoutesByIdCollapseBundle","tags":["Rate sheets"],"summary":"Collapse per-country listings back into one deck","description":"**Auth:** API key or JWT. Scoped keys need `routes:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"removed":{"type":"integer"}},"required":["removed"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/routes/{id}/children":{"get":{"operationId":"getRoutesByIdChildren","tags":["Rate sheets"],"summary":"List the per-country listings of a deck","description":"**Auth:** API key or JWT. Scoped keys need `routes:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/routes/{id}/rates":{"get":{"operationId":"getRoutesByIdRates","tags":["Rate sheets"],"summary":"List per-destination rates on a route","description":"Public for public routes. Buyers see cleaned destination names and no upstream operator labels.\n\n**Auth:** optional. Works anonymously; a token or API key personalises the answer.","responses":{"200":{"description":"Rows at the top level as `rates`, with `total` (not nested under `data`).","content":{"application/json":{"schema":{"type":"object","required":["success","rates","total"],"properties":{"success":{"type":"boolean","enum":[true]},"rates":{"type":"array","items":{"$ref":"#/components/schemas/RouteRate"}},"total":{"type":"integer"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"optional","security":[{},{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"search","in":"query","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}},"post":{"operationId":"postRoutesByIdRates","tags":["Rate sheets"],"summary":"Add a rate to your route's deck","description":"**Auth:** API key or JWT. Scoped keys need `routes:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"routeId":{"type":"string","format":"uuid"},"destinationName":{"type":"string"},"operator":{"type":"string","nullable":true},"prefix":{"type":"string"},"ratePerUnit":{"$ref":"#/components/schemas/Money"},"billingIncrement":{"type":"string","nullable":true},"minDuration":{"type":"integer","nullable":true},"effectiveDate":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"status":{"type":"string"},"mccMnc":{"type":"string","nullable":true,"description":"SMS sheets priced by network code: the network the row price came from (\"214\" = whole country)"},"operatorRates":{"type":"array","items":{"type":"object","properties":{"mccMnc":{"type":"string","description":"\"214-07\" for one network; \"214\" for All Operators"},"operator":{"type":"string","nullable":true},"rate":{"$ref":"#/components/schemas/Money"}},"required":["mccMnc","operator","rate"]},"nullable":true,"description":"SMS sheets priced by network: the price per destination network (charged per network when `networkPriced` is true). A message is charged its network's rate (networks not listed pay the All Operators rate when there is one); `ratePerUnit` is the price for other or unknown networks. The network is determined from the number's range (ported numbers may be priced at the network the range belongs to)"},"networkPriced":{"type":"boolean","description":"True when each SMS on this row is charged its destination network's rate from `operatorRates`; `ratePerUnit` then applies to other or unknown networks"},"updated":{"type":"boolean"}},"required":["id","routeId","destinationName","operator","prefix","ratePerUnit","billingIncrement","minDuration","effectiveDate","status","updated"],"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"destinationName":{"type":"string","minLength":1,"maxLength":255},"operator":{"type":"string","maxLength":120,"nullable":true},"prefix":{"type":"string","minLength":1,"maxLength":24},"ratePerUnit":{"type":"string","pattern":"^\\d+\\.\\d{1,6}$"},"billingIncrement":{"type":"string","maxLength":10},"minDuration":{"type":"integer","minimum":0}},"required":["destinationName","prefix","ratePerUnit"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"destinationName":"<destinationName>","prefix":"44","ratePerUnit":"<ratePerUnit>"}}}},"/api/v1/routes/{id}/coverage":{"get":{"operationId":"getRoutesByIdCoverage","tags":["Marketplace routes"],"summary":"GET /api/v1/routes/{id}/coverage","description":"**Auth:** API key or JWT. Scoped keys need `routes:read`.","responses":{"200":{"description":" Response shape not documented yet: the standard `{ \"success\": true, \"data\": ... }` envelope."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/routes/{id}/operator-rates":{"get":{"operationId":"getRoutesByIdOperatorRates","tags":["Marketplace routes"],"summary":"GET /api/v1/routes/{id}/operator-rates","description":"**Auth:** API key or JWT. Scoped keys need `routes:read`.","responses":{"200":{"description":" Response shape not documented yet: the standard `{ \"success\": true, \"data\": ... }` envelope."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/routes/{id}/line-type-evidence":{"get":{"operationId":"getRoutesByIdLineTypeEvidence","tags":["Marketplace routes"],"summary":"GET /api/v1/routes/{id}/line-type-evidence","description":"**Auth:** API key or JWT. Scoped keys need `routes:read`.","responses":{"200":{"description":" Response shape not documented yet: the standard `{ \"success\": true, \"data\": ... }` envelope."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/routes/{id}/networks":{"get":{"operationId":"getRoutesByIdNetworks","tags":["Marketplace routes"],"summary":"GET /api/v1/routes/{id}/networks","description":"**Auth:** API key or JWT. Scoped keys need `routes:read`.","responses":{"200":{"description":" Response shape not documented yet: the standard `{ \"success\": true, \"data\": ... }` envelope."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/routes/{id}/rates/export":{"get":{"operationId":"getRoutesByIdRatesExport","tags":["Rate sheets"],"summary":"Export a route's rates as CSV","description":"**Auth:** optional. Works anonymously; a token or API key personalises the answer.","responses":{"200":{"description":"The deck as CSV (attachment).","content":{"text/csv":{"schema":{"type":"string","format":"binary"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"optional","security":[{},{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/routes/{id}/rates/imports/{importId}/rejected":{"get":{"operationId":"getRoutesByIdRatesImportsByImportIdRejected","tags":["Marketplace routes"],"summary":"GET /api/v1/routes/{id}/rates/imports/{importId}/rejected","description":"**Auth:** API key or JWT. Scoped keys need `routes:read`.","responses":{"200":{"description":" Response shape not documented yet: the standard `{ \"success\": true, \"data\": ... }` envelope."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"importId","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>","importId":"<importId>"},"query":{}}}},"/api/v1/routes/{id}/rates/imports/{importId}/rejected.csv":{"get":{"operationId":"getRoutesByIdRatesImportsByImportIdRejectedCsv","tags":["Marketplace routes"],"summary":"GET /api/v1/routes/{id}/rates/imports/{importId}/rejected.csv","description":"**Auth:** API key or JWT. Scoped keys need `routes:read`.","responses":{"200":{"description":" Response shape not documented yet: the standard `{ \"success\": true, \"data\": ... }` envelope."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"importId","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>","importId":"<importId>"},"query":{}}}},"/api/v1/routes/{id}/rates/bulk":{"post":{"operationId":"postRoutesByIdRatesBulk","tags":["Rate sheets"],"summary":"Add many rates to your route's deck","description":"**Auth:** API key or JWT. Scoped keys need `routes:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"added":{"type":"integer"},"updated":{"type":"integer"},"skipped":{"type":"integer"},"skippedRows":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}}},"required":["added","updated","skipped","skippedRows"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"rows":{"type":"array","items":{"type":"object","properties":{"destinationName":{"type":"string","maxLength":255},"operator":{"type":"string","maxLength":120,"nullable":true},"prefix":{"type":"string","maxLength":24},"ratePerUnit":{"type":"string","maxLength":32},"billingIncrement":{"type":"string","maxLength":10},"minDuration":{"type":"integer","minimum":0}},"required":["prefix","ratePerUnit"]},"minItems":1,"maxItems":5000}},"required":["rows"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"rows":[{"prefix":"44","ratePerUnit":"<ratePerUnit>"}]}}}},"/api/v1/routes/{id}/rates/{rateId}":{"patch":{"operationId":"patchRoutesByIdRatesByRateId","tags":["Rate sheets"],"summary":"Edit or block one rate in your deck","description":"**Auth:** API key or JWT. Scoped keys need `routes:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/RouteRate"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"rateId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"destinationName":{"type":"string","minLength":1,"maxLength":255},"ratePerUnit":{"type":"string","pattern":"^\\d+\\.\\d{1,6}$"},"billingIncrement":{"type":"string","maxLength":10,"nullable":true},"minDuration":{"type":"integer","minimum":0,"nullable":true},"blocked":{"type":"boolean"}}}}}},"x-px-example":{"path":{"id":"<id>","rateId":"<rateId>"},"query":{},"body":{"destinationName":"<destinationName>","ratePerUnit":"<ratePerUnit>"}}},"delete":{"operationId":"deleteRoutesByIdRatesByRateId","tags":["Rate sheets"],"summary":"Delete one rate from your deck","description":"**Auth:** API key or JWT. Scoped keys need `routes:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/Message"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"rateId","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>","rateId":"<rateId>"},"query":{}}}},"/api/v1/routes/{id}/rate-changes":{"get":{"operationId":"getRoutesByIdRateChanges","tags":["Rate sheets"],"summary":"List scheduled rate changes on your route","description":"With how many buyers are held by each change and how many already accepted it.\n\n**Auth:** API key or JWT. Scoped keys need `routes:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"kind":{"type":"string"},"status":{"type":"string"},"effectiveDate":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"increases":{"type":"integer"},"decreases":{"type":"integer"},"added":{"type":"integer"},"removed":{"type":"integer"},"largestIncreasePct":{"type":"number","nullable":true},"sampleOldRate":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"US dollars as a decimal string with exactly 6 decimal places, e.g. \"0.012500\". Do money arithmetic with a decimal type, not floating point."},"sampleNewRate":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"US dollars as a decimal string with exactly 6 decimal places, e.g. \"0.012500\". Do money arithmetic with a decimal type, not floating point."},"flatOldPrice":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"US dollars as a decimal string with exactly 6 decimal places, e.g. \"0.012500\". Do money arithmetic with a decimal type, not floating point."},"flatNewPrice":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"US dollars as a decimal string with exactly 6 decimal places, e.g. \"0.012500\". Do money arithmetic with a decimal type, not floating point."},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"notifiedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"promotedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"cancelledAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"heldPurchases":{"type":"integer","nullable":true},"acceptedPurchases":{"type":"integer"}},"required":["id","kind","status","effectiveDate","increases","decreases","added","removed","largestIncreasePct","sampleOldRate","sampleNewRate","flatOldPrice","flatNewPrice","createdAt","notifiedAt","promotedAt","cancelledAt","heldPurchases","acceptedPurchases"]}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/routes/{id}/rate-changes/flat":{"post":{"operationId":"postRoutesByIdRateChangesFlat","tags":["Rate sheets"],"summary":"Schedule a price change on a one-price route","description":"An increase takes effect after the notice period when list-rate buyers are bound; buyers are notified and can accept in advance. Replaces any change already scheduled.\n\n**Auth:** API key or JWT. Scoped keys need `routes:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"scheduled":{"type":"boolean","description":"False when the change applied immediately"},"changeId":{"type":"string","format":"uuid"},"effectiveDate":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"boundBuyers":{"type":"integer"}},"required":["scheduled","changeId","effectiveDate","boundBuyers"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"newPrice":{"type":"string","pattern":"^\\d+(\\.\\d{1,6})?$"},"effectiveDate":{"type":"string","format":"date-time","nullable":true,"description":"Omit for the default notice period"}},"required":["newPrice"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"newPrice":"<newPrice>"}}}},"/api/v1/routes/{id}/rate-changes/{changeId}/cancel":{"post":{"operationId":"postRoutesByIdRateChangesByChangeIdCancel","tags":["Rate sheets"],"summary":"Withdraw a scheduled rate change","description":"**Auth:** API key or JWT. Scoped keys need `routes:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"cancelled":{"type":"boolean","enum":[true]}},"required":["cancelled"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"changeId","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>","changeId":"<changeId>"},"query":{}}}},"/api/v1/routes/blends/member-rates":{"post":{"operationId":"postRoutesBlendsMemberRates","tags":["Marketplace routes"],"summary":"POST /api/v1/routes/blends/member-rates","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":" Response shape not documented yet: the standard `{ \"success\": true, \"data\": ... }` envelope."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/routes/blends/preview":{"post":{"operationId":"postRoutesBlendsPreview","tags":["Route blends"],"summary":"Preview a blended route","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"blendedRate":{"type":"number","description":"Weighted rate (display figure)"},"capacity":{"type":"number"},"memberCount":{"type":"integer"},"members":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}},"coverage":{"type":"object","properties":{},"additionalProperties":true,"nullable":true},"coverageSummary":{"type":"string","nullable":true}},"required":["blendedRate","capacity","memberCount","members","coverage","coverageSummary"],"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"members":{"type":"array","items":{"type":"object","properties":{"memberRouteId":{"type":"string","format":"uuid","nullable":true},"memberVendorTrunkId":{"type":"string","format":"uuid","nullable":true},"rate":{"type":"number","minimum":0},"weightPct":{"type":"number","minimum":0,"maximum":100},"routeType":{"type":"string","enum":["direct","premium","standard","ncli"]},"capacity":{"type":"integer","minimum":0},"maxCps":{"type":"integer","minimum":0},"priority":{"type":"integer","minimum":1,"maximum":20},"enabled":{"type":"boolean"}},"required":["rate","weightPct"]},"minItems":1,"maxItems":20},"type":{"type":"string","enum":["voice","sms"]},"countryCode":{"type":"string","pattern":"^\\d{1,3}$"},"numberType":{"type":"string","enum":["mobile","fixed","both"]}},"required":["members"]}}}},"x-px-example":{"path":{},"query":{},"body":{"members":[{"rate":1,"weightPct":1}]}}}},"/api/v1/routes/blends/propose":{"post":{"operationId":"postRoutesBlendsPropose","tags":["Route blends"],"summary":"Propose the cheapest complete blend for a destination","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.\n\n**Rate limit:** 20 requests per minute per caller.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{},"additionalProperties":true,"description":"Proposed members, their coverage and a coverage summary"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-rate-limit":{"max":20,"window":"minute"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"type":{"type":"string","enum":["voice","sms"],"default":"voice"},"countryCode":{"type":"string","pattern":"^\\d{1,3}$"},"numberType":{"type":"string","enum":["mobile","fixed","both"],"default":"both"}},"required":["countryCode"]}}}},"x-px-example":{"path":{},"query":{},"body":{"countryCode":"GB"}}}},"/api/v1/routes/blends":{"get":{"operationId":"getRoutesBlends","tags":["Route blends"],"summary":"List your blended routes","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}},"post":{"operationId":"postRoutesBlends","tags":["Route blends"],"summary":"Create a blended route","description":"Refused when no member is enabled, or when the blend cannot carry the destination it claims unless `acknowledgeIncomplete` is set.\n\n**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.\n\n**Rate limit:** 30 requests per minute per caller.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{},"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-rate-limit":{"max":30,"window":"minute"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"type":{"type":"string","enum":["voice","sms"]},"country":{"type":"string","minLength":1,"maxLength":100},"countryCode":{"type":"string","pattern":"^\\d{1,3}$"},"prefix":{"type":"array","items":{"type":"string","minLength":1,"maxLength":15},"maxItems":100},"destinationName":{"type":"string","minLength":1,"maxLength":255},"cliType":{"type":"string","enum":["full_cli","ncli","local_cli","mixed_cli"]},"billingIncrement":{"type":"string","pattern":"^\\d{1,4}\\/\\d{1,4}$"},"visibility":{"type":"string","enum":["public","private"]},"dialerCompatible":{"type":"boolean"},"members":{"type":"array","items":{"type":"object","properties":{"memberRouteId":{"type":"string","format":"uuid","nullable":true},"memberVendorTrunkId":{"type":"string","format":"uuid","nullable":true},"rate":{"type":"number","minimum":0},"weightPct":{"type":"number","minimum":0,"maximum":100},"routeType":{"type":"string","enum":["direct","premium","standard","ncli"]},"capacity":{"type":"integer","minimum":0},"maxCps":{"type":"integer","minimum":0},"priority":{"type":"integer","minimum":1,"maximum":20},"enabled":{"type":"boolean"}},"required":["rate","weightPct"]},"minItems":1,"maxItems":20},"numberType":{"type":"string","enum":["mobile","fixed","both"]},"acknowledgeIncomplete":{"type":"boolean"}},"required":["name","type","country","countryCode","members"]}}}},"x-px-example":{"path":{},"query":{},"body":{"name":"Acme","type":"voice","country":"United Kingdom","countryCode":"GB","members":[{"rate":1,"weightPct":1}]}}}},"/api/v1/routes/blends/{id}":{"get":{"operationId":"getRoutesBlendsById","tags":["Route blends"],"summary":"Get a blended route","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"type":{"type":"string","enum":["voice","sms"]},"country":{"type":"string"},"countryCode":{"type":"string"},"visibility":{"type":"string","enum":["public","private"]},"status":{"type":"string","enum":["active","paused","suspended","pending_review"]},"numberType":{"type":"string","nullable":true},"coverage":{"type":"object","properties":{},"additionalProperties":true,"nullable":true},"coverageSummary":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","name","type","country","countryCode","visibility","status","numberType","coverage","coverageSummary","createdAt"],"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}},"patch":{"operationId":"patchRoutesBlendsById","tags":["Route blends"],"summary":"Update a blended route","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{},"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"visibility":{"type":"string","enum":["public","private"]},"dialerCompatible":{"type":"boolean"},"members":{"type":"array","items":{"type":"object","properties":{"memberRouteId":{"type":"string","format":"uuid","nullable":true},"memberVendorTrunkId":{"type":"string","format":"uuid","nullable":true},"rate":{"type":"number","minimum":0},"weightPct":{"type":"number","minimum":0,"maximum":100},"routeType":{"type":"string","enum":["direct","premium","standard","ncli"]},"capacity":{"type":"integer","minimum":0},"maxCps":{"type":"integer","minimum":0},"priority":{"type":"integer","minimum":1,"maximum":20},"enabled":{"type":"boolean"}},"required":["rate","weightPct"]},"minItems":1,"maxItems":20},"numberType":{"type":"string","enum":["mobile","fixed","both"]},"acknowledgeIncomplete":{"type":"boolean"}}}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"name":"Acme","visibility":"public"}}},"delete":{"operationId":"deleteRoutesBlendsById","tags":["Route blends"],"summary":"Archive a blended route","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"archived":{"type":"boolean","enum":[true]}},"required":["archived"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/routes/check":{"post":{"operationId":"postRoutesCheck","tags":["Route checks"],"summary":"Check up to three routes before buying","description":"Places one short real call over each route (1 to 3, in your order: the first is your primary, the rest backups) and reports whether it works. Returns `202` with a `checkId` at once; poll GET /routes/check/{checkId}.\n\n- **network** (default): the call goes to a public line that answers by itself (a speaking clock or information line) in the destination, chosen from the ones the route's rates cover and, where we have one, of the same line type as `number` (mobile or fixed). The call is answered, held about two seconds and ended. Where no such line exists yet for a destination, a lighter check runs instead: it confirms only that the route accepts calls, places no call to anyone, and says so (`accepts`).\n- **ring_me**: the route calls `number`, which must be your own phone in a country the route serves. Ringing counts as working. Satellite and premium-rate ranges are refused; one number can be rung by checks 10 times an hour, and an account can ring 10 different numbers a day (`429`).\n\n`number` (network mode) narrows the check to a destination: a dial code (`92`) or a full number (`+923001234567`); for an A-Z rate sheet pass it, or the route's own country is used.\n\nBilling: each connected leg is charged at the route's rate (your own effective rate for that number) for the billable seconds, plus the normal platform fee, from your test credit first and then your balance (`paidFrom` says which). Test credit covers at most $1 of checks on any one seller's routes; beyond that the balance pays. Unanswered legs and suspected false answers cost nothing; a check of your own listing is free. A funded balance is required (`400` otherwise). Limits: 10 checks a minute and 60 an hour per account (`429`); when the limiter cannot be reached checks pause (`503`) rather than run unlimited. Send `X-Idempotency-Key` to make a retry safe: the retry returns the first check instead of placing a second. Blended routes cannot be checked yet (`400`). A test key returns a simulated result immediately: no call, no charge.\n\nYou may check routes you have not bought. Private routes need an access grant.\n\n**Auth:** API key or JWT. Scoped keys need `voice:send`.","responses":{"202":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"checkId":{"type":"string","format":"uuid"}},"required":["checkId"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"voice:send","x-error-codes":["RATE_LIMITED","SERVICE_UNAVAILABLE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"routeIds":{"type":"array","items":{"type":"string","format":"uuid"},"minItems":1,"maxItems":3,"description":"1 to 3 route ids, in your order: the first is your primary, the rest backups"},"number":{"type":"string","maxLength":32,"description":"network mode: a dial code or full number to check for (narrows an A-Z rate sheet to that destination and line type). ring_me mode: your own number, required"},"mode":{"type":"string","enum":["network","ring_me"],"default":"network","description":"network = our test lines (default); ring_me = the route calls your own number"}},"required":["routeIds"]}}}},"x-px-example":{"path":{},"query":{},"body":{"routeIds":["<routeId>"]}}}},"/api/v1/routes/check/sms":{"post":{"operationId":"postRoutesCheckSms","tags":["Route checks"],"summary":"Send a test SMS over an SMS route","description":"Sends ONE short fixed message over exactly this SMS listing (never Smart Routing) to your own mobile, by the same transport a real message uses, and reports what happened. Returns `202` with a `checkId` at once; poll GET /routes/check/{checkId} (the test is its only route). The text is fixed and so is the sender: \"PacketExchange test message: this route delivered to your phone. Ref K7QD\", from a platform sender chosen by the route's sender rules (numeric on a route that carries numeric senders only).\n\nResults: `accepted` (the route took it; no carrier receipt yet), `delivered` (a carrier receipt confirmed it) or `refused` (the route refused it, or the receipt said it failed; `errorCode` says which). Receipts usually arrive within a minute; on a route that returns none the test stays `accepted`, and `routeReturnsReceipts` says whether the route has returned any lately. A later receipt updates the test, so it also appears in GET /routes/checks.\n\n`number` must be a mobile in international format that the route covers (by its rate sheet or its prefixes, longest prefix first); a number it does not cover is refused (`400`), as are premium-rate, satellite, special-service and short-code ranges, embargoed destinations and numbers on your Do-Not-Contact list.\n\nBilling: the route's normal price for one message for that number (your own effective rate), plus the normal platform fee, from your test credit first and then your balance (`paidFrom`). Test credit covers at most $1 of tests on any one seller's routes; beyond that the balance pays. A message the route refuses is not charged, and one whose receipt says it failed is refunded. Testing your own listing is free. Limits: 3 test messages to one number an hour (across all accounts), 5 different numbers and 20 test messages per account a day (`429`); when the limiter cannot be reached tests pause (`503`). Send `X-Idempotency-Key` to make a retry safe. A test key returns a simulated result at once: nothing is sent and nothing is charged.\n\nTest messages never count in SMS volume, revenue or quality figures. A buyer's delivered test counts as working and a refused one as a failure on the listing's check health, which the seller sees without learning who ran it.\n\n**Auth:** API key or JWT. Scoped keys need `sms:send`.","responses":{"202":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"checkId":{"type":"string","format":"uuid"}},"required":["checkId"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"sms:send","x-error-codes":["RATE_LIMITED","SERVICE_UNAVAILABLE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"routeId":{"type":"string","format":"uuid","description":"The SMS listing to test (a marketplace route id)"},"number":{"type":"string","minLength":1,"maxLength":32,"description":"Your own mobile number in international format (E.164), e.g. +35056012345. The route must cover it"}},"required":["routeId","number"]}}}},"x-px-example":{"path":{},"query":{},"body":{"routeId":"<routeId>","number":"+447700900123"}}}},"/api/v1/routes/check/coverage":{"get":{"operationId":"getRoutesCheckCoverage","tags":["Route checks"],"summary":"Is there a test line for these routes?","description":"For each route (1 to 3), whether we have a registered public test line for its destination (or for `number`'s destination on an A-Z rate sheet). When there is none, check the route with `mode: ring_me` and your own number. Says yes or no only.\n\n**Auth:** API key or JWT. Scoped keys need `routes:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"routeId":{"type":"string","format":"uuid"},"testLine":{"type":"boolean"}},"required":["routeId","testLine"]}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"routeIds","in":"query","required":true,"description":"Comma-separated route ids (1 to 3)","schema":{"allOf":[{"type":"string","minLength":1,"maxLength":200},{"type":"array","items":{"type":"string","format":"uuid"},"minItems":1,"maxItems":3}]}},{"name":"number","in":"query","required":false,"description":"Optional dial code or number, to ask about one destination of an A-Z rate sheet","schema":{"type":"string","maxLength":32}}],"x-px-example":{"path":{},"query":{"routeIds":"<routeIds>"}}}},"/api/v1/routes/check/{id}":{"get":{"operationId":"getRoutesCheckById","tags":["Route checks"],"summary":"Get a route check's results","description":"Per-route verdicts, in your order. `message` is the sentence to show a person. Routes are named without seller details.\n\n**Auth:** API key or JWT. Scoped keys need `routes:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/RouteCheck"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The check id from POST /routes/check"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/routes/checks":{"get":{"operationId":"getRoutesChecks","tags":["Route checks"],"summary":"List your recent route checks","description":"**Auth:** API key or JWT. Scoped keys need `routes:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/RouteCheck"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":50,"default":20}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/routes/check/{id}/purchase":{"post":{"operationId":"postRoutesCheckByIdPurchase","tags":["Route checks"],"summary":"Buy the routes that passed a check and set the routing order","description":"Buys every route in the check that came back working, in your order, and puts them at the top of your routing order: the first is the primary, the rest its backups (your other ranked routes keep their relative order below them). Routes you already bought are reused. A route that cannot be bought (for example email not verified, a private route, or a US route that needs compliance review) is reported in `purchases[].error` and does not stop the others. Needs a live key.\n\n**Auth:** API key or JWT. Scoped keys need `purchases:write`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/RouteCheckPurchase"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"purchases:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The check id from POST /routes/check"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/routes/{id}/check-health":{"get":{"operationId":"getRoutesByIdCheckHealth","tags":["Route checks"],"summary":"Check health of a route you sell","description":"For your own listing: the last 24 hours of full route checks (working vs failed), the recent checks, and any suspension made by checks with its reason and evidence. A listing whose checks fail 10 or more times in 24 hours with none working is confirmed once more and then suspended from the marketplace; run POST /routes/check with its id (free for your own listing) after fixing it, and a working result puts it back. A call answered under 1.5 s after our INVITE (or under 2.5 s with no ringing) is a false answer and counts as a failure; `answerMs` is the evidence. Your own checks, checks to a buyer's own number (ring_me) and lighter checks never count. On an SMS listing the window counts buyers' test messages instead: delivered is working, refused is a failure, a message still awaiting a receipt does not count, and an SMS listing is never suspended automatically. `networks` lists every network row of the listing with its state (ok, grace = warned and still listed until `graceUntil`, delisted), real calls answered / attempted in 7 days, caller-ID mark and reason.\n\n**Auth:** API key or JWT. Scoped keys need `routes:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/RouteCheckHealth"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/routes/my/live":{"get":{"operationId":"getRoutesMyLive","tags":["Marketplace routes"],"summary":"GET /api/v1/routes/my/live","description":"**Auth:** API key or JWT. Scoped keys need `routes:read`.","responses":{"200":{"description":" Response shape not documented yet: the standard `{ \"success\": true, \"data\": ... }` envelope."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/routes/purchased/live":{"get":{"operationId":"getRoutesPurchasedLive","tags":["Marketplace routes"],"summary":"GET /api/v1/routes/purchased/live","description":"**Auth:** API key or JWT. Scoped keys need `routes:read`.","responses":{"200":{"description":" Response shape not documented yet: the standard `{ \"success\": true, \"data\": ... }` envelope."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/topups":{"get":{"operationId":"getTopups","tags":["Top-ups"],"summary":"List your top-ups","description":"Your 50 most recent top-ups of every method and status.\n\n**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/Topup"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/topups/stripe":{"post":{"operationId":"postTopupsStripe","tags":["Top-ups"],"summary":"Start a card top-up","description":"Creates a pending top-up and a card payment to confirm client-side with `clientSecret` and `publishableKey`. The balance is credited when the card processor confirms the payment. If card payments are not enabled, the pending top-up is returned with a `message` instead. Requires identity verification when the platform enforces it (403 `KYC_REQUIRED`), and is subject to account flags and top-up velocity limits.\n\n**Auth:** API key or JWT. Scoped keys need `billing:write`.\n\n**Idempotency:** send an `X-Idempotency-Key` header to make retries safe; a replay within 24 hours returns the original response.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"topupId":{"type":"string","format":"uuid"},"amountUsd":{"type":"number","description":"Echo of the requested amount (JSON number)"},"method":{"type":"string","enum":["stripe"]},"status":{"type":"string","enum":["pending"]},"clientSecret":{"type":"string"},"publishableKey":{"type":"string","nullable":true},"message":{"type":"string"}},"required":["topupId","amountUsd","method","status"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"billing:write","x-error-codes":["KYC_REQUIRED","STRIPE_ERROR"],"x-idempotent":true,"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"X-Idempotency-Key","in":"header","required":false,"description":"Any unique string (a UUID is ideal). Replays within 24 hours return the first response instead of acting twice.","schema":{"type":"string","maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"amountUsd":{"type":"number","minimum":5,"maximum":10000}},"required":["amountUsd"]}}}},"x-px-example":{"path":{},"query":{},"body":{"amountUsd":5}},"x-px-billable":{"kind":"money","note":"Starts a payment to top up your balance."}}},"/api/v1/topups/quick-pay":{"get":{"operationId":"getTopupsQuickPay","tags":["Top-ups"],"summary":"GET /api/v1/topups/quick-pay","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":" Response shape not documented yet: the standard `{ \"success\": true, \"data\": ... }` envelope."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/topups/stripe/saved":{"post":{"operationId":"postTopupsStripeSaved","tags":["Top-ups"],"summary":"POST /api/v1/topups/stripe/saved","description":"**Auth:** API key or JWT. Scoped keys need `billing:write`.\n\n**Rate limit:** 10 requests per minute per caller.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":" Response shape not documented yet: the standard `{ \"success\": true, \"data\": ... }` envelope."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"billing:write","x-rate-limit":{"max":10,"window":"minute"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}},"x-px-billable":{"kind":"money","note":"Starts a payment to top up your balance."}}},"/api/v1/topups/progress":{"get":{"operationId":"getTopupsProgress","tags":["Top-ups"],"summary":"GET /api/v1/topups/progress","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":" Response shape not documented yet: the standard `{ \"success\": true, \"data\": ... }` envelope."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/topups/x402":{"post":{"operationId":"postTopupsX402","tags":["Top-ups"],"summary":"Top up with an x402 USDC payment","description":"Pay-per-request top-up using the x402 protocol. Call once without an `X-PAYMENT` header to receive a 402 challenge with the payment requirements; retry with a signed `X-PAYMENT` header to settle and be credited in the same request. A replayed payment returns the original top-up with `already: true`. It settles real USDC on Base mainnet into your live balance, so test keys are refused with 403 `TEST_KEY_NOT_ALLOWED`. Requires identity verification when the platform enforces it (403 `KYC_REQUIRED`), and is subject to account flags and top-up velocity limits.\n\n**Auth:** API key or JWT. Scoped keys need `billing:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"topupId":{"type":"string","format":"uuid"},"amountUsd":{"type":"number"},"method":{"type":"string","enum":["x402"]},"status":{"type":"string","enum":["pending","confirmed"]},"network":{"type":"string"},"txHash":{"type":"string"},"payer":{"type":"string"},"newBalance":{"type":"number","description":"Balance after crediting (JSON number)"},"already":{"type":"boolean"},"message":{"type":"string"}},"required":["topupId","amountUsd","method","status"],"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"billing:write","x-error-codes":["KYC_REQUIRED","TEST_KEY_NOT_ALLOWED"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"amountUsd":{"type":"number","minimum":5,"maximum":50000}},"required":["amountUsd"]}}}},"x-px-example":{"path":{},"query":{},"body":{"amountUsd":5}},"x-px-billable":{"kind":"money","note":"Starts a payment to top up your balance."}}},"/api/v1/topups/crypto":{"post":{"operationId":"postTopupsCrypto","tags":["Top-ups"],"summary":"Start a crypto top-up","description":"Returns where to send funds. When a unique deposit address (or memo) could be allocated, `autoCredit` is true and the deposit credits automatically on confirmation; otherwise send to the shared address quoting `reference` and it is credited after manual verification. A memo, when present, is mandatory. Requires identity verification when the platform enforces it (403 `KYC_REQUIRED`), and is subject to account flags and top-up velocity limits.\n\n**Auth:** API key or JWT. Scoped keys need `billing:write`.\n\n**Rate limit:** 10 requests per minute per caller.\n\n**Idempotency:** send an `X-Idempotency-Key` header to make retries safe; a replay within 24 hours returns the original response.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"topupId":{"type":"string","format":"uuid"},"amountUsd":{"type":"number"},"token":{"type":"string","enum":["BTC","ETH","USDT","USDC","SOL"]},"network":{"type":"string","enum":["bitcoin","ethereum","solana","tron","polygon"]},"depositAddress":{"type":"string"},"memo":{"type":"string","nullable":true},"reference":{"type":"string"},"autoCredit":{"type":"boolean"},"status":{"type":"string","enum":["pending"]},"message":{"type":"string"}},"required":["topupId","amountUsd","token","network","depositAddress","memo","reference","autoCredit","status","message"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"billing:write","x-rate-limit":{"max":10,"window":"minute"},"x-error-codes":["KYC_REQUIRED"],"x-idempotent":true,"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"X-Idempotency-Key","in":"header","required":false,"description":"Any unique string (a UUID is ideal). Replays within 24 hours return the first response instead of acting twice.","schema":{"type":"string","maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"amountUsd":{"type":"number","minimum":5,"maximum":50000},"token":{"type":"string","enum":["BTC","ETH","USDT","USDC","SOL"]},"network":{"type":"string","enum":["bitcoin","ethereum","solana","tron","polygon"]}},"required":["amountUsd","token","network"]}}}},"x-px-example":{"path":{},"query":{},"body":{"amountUsd":5,"token":"BTC","network":"bitcoin"}},"x-px-billable":{"kind":"money","note":"Starts a payment to top up your balance."}}},"/api/v1/topups/wire":{"post":{"operationId":"postTopupsWire","tags":["Top-ups"],"summary":"Start a wire-transfer top-up","description":"Returns bank details and a reference you must quote on the transfer. Credited within 1-3 business days of receipt. 503 `WIRE_UNAVAILABLE` when wire is not offered. Requires identity verification when the platform enforces it (403 `KYC_REQUIRED`), and is subject to account flags and top-up velocity limits.\n\n**Auth:** API key or JWT. Scoped keys need `billing:write`.\n\n**Idempotency:** send an `X-Idempotency-Key` header to make retries safe; a replay within 24 hours returns the original response.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"topupId":{"type":"string","format":"uuid"},"amountUsd":{"type":"number"},"wireReference":{"type":"string"},"bankDetails":{"type":"object","properties":{"bankName":{"type":"string"},"accountName":{"type":"string"},"iban":{"type":"string"},"swift":{"type":"string"},"currency":{"type":"string","enum":["USD"]}},"required":["bankName","accountName","iban","swift","currency"]},"status":{"type":"string","enum":["pending"]},"message":{"type":"string"}},"required":["topupId","amountUsd","wireReference","bankDetails","status","message"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"billing:write","x-error-codes":["KYC_REQUIRED","WIRE_UNAVAILABLE"],"x-idempotent":true,"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"X-Idempotency-Key","in":"header","required":false,"description":"Any unique string (a UUID is ideal). Replays within 24 hours return the first response instead of acting twice.","schema":{"type":"string","maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"amountUsd":{"type":"number","minimum":100,"maximum":100000}},"required":["amountUsd"]}}}},"x-px-example":{"path":{},"query":{},"body":{"amountUsd":100}},"x-px-billable":{"kind":"money","note":"Starts a payment to top up your balance."}}},"/api/v1/topups/methods":{"get":{"operationId":"getTopupsMethods","tags":["Top-ups"],"summary":"List available top-up methods and their limits","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"stripe":{"type":"object","properties":{"enabled":{"type":"boolean"},"minAmount":{"type":"number"},"maxAmount":{"type":"number"},"currency":{"type":"string"},"processingTime":{"type":"string"}},"required":["enabled","minAmount","maxAmount","currency","processingTime"]},"crypto":{"type":"object","properties":{"enabled":{"type":"boolean"},"minAmount":{"type":"number"},"maxAmount":{"type":"number"},"tokens":{"type":"array","items":{"type":"string"}},"networks":{"type":"array","items":{"type":"string"}},"processingTime":{"type":"string"}},"required":["enabled","minAmount","maxAmount","tokens","networks","processingTime"]},"wire":{"type":"object","properties":{"enabled":{"type":"boolean"},"minAmount":{"type":"number"},"maxAmount":{"type":"number"},"currency":{"type":"string"},"processingTime":{"type":"string"},"bankDetails":{"type":"object","properties":{"bankName":{"type":"string"},"accountName":{"type":"string"},"iban":{"type":"string"},"swift":{"type":"string"},"currency":{"type":"string","enum":["USD"]}},"required":["bankName","accountName","iban","swift","currency"],"nullable":true}},"required":["enabled","minAmount","maxAmount","currency","processingTime","bankDetails"]}},"required":["stripe","crypto","wire"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/topups/payment-methods":{"get":{"operationId":"getTopupsPaymentMethods","tags":["Top-ups"],"summary":"List your saved cards","description":"Brand, last 4 and expiry only. Empty when card payments are off or no card is saved.\n\n**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"brand":{"type":"string"},"last4":{"type":"string"},"expMonth":{"type":"integer","nullable":true},"expYear":{"type":"integer","nullable":true},"isDefault":{"type":"boolean"}},"required":["id","brand","last4","expMonth","expYear","isDefault"]}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/topups/payment-methods/default":{"post":{"operationId":"postTopupsPaymentMethodsDefault","tags":["Top-ups"],"summary":"Set your default card","description":"The default card is the one auto-recharge charges.\n\n**Auth:** dashboard session (JWT) only. API keys are refused with 403 so a leaked key can never perform this action.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"defaultPaymentMethodId":{"type":"string"}},"required":["defaultPaymentMethodId"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"session","x-error-codes":["STRIPE_DISABLED"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"paymentMethodId":{"type":"string","minLength":1}},"required":["paymentMethodId"]}}}},"x-px-example":{"path":{},"query":{},"body":{"paymentMethodId":"<paymentMethodId>"}},"x-px-billable":{"kind":"money","note":"Starts a payment to top up your balance."}}},"/api/v1/topups/payment-methods/{id}":{"delete":{"operationId":"deleteTopupsPaymentMethodsById","tags":["Top-ups"],"summary":"Remove a saved card","description":"Removing the default card also clears it as default, which stops auto-recharge from charging.\n\n**Auth:** dashboard session (JWT) only. API keys are refused with 403 so a leaked key can never perform this action.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"removed":{"type":"string"}},"required":["removed"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"session","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}},"x-px-billable":{"kind":"money","note":"Starts a payment to top up your balance."}}},"/api/v1/topups/auto-recharge":{"get":{"operationId":"getTopupsAutoRecharge","tags":["Top-ups"],"summary":"Get your auto-recharge settings","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/AutoRecharge"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}},"put":{"operationId":"putTopupsAutoRecharge","tags":["Top-ups"],"summary":"Update your auto-recharge settings","description":"Send only the fields to change; `null` clears a value. Enabling requires a default card and both a threshold and an amount.\n\n**Auth:** dashboard session (JWT) only. API keys are refused with 403 so a leaked key can never perform this action.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/AutoRecharge"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"session","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean"},"threshold":{"type":"number","minimum":0,"maximum":100000,"nullable":true},"amount":{"type":"number","minimum":5,"maximum":10000,"nullable":true},"dailyCap":{"type":"number","minimum":0,"maximum":100000,"nullable":true}}}}}},"x-px-example":{"path":{},"query":{},"body":{"enabled":true,"threshold":1}},"x-px-billable":{"kind":"money","note":"Starts a payment to top up your balance."}}},"/api/v1/topups/pending":{"get":{"operationId":"getTopupsPending","tags":["Top-ups"],"summary":"List your pending top-ups with payment instructions","description":"Pending crypto and wire top-ups with the address or bank details to complete them. Pending top-ups expire after 7 days. `amountUsd` here is a plain JSON number.\n\n**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"method":{"type":"string","enum":["crypto","wire","stripe","x402"]},"amountUsd":{"type":"number"},"status":{"type":"string","enum":["pending"]},"reference":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"ageHours":{"type":"integer"},"expiresInDays":{"type":"integer"},"token":{"type":"string","nullable":true},"network":{"type":"string","nullable":true},"depositAddress":{"type":"string","nullable":true},"bankDetails":{"type":"object","properties":{"bankName":{"type":"string"},"accountName":{"type":"string"},"iban":{"type":"string"},"swift":{"type":"string"},"currency":{"type":"string","enum":["USD"]}},"required":["bankName","accountName","iban","swift","currency"],"nullable":true},"instructions":{"type":"string"}},"required":["id","method","amountUsd","status","reference","createdAt","ageHours","expiresInDays","instructions"],"additionalProperties":true}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/dialer/agent/ask":{"post":{"operationId":"postDialerAgentAsk","tags":["Dialer"],"summary":"Ask the dialer assistant a question or give it an instruction","description":"A conversational assistant that reads and operates YOUR dialer (campaigns, numbers, caller IDs). Send the `history` from the previous reply to continue a conversation. `actions` lists what it did, including any writes.\n\n**Auth:** API key or JWT. Scoped keys need `dialer:write`.\n\n**Rate limit:** 20 requests per minute per caller.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"reply":{"type":"string"},"actions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"ok":{"type":"boolean"},"write":{"type":"boolean"}},"required":["tool","ok","write"]}},"suggestions":{"type":"array","items":{"type":"string"}},"history":{"type":"array","items":{}}},"required":["reply","actions","suggestions","history"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"dialer:write","x-rate-limit":{"max":20,"window":"minute"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","minLength":1,"maxLength":4000},"history":{"type":"array","description":"The `history` returned by the previous turn"}},"required":["message"]}}}},"x-px-example":{"path":{},"query":{},"body":{"message":"Hello from Acme"}}}},"/api/v1/dialer/analytics/overview":{"get":{"operationId":"getDialerAnalyticsOverview","tags":["Dialer"],"summary":"Get dialer analytics across all your campaigns","description":"Defaults to the last 30 days when `from`/`to` are omitted.\n\n**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"window":{"type":"object","properties":{"from":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"to":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["from","to"]},"campaigns":{"type":"object","additionalProperties":{"type":"integer"},"description":"Campaign counts by status, plus `total`"},"headline":{"type":"object","properties":{"dialed":{"type":"integer"},"answered":{"type":"integer"},"failed":{"type":"integer"},"connectRate":{"type":"number"},"acd":{"type":"number"},"talkMinutes":{"type":"number"},"spend":{"type":"number","description":"USD, a display number"},"costPerAnswered":{"type":"number"},"costPerMinute":{"type":"number"}},"required":["dialed","answered","failed","connectRate","acd","talkMinutes","spend","costPerAnswered","costPerMinute"]},"topDestinations":{"type":"array","items":{"type":"object","properties":{"dialed":{"type":"integer"},"answered":{"type":"integer"},"asr":{"type":"number"},"prefix":{"type":"string"}},"required":["dialed","answered","asr","prefix"]}},"byHour":{"type":"array","items":{"type":"object","additionalProperties":{}}},"daily":{"type":"array","items":{"type":"object","properties":{"dialed":{"type":"integer"},"answered":{"type":"integer"},"asr":{"type":"number"},"day":{"type":"string"}},"required":["dialed","answered","asr","day"]}},"topCampaigns":{"type":"array","items":{"type":"object","properties":{"dialed":{"type":"integer"},"answered":{"type":"integer"},"asr":{"type":"number"},"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"status":{"type":"string","enum":["draft","ready","running","paused","completed","failed"]}},"required":["dialed","answered","asr","id","name","status"]}}},"required":["window","campaigns","headline","topDestinations","byHour","daily","topCampaigns"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"from","in":"query","required":false,"description":"ISO date/time","schema":{"type":"string"}},{"name":"to","in":"query","required":false,"description":"ISO date/time","schema":{"type":"string"}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/dialer/campaigns/{id}/analytics":{"get":{"operationId":"getDialerCampaignsByIdAnalytics","tags":["Dialer"],"summary":"Get detailed analytics for one campaign","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"campaign":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"status":{"type":"string","enum":["draft","ready","running","paused","completed","failed"]},"kind":{"type":"string","enum":["voice","sms"]}},"required":["id","name","status","kind"]},"headline":{"type":"object","properties":{"dialed":{"type":"integer"},"answered":{"type":"integer"},"failed":{"type":"integer"},"connectRate":{"type":"number"},"acd":{"type":"number"},"talkMinutes":{"type":"number"},"spend":{"type":"number","description":"USD, a display number"},"costPerAnswered":{"type":"number"},"costPerMinute":{"type":"number"},"totalNumbers":{"type":"integer"},"pending":{"type":"integer"},"asr":{"type":"number"},"bestHour":{"type":"object","properties":{"hour":{"type":"integer"},"asr":{"type":"number"},"tz":{"type":"string"}},"required":["hour","asr","tz"],"nullable":true}},"required":["dialed","answered","failed","connectRate","acd","talkMinutes","spend","costPerAnswered","costPerMinute","totalNumbers","pending","asr","bestHour"]},"dispositions":{"type":"array","items":{"type":"object","properties":{"status":{"type":"string"},"count":{"type":"integer"},"pct":{"type":"number"}},"required":["status","count","pct"]}},"failureCauses":{"type":"array","items":{"type":"object","properties":{"code":{"type":"integer"},"label":{"type":"string"},"count":{"type":"integer"}},"required":["code","label","count"]}},"byHour":{"type":"array","items":{"type":"object","additionalProperties":{}}},"byDayOfWeek":{"type":"array","items":{"type":"object","properties":{"dialed":{"type":"integer"},"answered":{"type":"integer"},"asr":{"type":"number"},"dow":{"type":"integer"}},"required":["dialed","answered","asr","dow"]}},"byDestination":{"type":"array","items":{"type":"object","properties":{"dialed":{"type":"integer"},"answered":{"type":"integer"},"asr":{"type":"number"},"prefix":{"type":"string"},"acd":{"type":"number"}},"required":["dialed","answered","asr","prefix","acd"]}},"retryEffectiveness":{"type":"array","items":{"type":"object","properties":{"dialed":{"type":"integer"},"answered":{"type":"integer"},"asr":{"type":"number"},"attempt":{"type":"integer"}},"required":["dialed","answered","asr","attempt"]}},"daily":{"type":"array","items":{"type":"object","properties":{"dialed":{"type":"integer"},"answered":{"type":"integer"},"asr":{"type":"number"},"day":{"type":"string"}},"required":["dialed","answered","asr","day"]}}},"required":["campaign","headline","dispositions","failureCauses","byHour","byDayOfWeek","byDestination","retryEffectiveness","daily"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/dialer/campaigns":{"get":{"operationId":"getDialerCampaigns","tags":["Dialer"],"summary":"List your dialer and SMS campaigns","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":"One page of results, newest first.","content":{"application/json":{"schema":{"type":"object","required":["success","data","nextCursor","hasMore"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/DialerCampaign"}},"nextCursor":{"type":"string","nullable":true,"description":"Pass as `cursor` to fetch the next page; null on the last page."},"hasMore":{"type":"boolean","description":"True when another page exists."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["draft","ready","running","paused","completed","failed"]}},{"name":"search","in":"query","required":false,"schema":{"type":"string"}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"x-px-example":{"path":{},"query":{}}},"post":{"operationId":"postDialerCampaigns","tags":["Dialer"],"summary":"Create a dialer or SMS campaign","description":"Creates the campaign in `draft`. Add numbers (POST /campaigns/{id}/numbers or /contacts/import), then start it with POST /campaigns/{id}/control. A campaign created with a test key is simulated and never really dialled or billed.\n\n**Auth:** API key or JWT. Scoped keys need `dialer:write`.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/DialerCampaign"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"dialer:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"routeId":{"type":"string","format":"uuid"},"kind":{"type":"string","enum":["voice","sms"]},"messageBody":{"type":"string","maxLength":1600},"senderId":{"type":"string","maxLength":20,"pattern":"^[A-Za-z0-9 .+_-]*$"},"targetAcd":{"type":"string","pattern":"^\\d+(\\.\\d{1,2})?$"},"targetAsr":{"type":"string","pattern":"^\\d+(\\.\\d{1,2})?$"},"concurrency":{"type":"integer","minimum":1,"maximum":50000,"default":1},"maxCallDuration":{"type":"integer","minimum":1,"maximum":3600,"default":300},"callInterval":{"type":"integer","minimum":0,"maximum":60000,"default":0},"notes":{"type":"string","maxLength":2000},"windowStartHour":{"type":"integer","minimum":0,"maximum":23},"windowEndHour":{"type":"integer","minimum":0,"maximum":23},"windowTz":{"type":"string","maxLength":64},"maxAttempts":{"type":"integer","minimum":1,"maximum":10,"default":1},"retryDelayMinutes":{"type":"integer","minimum":1,"maximum":1440,"default":60},"maxSpend":{"type":"string","pattern":"^\\d+(\\.\\d{1,6})?$"},"scheduleAt":{"type":"string","format":"date-time"},"aiAgentId":{"type":"string","format":"uuid","nullable":true}},"required":["name","routeId"]}}}},"x-px-example":{"path":{},"query":{},"body":{"name":"Acme","routeId":"<routeId>"}}}},"/api/v1/dialer/campaigns/{id}":{"get":{"operationId":"getDialerCampaignsById","tags":["Dialer"],"summary":"Get a campaign","description":"**Auth:** API key or JWT. Scoped keys need `dialer:write`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/DialerCampaign"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"dialer:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}},"put":{"operationId":"putDialerCampaignsById","tags":["Dialer"],"summary":"Update a campaign","description":"**Auth:** API key or JWT. Scoped keys need `dialer:write`.\n\n**Test keys:** allowed on campaigns created with a test key (simulated); refused with 403 `TEST_KEY_NOT_ALLOWED` on a live campaign.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/DialerCampaign"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"dialer:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"messageBody":{"type":"string","maxLength":1600,"nullable":true},"senderId":{"type":"string","maxLength":20,"pattern":"^[A-Za-z0-9 .+_-]*$","nullable":true},"targetAcd":{"type":"string","pattern":"^\\d+(\\.\\d{1,2})?$","nullable":true},"targetAsr":{"type":"string","pattern":"^\\d+(\\.\\d{1,2})?$","nullable":true},"concurrency":{"type":"integer","minimum":1,"maximum":50000},"maxCallDuration":{"type":"integer","minimum":1,"maximum":3600},"callInterval":{"type":"integer","minimum":0,"maximum":60000},"notes":{"type":"string","maxLength":2000,"nullable":true},"windowStartHour":{"type":"integer","minimum":0,"maximum":23,"nullable":true},"windowEndHour":{"type":"integer","minimum":0,"maximum":23,"nullable":true},"windowTz":{"type":"string","maxLength":64,"nullable":true},"maxAttempts":{"type":"integer","minimum":1,"maximum":10},"retryDelayMinutes":{"type":"integer","minimum":1,"maximum":1440},"maxSpend":{"type":"string","pattern":"^\\d+(\\.\\d{1,6})?$","nullable":true},"scheduleAt":{"type":"string","format":"date-time","nullable":true},"aiAgentId":{"type":"string","format":"uuid","nullable":true}}}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"name":"Acme","messageBody":"<messageBody>"}}},"delete":{"operationId":"deleteDialerCampaignsById","tags":["Dialer"],"summary":"Delete a campaign","description":"**Auth:** API key or JWT. Scoped keys need `dialer:write`.\n\n**Test keys:** allowed on campaigns created with a test key (simulated); refused with 403 `TEST_KEY_NOT_ALLOWED` on a live campaign.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/Message"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"dialer:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/dialer/campaigns/{id}/control":{"post":{"operationId":"postDialerCampaignsByIdControl","tags":["Dialer"],"summary":"Start, pause or stop a campaign","description":"Starting spends money: calls and messages are billed to your balance as they happen. Start is refused with VALIDATION_ERROR when the balance is insufficient or the campaign has no numbers.\n\n**Auth:** API key or JWT. Scoped keys need `dialer:write`.\n\n**Test keys:** allowed on campaigns created with a test key (simulated); refused with 403 `TEST_KEY_NOT_ALLOWED` on a live campaign.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/DialerCampaign"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"dialer:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","enum":["start","pause","stop"]}},"required":["action"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"action":"start"}},"x-px-billable":{"kind":"traffic","note":"Starting a campaign dials real numbers or sends real messages, billed as they happen."}}},"/api/v1/dialer/campaigns/{id}/ready":{"post":{"operationId":"postDialerCampaignsByIdReady","tags":["Dialer"],"summary":"Mark a draft campaign ready to start","description":"Status only; every start-time check still runs when you start it. Refused when the campaign has no contacts yet.\n\n**Auth:** API key or JWT. Scoped keys need `dialer:write`.\n\n**Test keys:** allowed on campaigns created with a test key (simulated); refused with 403 `TEST_KEY_NOT_ALLOWED` on a live campaign.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/DialerCampaign"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"dialer:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/dialer/campaigns/{id}/stats":{"get":{"operationId":"getDialerCampaignsByIdStats","tags":["Dialer"],"summary":"Get live progress and spend for a campaign","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/DialerCampaignStats"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/dialer/contacts/parse":{"post":{"operationId":"postDialerContactsParse","tags":["Dialer"],"summary":"Parse a contact file and suggest a column mapping","description":"Upload a CSV or XLSX (multipart `file` part, or JSON `contentBase64`/`content`, up to about 12 MB). Returns the detected columns, a suggested mapping, a preview and the data rows to send back to /contacts/import. Nothing is saved.\n\n**Auth:** API key or JWT. Scoped keys need `dialer:write`.\n\n**Rate limit:** 20 requests per minute per caller.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/DialerContactParseResult"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"dialer:write","x-rate-limit":{"max":20,"window":"minute"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"filename":{"type":"string","maxLength":255},"contentBase64":{"type":"string","description":"The file, base64-encoded"},"content":{"type":"string","description":"The file as plain text (CSV)"}}}}}},"x-px-example":{"path":{},"query":{},"body":{"filename":"<filename>","contentBase64":"<contentBase64>"}}}},"/api/v1/dialer/contacts/import":{"post":{"operationId":"postDialerContactsImport","tags":["Dialer"],"summary":"Import mapped contacts into a campaign or a saved list","description":"Rows are re-normalised to E.164 and de-duplicated server-side, so what the preview showed is what is stored.\n\n**Auth:** API key or JWT. Scoped keys need `dialer:write`.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"imported":{"type":"integer"},"skippedInvalid":{"type":"integer"},"skippedDup":{"type":"integer"},"sample":{"type":"array","items":{"type":"object","properties":{"number":{"type":"string"},"name":{"type":"string","nullable":true},"fields":{"type":"object","additionalProperties":{"type":"string"},"nullable":true}},"required":["number","name","fields"]}},"rejects":{"type":"array","items":{"type":"object","properties":{"row":{"type":"integer"},"value":{"type":"string"},"reason":{"type":"string"}},"required":["row","value","reason"]}},"savedListId":{"type":"string","format":"uuid","nullable":true},"campaign":{"$ref":"#/components/schemas/DialerCampaign"},"totalNumbers":{"type":"integer"}},"required":["imported","skippedInvalid","skippedDup","sample","rejects"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"dialer:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"rows":{"type":"array","items":{"type":"array","items":{"type":"string"}},"minItems":1,"maxItems":100000,"description":"The dataRows returned by /contacts/parse"},"mapping":{"$ref":"#/components/schemas/DialerContactMapping"},"columnLabels":{"type":"array","items":{"type":"object","properties":{"index":{"type":"integer"},"label":{"type":"string","maxLength":255}},"required":["index","label"]},"maxItems":500},"campaignId":{"type":"string","format":"uuid"},"listId":{"type":"string","format":"uuid"},"saveAsListName":{"type":"string","minLength":1,"maxLength":255},"keepDraft":{"type":"boolean"}},"required":["rows","mapping"]}}}},"x-px-example":{"path":{},"query":{},"body":{"rows":[["<row>"]],"mapping":{"headerRowIndex":1,"columns":{"phone":1,"name":1,"firstName":1,"lastName":1},"extraColumns":[1]}}}}},"/api/v1/dialer/campaigns/{id}/numbers":{"post":{"operationId":"postDialerCampaignsByIdNumbers","tags":["Dialer"],"summary":"Add destination numbers to a campaign","description":"Invalid and duplicate numbers are skipped and reported in `rejects`, not failed. The campaign becomes `ready` unless `keepDraft` is set.\n\n**Auth:** API key or JWT. Scoped keys need `dialer:write`.\n\n**Test keys:** allowed on campaigns created with a test key (simulated); refused with 403 `TEST_KEY_NOT_ALLOWED` on a live campaign.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/DialerNumbersUploadResult"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"dialer:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"numbers":{"type":"array","items":{"type":"string","minLength":1,"maxLength":30},"minItems":1,"maxItems":10000},"keepDraft":{"type":"boolean"}},"required":["numbers"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"numbers":["+447700900123"]}}},"get":{"operationId":"getDialerCampaignsByIdNumbers","tags":["Dialer"],"summary":"List a campaign’s numbers with their call outcome","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":"One page of results, newest first.","content":{"application/json":{"schema":{"type":"object","required":["success","data","nextCursor","hasMore"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/DialerNumber"}},"nextCursor":{"type":"string","nullable":true,"description":"Pass as `cursor` to fetch the next page; null on the last page."},"hasMore":{"type":"boolean","description":"True when another page exists."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["pending","dialing","answered","no_answer","busy","failed","skipped"]}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}},"delete":{"operationId":"deleteDialerCampaignsByIdNumbers","tags":["Dialer"],"summary":"Remove every number from a campaign","description":"**Auth:** API key or JWT. Scoped keys need `dialer:write`.\n\n**Test keys:** allowed on campaigns created with a test key (simulated); refused with 403 `TEST_KEY_NOT_ALLOWED` on a live campaign.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/Message"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"dialer:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/dialer/campaigns/{id}/numbers/{numberId}":{"delete":{"operationId":"deleteDialerCampaignsByIdNumbersByNumberId","tags":["Dialer"],"summary":"Remove one number from a campaign","description":"**Auth:** API key or JWT. Scoped keys need `dialer:write`.\n\n**Test keys:** allowed on campaigns created with a test key (simulated); refused with 403 `TEST_KEY_NOT_ALLOWED` on a live campaign.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"}},"required":["id"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"dialer:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"numberId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>","numberId":"<numberId>"},"query":{}}}},"/api/v1/dialer/campaigns/{id}/clis":{"post":{"operationId":"postDialerCampaignsByIdClis","tags":["Dialer"],"summary":"Add caller IDs to a campaign","description":"Up to 100 per request. Caller IDs rotate round-robin across calls unless a caller-ID set is assigned.\n\n**Auth:** API key or JWT. Scoped keys need `dialer:write`.\n\n**Test keys:** allowed on campaigns created with a test key (simulated); refused with 403 `TEST_KEY_NOT_ALLOWED` on a live campaign.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"count":{"type":"integer"},"inserted":{"type":"integer"},"skipped":{"type":"integer"},"rejects":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"reason":{"type":"string"}},"required":["value","reason"]}},"totalClis":{"type":"integer"}},"required":["count","inserted","skipped","rejects","totalClis"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"dialer:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"clis":{"type":"array","items":{"type":"string","minLength":1,"maxLength":30},"minItems":1,"maxItems":100}},"required":["clis"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"clis":["+447700900123"]}}},"get":{"operationId":"getDialerCampaignsByIdClis","tags":["Dialer"],"summary":"List a campaign’s caller IDs","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/DialerCampaignCli"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}},"delete":{"operationId":"deleteDialerCampaignsByIdClis","tags":["Dialer"],"summary":"Remove every caller ID from a campaign","description":"**Auth:** API key or JWT. Scoped keys need `dialer:write`.\n\n**Test keys:** allowed on campaigns created with a test key (simulated); refused with 403 `TEST_KEY_NOT_ALLOWED` on a live campaign.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/Message"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"dialer:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/dialer/caller-ids":{"get":{"operationId":"getDialerCallerIds","tags":["Dialer"],"summary":"List your caller-ID sets","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"cliCount":{"type":"integer"}},"required":["id","userId","name","description","createdAt","updatedAt","cliCount"]}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}},"post":{"operationId":"postDialerCallerIds","tags":["Dialer"],"summary":"Create a caller-ID set","description":"**Auth:** API key or JWT. Scoped keys need `dialer:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/DialerCallerIdSet"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"dialer:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"description":{"type":"string","maxLength":2000}},"required":["name"]}}}},"x-px-example":{"path":{},"query":{},"body":{"name":"Acme"}}}},"/api/v1/dialer/caller-ids/{id}":{"get":{"operationId":"getDialerCallerIdsById","tags":["Dialer"],"summary":"Get a caller-ID set","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/DialerCallerIdSet"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}},"patch":{"operationId":"patchDialerCallerIdsById","tags":["Dialer"],"summary":"Rename or describe a caller-ID set","description":"**Auth:** API key or JWT. Scoped keys need `dialer:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/DialerCallerIdSet"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"dialer:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"description":{"type":"string","maxLength":2000,"nullable":true}}}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"name":"Acme","description":"Example"}}},"delete":{"operationId":"deleteDialerCallerIdsById","tags":["Dialer"],"summary":"Delete a caller-ID set","description":"Campaigns using the set are detached from it and fall back to their own caller-ID list.\n\n**Auth:** API key or JWT. Scoped keys need `dialer:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"}},"required":["id"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"dialer:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/dialer/caller-ids/{id}/numbers":{"get":{"operationId":"getDialerCallerIdsByIdNumbers","tags":["Dialer"],"summary":"List the caller IDs in a set, with usage stats","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"setId":{"type":"string","format":"uuid"},"cli":{"type":"string"},"label":{"type":"string","nullable":true},"country":{"type":"string","nullable":true},"countryCode":{"type":"string","nullable":true},"areaCode":{"type":"string","nullable":true},"source":{"type":"string","enum":["upload","paste","manual","revshare","did"]},"enabled":{"type":"boolean"},"weight":{"type":"integer"},"dailyCap":{"type":"integer","nullable":true},"campaignCap":{"type":"integer","nullable":true},"hourlyCap":{"type":"integer","nullable":true},"cooldownSec":{"type":"integer","nullable":true},"status":{"type":"string","enum":["active","resting","retired"]},"tags":{"type":"array","items":{"type":"string"}},"notes":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"stats":{"type":"object","properties":{"calls":{"type":"integer"},"connects":{"type":"integer"},"connectRate":{"type":"number","description":"Percent"},"avgSec":{"type":"number"},"todayUsed":{"type":"integer"},"campaignUsed":{"type":"integer"},"lastUsedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true}},"required":["calls","connects","connectRate","avgSec","todayUsed","campaignUsed","lastUsedAt"]}},"required":["id","setId","cli","label","country","countryCode","areaCode","source","enabled","weight","dailyCap","campaignCap","hourlyCap","cooldownSec","status","tags","notes","createdAt","stats"]}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}},"post":{"operationId":"postDialerCallerIdsByIdNumbers","tags":["Dialer"],"summary":"Add caller IDs to a set","description":"Send ONE of: `clis` (a list), `paste` (free text), a file (multipart `file` part, or `contentBase64`/`content`). Numbers must be E.164; invalid and duplicate entries are reported in `rejects`.\n\n**Auth:** API key or JWT. Scoped keys need `dialer:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/DialerCallerIdAddResult"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"dialer:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"clis":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"object","properties":{"cli":{"type":"string"},"label":{"type":"string","maxLength":120,"nullable":true}},"required":["cli"]}]},"maxItems":100000,"description":"A manual list of E.164 caller IDs, bare or with a label"},"paste":{"type":"string","maxLength":2000000,"description":"A pasted block of numbers"},"filename":{"type":"string","maxLength":255},"contentBase64":{"type":"string","description":"A CSV/XLSX file, base64-encoded"},"content":{"type":"string","description":"A CSV file as plain text"}}}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"clis":["+447700900123"],"paste":"<paste>"}}}},"/api/v1/dialer/caller-ids/{id}/from-revshare":{"post":{"operationId":"postDialerCallerIdsByIdFromRevshare","tags":["Dialer"],"summary":"Add your revenue share numbers to a caller-ID set","description":"Omit `takingIds` (or pass \"all\") to add every active revenue share number you hold.\n\n**Auth:** API key or JWT. Scoped keys need `dialer:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/DialerCallerIdAddResult"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"dialer:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"takingIds":{"anyOf":[{"type":"array","items":{"type":"string","format":"uuid"}},{"type":"string","enum":["all"]}]}}}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"takingIds":["<takingId>"]}}}},"/api/v1/dialer/caller-ids/{id}/numbers/{nid}":{"patch":{"operationId":"patchDialerCallerIdsByIdNumbersByNid","tags":["Dialer"],"summary":"Update one caller ID in a set","description":"Enable or disable it, and set its weight, caps, cooldown, status, tags, label or notes.\n\n**Auth:** API key or JWT. Scoped keys need `dialer:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/DialerCallerIdNumber"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"dialer:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"nid","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean"},"weight":{"type":"integer","minimum":1,"maximum":1000},"dailyCap":{"type":"integer","minimum":0,"nullable":true},"campaignCap":{"type":"integer","minimum":0,"nullable":true},"hourlyCap":{"type":"integer","minimum":0,"nullable":true},"cooldownSec":{"type":"integer","minimum":0,"nullable":true},"tags":{"type":"array","items":{"type":"string","maxLength":40},"maxItems":50},"status":{"type":"string","enum":["active","resting","retired"]},"label":{"type":"string","maxLength":120,"nullable":true},"notes":{"type":"string","maxLength":2000,"nullable":true}}}}}},"x-px-example":{"path":{"id":"<id>","nid":"<nid>"},"query":{},"body":{"enabled":true,"weight":1}}},"delete":{"operationId":"deleteDialerCallerIdsByIdNumbersByNid","tags":["Dialer"],"summary":"Remove one caller ID from a set","description":"**Auth:** API key or JWT. Scoped keys need `dialer:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"}},"required":["id"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"dialer:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"nid","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>","nid":"<nid>"},"query":{}}}},"/api/v1/dialer/caller-ids/{id}/numbers/bulk":{"post":{"operationId":"postDialerCallerIdsByIdNumbersBulk","tags":["Dialer"],"summary":"Enable, disable or delete many caller IDs in a set","description":"**Auth:** API key or JWT. Scoped keys need `dialer:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"affected":{"type":"integer"}},"required":["affected"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"dialer:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","enum":["enable","disable","delete"]},"cliIds":{"type":"array","items":{"type":"string","format":"uuid"},"minItems":1,"maxItems":100000}},"required":["action","cliIds"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"action":"enable","cliIds":["<cliId>"]}}}},"/api/v1/dialer/caller-ids/{id}/stats":{"get":{"operationId":"getDialerCallerIdsByIdStats","tags":["Dialer"],"summary":"Get usage stats for a caller-ID set","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"totalClis":{"type":"integer"},"activeClis":{"type":"integer"},"restingClis":{"type":"integer"},"retiredClis":{"type":"integer"},"calls":{"type":"integer"},"connects":{"type":"integer"},"connectRate":{"type":"number","description":"Percent"},"avgSec":{"type":"number"},"campaigns":{"type":"integer"}},"required":["totalClis","activeClis","restingClis","retiredClis","calls","connects","connectRate","avgSec","campaigns"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/dialer/campaigns/{id}/cli":{"put":{"operationId":"putDialerCampaignsByIdCli","tags":["Dialer"],"summary":"Assign a caller-ID set and rotation strategy to a campaign","description":"**Auth:** API key or JWT. Scoped keys need `dialer:write`.\n\n**Test keys:** allowed on campaigns created with a test key (simulated); refused with 403 `TEST_KEY_NOT_ALLOWED` on a live campaign.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/DialerCampaign"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"dialer:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"cliSetId":{"type":"string","format":"uuid","nullable":true,"description":"null clears the assignment (the campaign falls back to its own caller-ID list)"},"strategy":{"type":"object","properties":{"mode":{"type":"string","enum":["random","round_robin","per_day_cap","per_campaign_cap","hourly_cap","cooldown","sticky_dest","area_match","country_match","weighted","lru","best_perf","random_mix"]},"dailyCap":{"type":"integer","minimum":0,"nullable":true},"campaignCap":{"type":"integer","minimum":0,"nullable":true},"hourlyCap":{"type":"integer","minimum":0,"nullable":true},"cooldownSec":{"type":"integer","minimum":0,"nullable":true},"restBelowAsr":{"type":"number","minimum":0,"maximum":100,"nullable":true,"description":"Rest a caller ID whose ASR falls below this percent"},"weightsRespected":{"type":"boolean"}},"required":["mode"]}},"required":["cliSetId"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"cliSetId":"<cliSetId>"}}}},"/api/v1/dialer/target-lists/from-revshare-cdr":{"post":{"operationId":"postDialerTargetListsFromRevshareCdr","tags":["Dialer"],"summary":"Build a call-back list from callers to your revenue share numbers","description":"Returns the distinct inbound callers in the window. Revenue share call records keep only a MASKED prefix of each caller, so entries are marked `dialable: false` and are not saved as a dial list; `limitation` explains this when it applies.\n\n**Auth:** API key or JWT. Scoped keys need `dialer:write`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"total":{"type":"integer"},"dialableCount":{"type":"integer"},"callers":{"type":"array","items":{"$ref":"#/components/schemas/DialerRevshareCaller"}},"saved":{"type":"object","properties":{"list":{"$ref":"#/components/schemas/DialerContactList"},"saved":{"type":"integer"},"skipped":{"type":"integer"}},"required":["list","saved","skipped"],"nullable":true,"description":"The saved contact list, when saveAsListName was given and there was something dialable to save"},"limitation":{"type":"string","nullable":true}},"required":["total","dialableCount","callers","saved","limitation"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"dialer:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"takingIds":{"anyOf":[{"type":"array","items":{"type":"string","format":"uuid"}},{"type":"string","enum":["all"]}]},"from":{"type":"string","description":"ISO date/time"},"to":{"type":"string","description":"ISO date/time"},"minDurationSec":{"type":"integer","minimum":0},"saveAsListName":{"type":"string","minLength":1,"maxLength":255}}}}}},"x-px-example":{"path":{},"query":{},"body":{"takingIds":["<takingId>"],"from":"+447700900123"}}}},"/api/v1/dialer/target-lists/compatible":{"get":{"operationId":"getDialerTargetListsCompatible","tags":["Dialer"],"summary":"Match inbound callers to the caller IDs in a set","description":"For each caller ID in the set, the inbound callers reachable from its country. `takingIds` may be comma-separated.\n\n**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/DialerCompatibleTargets"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"cliSetId","in":"query","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"takingIds","in":"query","required":false,"description":"\"all\" or comma-separated revenue share taking ids","schema":{"type":"string"}}],"x-px-example":{"path":{},"query":{"cliSetId":"<cliSetId>"}}},"post":{"operationId":"postDialerTargetListsCompatible","tags":["Dialer"],"summary":"Match inbound callers to a caller-ID set and optionally save them","description":"**Auth:** API key or JWT. Scoped keys need `dialer:write`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/DialerCompatibleTargets"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"dialer:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"cliSetId":{"type":"string","format":"uuid"},"takingIds":{"anyOf":[{"type":"array","items":{"type":"string","format":"uuid"}},{"type":"string","enum":["all"]},{"type":"string"}]},"saveAsListName":{"type":"string","minLength":1,"maxLength":255}},"required":["cliSetId"]}}}},"x-px-example":{"path":{},"query":{},"body":{"cliSetId":"<cliSetId>"}}}},"/api/v1/dialer/target-lists/refine":{"post":{"operationId":"postDialerTargetListsRefine","tags":["Dialer"],"summary":"Preview a cleaned number list","description":"De-duplicates, filters by country dial code or prefix, and optionally removes do-not-call entries. Nothing is saved.\n\n**Auth:** API key or JWT. Scoped keys need `dialer:write`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"kept":{"type":"array","items":{"type":"string"},"description":"E.164 numbers that survived"},"invalid":{"type":"integer"},"dup":{"type":"integer"},"filtered":{"type":"integer"},"suppressed":{"type":"integer"},"total":{"type":"integer"}},"required":["kept","invalid","dup","filtered","suppressed","total"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"dialer:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"numbers":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":200000},"countryCode":{"type":"string","maxLength":8,"description":"Country dial code, e.g. \"44\""},"prefix":{"type":"string","maxLength":24},"suppressDnc":{"type":"boolean"}},"required":["numbers"]}}}},"x-px-example":{"path":{},"query":{},"body":{"numbers":["+447700900123"]}}}},"/api/v1/dialer/target-lists/save":{"post":{"operationId":"postDialerTargetListsSave","tags":["Dialer"],"summary":"Save numbers as a contact list","description":"Only valid full E.164 numbers are stored.\n\n**Auth:** API key or JWT. Scoped keys need `dialer:write`.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"list":{"$ref":"#/components/schemas/DialerContactList"},"saved":{"type":"integer"},"skipped":{"type":"integer"}},"required":["list","saved","skipped"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"dialer:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"numbers":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":200000}},"required":["name","numbers"]}}}},"x-px-example":{"path":{},"query":{},"body":{"name":"Acme","numbers":["+447700900123"]}}}},"/api/v1/dialer/templates":{"get":{"operationId":"getDialerTemplates","tags":["Dialer"],"summary":"List your SMS templates","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/DialerSmsTemplate"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}},"post":{"operationId":"postDialerTemplates","tags":["Dialer"],"summary":"Create an SMS template","description":"`{{variable}}` placeholders are stored as written; per-recipient merge is not applied yet.\n\n**Auth:** API key or JWT. Scoped keys need `dialer:write`.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/DialerSmsTemplate"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"dialer:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"body":{"type":"string","minLength":1,"maxLength":1600}},"required":["name","body"]}}}},"x-px-example":{"path":{},"query":{},"body":{"name":"Acme","body":"Hello from Acme"}}}},"/api/v1/dialer/templates/{id}":{"patch":{"operationId":"patchDialerTemplatesById","tags":["Dialer"],"summary":"Update an SMS template","description":"**Auth:** API key or JWT. Scoped keys need `dialer:write`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/DialerSmsTemplate"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"dialer:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"body":{"type":"string","minLength":1,"maxLength":1600}}}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"name":"Acme","body":"Hello from Acme"}}},"delete":{"operationId":"deleteDialerTemplatesById","tags":["Dialer"],"summary":"Delete an SMS template","description":"**Auth:** API key or JWT. Scoped keys need `dialer:write`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/Message"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"dialer:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/dialer/contact-lists":{"get":{"operationId":"getDialerContactLists","tags":["Dialer"],"summary":"List your saved contact lists","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/DialerContactList"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}},"post":{"operationId":"postDialerContactLists","tags":["Dialer"],"summary":"Create a saved contact list","description":"**Auth:** API key or JWT. Scoped keys need `dialer:write`.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/DialerContactList"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"dialer:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"numbers":{"type":"array","items":{"type":"string","minLength":1,"maxLength":30},"minItems":1,"maxItems":10000}},"required":["name","numbers"]}}}},"x-px-example":{"path":{},"query":{},"body":{"name":"Acme","numbers":["+447700900123"]}}}},"/api/v1/dialer/contact-lists/{id}":{"get":{"operationId":"getDialerContactListsById","tags":["Dialer"],"summary":"Get a saved contact list with its numbers","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"name":{"type":"string"},"count":{"type":"integer"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"numbers":{"type":"array","items":{"type":"string"},"description":"Bare numbers (kept for existing clients)"},"contacts":{"type":"array","items":{"type":"object","properties":{"number":{"type":"string"},"name":{"type":"string","nullable":true},"fields":{"type":"object","additionalProperties":{"type":"string"},"nullable":true}},"required":["number","name","fields"]}}},"required":["id","userId","name","count","createdAt","numbers","contacts"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}},"delete":{"operationId":"deleteDialerContactListsById","tags":["Dialer"],"summary":"Delete a saved contact list","description":"**Auth:** API key or JWT. Scoped keys need `dialer:write`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/Message"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"dialer:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/dialer/cli-sets":{"get":{"operationId":"getDialerCliSets","tags":["Dialer"],"summary":"List your simple caller-ID lists","description":"The older named caller-ID lists used by the campaign wizard. For rotation, caps and stats use /dialer/caller-ids.\n\n**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/DialerCliSet"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}},"post":{"operationId":"postDialerCliSets","tags":["Dialer"],"summary":"Create a simple caller-ID list","description":"**Auth:** API key or JWT. Scoped keys need `dialer:write`.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/DialerCliSet"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"dialer:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"clis":{"type":"array","items":{"type":"string","minLength":1,"maxLength":30},"minItems":1,"maxItems":100}},"required":["name","clis"]}}}},"x-px-example":{"path":{},"query":{},"body":{"name":"Acme","clis":["+447700900123"]}}}},"/api/v1/dialer/cli-sets/{id}":{"delete":{"operationId":"deleteDialerCliSetsById","tags":["Dialer"],"summary":"Delete a simple caller-ID list","description":"**Auth:** API key or JWT. Scoped keys need `dialer:write`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/Message"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"dialer:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/purchases":{"post":{"operationId":"postPurchases","tags":["Purchases"],"summary":"Buy access to a marketplace route","description":"No upfront cost: usage is billed per minute or message from your balance. Requires a LIVE API key: a test key is refused with 400.\n\n**Auth:** API key or JWT. Scoped keys need `purchases:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"buyerId":{"type":"string","format":"uuid","description":"Your account id"},"routeId":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["active","paused","cancelled","pending_review"]},"sipUsername":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"cancelledAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"agreedPrice":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"Negotiated price (from an accepted offer) that overrides the list price"},"heldOldRate":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"Set while the purchase is paused by a seller rate increase: the rate you were paying"},"heldNewRate":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"The increased rate waiting for your acceptance"},"routingPriority":{"type":"integer","nullable":true,"description":"Your routing position (1 = first); null = unranked"},"requiresUsCompliance":{"type":"boolean","description":"A US voice route that needs STIR/SHAKEN review before traffic flows"},"reviewedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"reviewNote":{"type":"string","nullable":true,"description":"The compliance reviewer's note to you, if any"},"sipPasswordSet":{"type":"boolean","description":"Whether a SIP password exists. The value is not returned here: it is shown once at purchase, on your purchased-routes list and on Interconnections."},"smppSystemId":{"type":"string","nullable":true},"offerId":{"type":"string","format":"uuid","nullable":true,"description":"The accepted offer that set agreedPrice"},"route":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"type":{"type":"string","enum":["voice","sms"]},"country":{"type":"string"},"destinationName":{"type":"string","description":"The listing name as a buyer reads it: generated by the platform, never the seller's text, and ending in the listing reference (e.g. \"Niger Mobile · Ref 7K2Q\", \"A-Z Voice · Premium · Full CLI · Ref 3MX9\"). Your own listings keep the name you gave them."},"listingRef":{"type":"string","description":"Anonymous short reference of the listing (4 characters, e.g. \"7K2Q\"): stable for the life of the listing, unique enough to tell two same-named listings apart, and derived from the listing alone (it says nothing about the seller). Absent on your own listings."},"pricePerUnit":{"$ref":"#/components/schemas/Money"},"billingIncrement":{"type":"string","nullable":true},"jingleSipIp":{"enum":["null"],"nullable":true}},"required":["id","type","country","destinationName","listingRef","pricePerUnit","billingIncrement","jingleSipIp"],"nullable":true},"sipPublicIp":{"type":"string","description":"Where to send your SIP traffic"},"sipPassword":{"type":"string","nullable":true,"description":"Plaintext SIP password, returned once here"},"pendingCompliance":{"type":"boolean","description":"True when US STIR/SHAKEN compliance review must finish before traffic flows"}},"required":["id","buyerId","routeId","status","sipUsername","createdAt","cancelledAt","agreedPrice","heldOldRate","heldNewRate","routingPriority","requiresUsCompliance","reviewedAt","reviewNote","sipPasswordSet","smppSystemId","offerId","route","sipPublicIp","sipPassword","pendingCompliance"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"purchases:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"routeId":{"type":"string","format":"uuid"},"alertsForDestination":{"type":"boolean","description":"Follow this destination for new routes and price changes (default true). Multi-country decks follow nothing. Manage under /account/destination-alerts."}},"required":["routeId"]}}}},"x-px-example":{"path":{},"query":{},"body":{"routeId":"<routeId>"}},"x-px-billable":{"kind":"money","note":"Buys access to a marketplace route."}},"get":{"operationId":"getPurchases","tags":["Purchases"],"summary":"List your route purchases","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":"One page of results, newest first.","content":{"application/json":{"schema":{"type":"object","required":["success","data","nextCursor","hasMore"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/Purchase"}},"nextCursor":{"type":"string","nullable":true,"description":"Pass as `cursor` to fetch the next page; null on the last page."},"hasMore":{"type":"boolean","description":"True when another page exists."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["active","paused","cancelled"]}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/purchases/owned/{routeId}":{"get":{"operationId":"getPurchasesOwnedByRouteId","tags":["Purchases"],"summary":"GET /api/v1/purchases/owned/{routeId}","description":"**Auth:** API key or JWT. Scoped keys need `routes:read`.","responses":{"200":{"description":" Response shape not documented yet: the standard `{ \"success\": true, \"data\": ... }` envelope."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"routeId","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"routeId":"<routeId>"},"query":{}}}},"/api/v1/purchases/routing-order":{"get":{"operationId":"getPurchasesRoutingOrder","tags":["Purchases"],"summary":"Get your voice routing order","description":"Your SIP credentials and whitelisted IPs identify your ACCOUNT, not a route, so every active voice purchase can carry any call it covers. When several cover a number equally well (same prefix length), your routing order decides, then the cheaper rate, then the older purchase. This lists every voice purchase that can hold a position (active, paused or pending review): ranked ones first by position, then unranked ones oldest first. Destination names are cleaned of seller details. `rateSheet` routes are priced by an A-Z deck, so they can overlap any destination.\n\n**Auth:** API key or JWT. Scoped keys need `routes:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/RoutingOrderEntry"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}},"put":{"operationId":"putPurchasesRoutingOrder","tags":["Purchases"],"summary":"Replace your voice routing order","description":"`purchaseIds[0]` becomes position 1, the next 2, and so on; every other voice purchase of yours is cleared to unranked. Atomic: a reorder never leaves two routes half-swapped. An empty list clears the whole order (back to cheapest, then oldest). A repeated id is 400 VALIDATION_ERROR; an id that is not one of your rankable voice purchases is 404 and nothing changes.\n\n**Auth:** API key or JWT. Scoped keys need `purchases:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/RoutingOrderResult"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"purchases:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"purchaseIds":{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":500,"description":"Your voice purchases in the order to try them; an empty list clears the order"}},"required":["purchaseIds"]}}}},"x-px-example":{"path":{},"query":{},"body":{"purchaseIds":["<purchaseId>"]}}}},"/api/v1/purchases/lcr":{"get":{"operationId":"getPurchasesLcr","tags":["Purchases"],"summary":"GET /api/v1/purchases/lcr","description":"**Auth:** API key or JWT. Scoped keys need `routes:read`.\n\n**Rate limit:** 60 requests per minute per caller.","responses":{"200":{"description":" Response shape not documented yet: the standard `{ \"success\": true, \"data\": ... }` envelope."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:read","x-rate-limit":{"max":60,"window":"minute"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/purchases/lcr-order":{"put":{"operationId":"putPurchasesLcrOrder","tags":["Purchases"],"summary":"PUT /api/v1/purchases/lcr-order","description":"**Auth:** API key or JWT. Scoped keys need `purchases:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":" Response shape not documented yet: the standard `{ \"success\": true, \"data\": ... }` envelope."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"purchases:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/purchases/failover":{"get":{"operationId":"getPurchasesFailover","tags":["Purchases"],"summary":"See your first-choice and backup routes per destination","description":"For each prefix your active voice routes list: the route tried first and the backups behind it, in the order a call would use them. When automatic failover is on (`enabled: true`), a call that a route refuses before it is answered (for example SIP 403, 480, 5xx or no response) is tried straight away on the next route, up to `maxAttempts` routes, and only the route that connects is billed. A wrong number, a busy or declined call and an unanswered call are never retried. Over a SIP trunk only server errors and congestion (5xx) move a call on; `apiOnly` marks backups SIP trunk calls never use. `singleRoute: true` marks a destination with no backup. A-Z rate sheets are listed separately because they have no single prefix. Names are cleaned of seller details. Read-only.\n\n**Auth:** API key or JWT. Scoped keys need `routes:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/FailoverOverview"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/purchases/failover/price-limit":{"put":{"operationId":"putPurchasesFailoverPriceLimit","tags":["Purchases"],"summary":"PUT /api/v1/purchases/failover/price-limit","description":"**Auth:** API key or JWT. Scoped keys need `purchases:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":" Response shape not documented yet: the standard `{ \"success\": true, \"data\": ... }` envelope."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"purchases:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/purchases/route-for":{"get":{"operationId":"getPurchasesRouteFor","tags":["Purchases"],"summary":"See which of your routes would carry a number","description":"Runs the same ranking the live SIP path uses, for your account and with the same number normalisation, so the answer is what a real call would do. Lists every route of yours that covers the number, in order, with the step of the rule that put each one behind the one above. Also reports the two refusals that sit in front of routing: an embargoed destination and an empty balance; when `refused` is set, no route carries the call. Read-only.\n\n**Auth:** API key or JWT. Scoped keys need `routes:read`.\n\n**Rate limit:** 60 requests per minute per caller.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/RouteForResult"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:read","x-rate-limit":{"max":60,"window":"minute"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"to","in":"query","required":true,"description":"The number to check, international format","schema":{"type":"string","minLength":1,"maxLength":40}}],"x-px-example":{"path":{},"query":{"to":"+447700900123"}}}},"/api/v1/purchases/{id}/routing-priority":{"patch":{"operationId":"patchPurchasesByIdRoutingPriority","tags":["Purchases"],"summary":"Set a purchase's routing position","description":"Sets (`priority: n`) or clears (`priority: null`) one voice purchase's position in your routing order; 1 is tried first. Positions do not have to be contiguous, and two purchases may share one (then rate, then age decides). Voice purchases only, and not a cancelled one (400 VALIDATION_ERROR). To reorder several at once use PUT /purchases/routing-order.\n\n**Auth:** API key or JWT. Scoped keys need `purchases:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"routingPriority":{"type":"integer","nullable":true}},"required":["id","routingPriority"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"purchases:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"priority":{"type":"integer","minimum":1,"maximum":9999,"nullable":true,"description":"1 = tried first; null clears the position"}},"required":["priority"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"priority":1}}},"delete":{"operationId":"deletePurchasesByIdRoutingPriority","tags":["Purchases"],"summary":"Clear a purchase's routing position","description":"The purchase goes back to unranked: after every ranked route, cheapest then oldest.\n\n**Auth:** API key or JWT. Scoped keys need `purchases:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"routingPriority":{"type":"integer","nullable":true}},"required":["id","routingPriority"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"purchases:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/purchases/{id}":{"get":{"operationId":"getPurchasesById","tags":["Purchases"],"summary":"Get a purchase","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/PurchaseDetail"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}},"patch":{"operationId":"patchPurchasesById","tags":["Purchases"],"summary":"Pause or resume a purchase","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/PurchaseRow"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["active","paused"]}},"required":["status"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"status":"active"}}},"delete":{"operationId":"deletePurchasesById","tags":["Purchases"],"summary":"Cancel a purchase","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/PurchaseRow"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/purchases/{id}/usage":{"get":{"operationId":"getPurchasesByIdUsage","tags":["Purchases"],"summary":"Get call counts, ASR and spend for a purchase","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"calls24h":{"type":"integer"},"calls7d":{"type":"integer"},"calls30d":{"type":"integer"},"totalCalls":{"type":"integer"},"lastActivityAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"spend30d":{"$ref":"#/components/schemas/Money","description":"Absent when nothing was spent"},"measuredAsr":{"type":"number"},"measuredAsrSessions":{"type":"integer"},"measuredAsrPopulation":{"type":"string"},"measuredAsrWindow":{"type":"string"},"measuredAcd":{"type":"number"}},"required":["calls24h","calls7d","calls30d","totalCalls","lastActivityAt"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/purchases/{id}/accept-rate":{"post":{"operationId":"postPurchasesByIdAcceptRate","tags":["Purchases"],"summary":"Accept a seller's rate increase","description":"A purchase paused by a price rise resumes at the new rate. Pass the rate (or deck version) you reviewed so a further change is not accepted by mistake.\n\n**Auth:** API key or JWT. Scoped keys need `purchases:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"anyOf":[{"$ref":"#/components/schemas/PurchaseRow"},{"type":"object","properties":{"accepted":{"type":"boolean","enum":[true]},"changeId":{"type":"string","format":"uuid"},"purchaseId":{"type":"string","format":"uuid"},"effectiveDate":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["accepted","changeId","purchaseId","effectiveDate"],"description":"With changeId: a scheduled change accepted in advance; nothing resumes or bills now"}]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"purchases:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"acceptedRate":{"anyOf":[{"type":"string","pattern":"^\\d+(\\.\\d+)?$"},{"type":"number","minimum":0}],"description":"The new rate you are agreeing to, as shown to you (guards against a further change in between)"},"deckVersion":{"type":"string","pattern":"^[0-9a-f]{32}$","description":"For A-Z decks: the heldDeckVersion you reviewed"},"changeId":{"type":"string","format":"uuid","description":"Accept a SCHEDULED change in advance (id from upcoming-rate-changes). Nothing resumes or bills now."}}}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"acceptedRate":"<acceptedRate>","deckVersion":"<deckVersion>"}},"x-px-billable":{"kind":"money","note":"Accepts a higher rate on a route you buy."}}},"/api/v1/purchases/{id}/upcoming-rate-changes":{"get":{"operationId":"getPurchasesByIdUpcomingRateChanges","tags":["Purchases"],"summary":"List scheduled rate changes on a route you bought","description":"Rate changes the seller has scheduled on a route you bought and that are not yet in effect, soonest first: the effective date, the old and new rate per destination (biggest increases first, at most 200 rows per change; `totalRows` is the full count), and whether you have already accepted each one. For a per-country listing of an A-Z deck, only that listing's destinations are shown. Accept a change in advance with POST /purchases/{id}/accept-rate and `changeId`: at the effective date an accepted purchase keeps running instead of being paused for re-consent. `affectsYou` is false when you do not pay the list rate (an accepted offer or a private price), so a change will not pause you. Destination names are cleaned of seller details.\n\n**Auth:** API key or JWT. Scoped keys need `routes:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/PurchaseUpcomingRateChanges"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"routes:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/application/analytics":{"get":{"operationId":"getApplicationAnalytics","tags":["Application Manager"],"summary":"Get reseller analytics across your sub-accounts","description":"Headline totals and quality, a daily series, per-sub-account margin and top destinations. Figures are JSON numbers (analytics rollups, not ledger entries).\n\n**Auth:** API key or JWT. Scoped keys need `application:write`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"period":{"type":"object","properties":{"days":{"type":"integer"}},"required":["days"]},"summary":{"type":"object","properties":{"calls":{"type":"integer"},"sms":{"type":"integer"},"minutes":{"type":"integer"},"revenue":{"type":"number","description":"USD, JSON number (analytics rollup)"},"margin":{"type":"number","description":"USD, JSON number (analytics rollup)"},"asr":{"type":"number","nullable":true,"description":"Answer rate percent over customer sessions; null with no calls"},"acd":{"type":"number"},"carrierCost":{"type":"number"},"activeSubs":{"type":"integer"}},"required":["calls","sms","minutes","revenue","margin","asr","acd","carrierCost","activeSubs"],"additionalProperties":true},"timeseries":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string","description":"YYYY-MM-DD"},"calls":{"type":"integer"},"sms":{"type":"integer"},"revenue":{"type":"number"},"margin":{"type":"number"}},"required":["date","calls","sms","revenue","margin"],"additionalProperties":true}},"bySubAccount":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}},"byRoute":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}}},"required":["period","summary","timeseries","bySubAccount","byRoute"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"application:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"days","in":"query","required":false,"description":"Trailing window in days (default 30)","schema":{"type":"integer","minimum":1,"maximum":365}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/application/settings":{"get":{"operationId":"getApplicationSettings","tags":["Application Manager"],"summary":"Get your Application Manager settings","description":"Created with defaults on first read.\n\n**Auth:** API key or JWT. Scoped keys need `application:write`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/ApplicationSettings"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"application:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}},"put":{"operationId":"putApplicationSettings","tags":["Application Manager"],"summary":"Update your Application Manager settings","description":"Default markup, low-balance threshold, default fraud caps and portal branding. Send only what changes.\n\n**Auth:** API key or JWT. Scoped keys need `application:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/ApplicationSettings"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"application:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"defaultMarkupPct":{"type":"number","minimum":0,"maximum":100000},"subLowBalanceThreshold":{"type":"number","minimum":0,"maximum":1000000},"defaultDailySpendCap":{"type":"number","minimum":0,"maximum":1000000,"nullable":true},"defaultMaxConcurrentCalls":{"type":"integer","minimum":0,"maximum":100000,"nullable":true},"brandName":{"type":"string","maxLength":120,"nullable":true},"brandColor":{"type":"string","maxLength":9,"nullable":true},"brandLogoUrl":{"type":"string","format":"uri","maxLength":500,"nullable":true}}}}}},"x-px-example":{"path":{},"query":{},"body":{"defaultMarkupPct":1,"subLowBalanceThreshold":1}}}},"/api/v1/application/overview":{"get":{"operationId":"getApplicationOverview","tags":["Application Manager"],"summary":"Get sub-account totals","description":"**Auth:** API key or JWT. Scoped keys need `application:write`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"subCount":{"type":"integer"},"activeSubCount":{"type":"integer"},"aggregateBalance":{"type":"number","description":"Sum of sub-account balances, USD as a JSON number"}},"required":["subCount","activeSubCount","aggregateBalance"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"application:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/application/sub-accounts":{"get":{"operationId":"getApplicationSubAccounts","tags":["Application Manager"],"summary":"List your sub-accounts","description":"Newest first, cursor-paginated and searchable by label or external reference. `total` counts every match.\n\n**Auth:** API key or JWT. Scoped keys need `application:write`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"label":{"type":"string"},"externalRef":{"type":"string","nullable":true},"balance":{"$ref":"#/components/schemas/Money"},"status":{"type":"string","enum":["draft","active","suspended","closed"]},"markupPct":{"type":"string","nullable":true,"description":"Markup percent as a 3-decimal string; null = operator default"},"dailySpendCap":{"type":"string","nullable":true,"description":"null = operator default; \"0.00\" = unlimited"},"maxConcurrentCalls":{"type":"integer","nullable":true},"creditLimit":{"type":"string","description":"Postpaid credit, \"0.00\" = strict prepaid"},"currency":{"type":"string","minLength":3,"maxLength":3,"description":"Display currency for statements"},"portalEmail":{"type":"string","nullable":true},"autoSuspended":{"type":"boolean","description":"Suspended automatically by a daily cap, lifts itself"},"sipUsername":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"lowBalance":{"type":"boolean"}},"required":["id","label","externalRef","balance","status","markupPct","dailySpendCap","maxConcurrentCalls","creditLimit","currency","portalEmail","autoSuspended","sipUsername","createdAt","updatedAt","lowBalance"]}},"nextCursor":{"type":"string","nullable":true},"hasMore":{"type":"boolean"},"total":{"type":"integer"},"lowBalanceThreshold":{"type":"number"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"application:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"cursor","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","required":false,"description":"Default 50","schema":{"type":"integer","minimum":1,"maximum":100}},{"name":"search","in":"query","required":false,"schema":{"type":"string"}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["draft","active","suspended","closed"]}},{"name":"lowBalanceOnly","in":"query","required":false,"schema":{"type":"string","enum":["true","1"]}}],"x-px-example":{"path":{},"query":{}}},"post":{"operationId":"postApplicationSubAccounts","tags":["Application Manager"],"summary":"Create a sub-account","description":"Provisions its SIP credentials and one API key, both returned ONCE. Requires an active route purchase or an active route of your own.\n\n**Auth:** API key or JWT. Scoped keys need `application:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SubAccountCreated"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"application:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":255},"externalRef":{"type":"string","maxLength":10000,"nullable":true},"markupPct":{"type":"number","minimum":0,"maximum":100000,"nullable":true},"dailySpendCap":{"type":"number","minimum":0,"maximum":1000000,"nullable":true},"maxConcurrentCalls":{"type":"integer","minimum":0,"maximum":100000,"nullable":true},"creditLimit":{"type":"number","minimum":0,"maximum":10000000,"nullable":true},"currency":{"type":"string","minLength":3,"maxLength":3}},"required":["label"]}}}},"x-px-example":{"path":{},"query":{},"body":{"label":"Acme"}}}},"/api/v1/application/sub-accounts/bulk":{"post":{"operationId":"postApplicationSubAccountsBulk","tags":["Application Manager"],"summary":"Create up to 100 sub-accounts at once","description":"Each item is created independently, so one bad row does not fail the batch. Each created entry carries its one-time credentials.\n\n**Auth:** API key or JWT. Scoped keys need `application:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"created":{"type":"array","items":{"$ref":"#/components/schemas/SubAccountCreated"}},"failed":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string"},"error":{"type":"string"}},"required":["label","error"]}},"requested":{"type":"integer"},"createdCount":{"type":"integer"}},"required":["created","failed","requested","createdCount"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"application:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"subAccounts":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":255},"externalRef":{"type":"string","maxLength":10000,"nullable":true},"markupPct":{"type":"number","minimum":0,"maximum":100000,"nullable":true},"dailySpendCap":{"type":"number","minimum":0,"maximum":1000000,"nullable":true},"maxConcurrentCalls":{"type":"integer","minimum":0,"maximum":100000,"nullable":true},"creditLimit":{"type":"number","minimum":0,"maximum":10000000,"nullable":true},"currency":{"type":"string","minLength":3,"maxLength":3}},"required":["label"]},"minItems":1,"maxItems":100}},"required":["subAccounts"]}}}},"x-px-example":{"path":{},"query":{},"body":{"subAccounts":[{"label":"Acme"}]}}}},"/api/v1/application/sub-accounts/{id}":{"get":{"operationId":"getApplicationSubAccountsById","tags":["Application Manager"],"summary":"Get a sub-account","description":"**Auth:** API key or JWT. Scoped keys need `application:write`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SubAccount"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"application:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}},"patch":{"operationId":"patchApplicationSubAccountsById","tags":["Application Manager"],"summary":"Update a sub-account","description":"Suspending or closing revokes its API keys and stops its campaigns.\n\n**Auth:** API key or JWT. Scoped keys need `application:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SubAccount"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"application:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":255},"status":{"type":"string","enum":["active","suspended","closed"]},"markupPct":{"type":"number","minimum":0,"maximum":100000,"nullable":true},"dailySpendCap":{"type":"number","minimum":0,"maximum":1000000,"nullable":true},"maxConcurrentCalls":{"type":"integer","minimum":0,"maximum":100000,"nullable":true},"creditLimit":{"type":"number","minimum":0,"maximum":10000000,"nullable":true},"currency":{"type":"string","minLength":3,"maxLength":3}}}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"label":"Acme","status":"active"}}}},"/api/v1/application/sub-accounts/{id}/credit":{"post":{"operationId":"postApplicationSubAccountsByIdCredit","tags":["Application Manager"],"summary":"Fund a sub-account from your balance","description":"Moves money from your balance into the sub-account. Only active sub-accounts can be funded.\n\n**Auth:** API key or JWT. Scoped keys need `application:write`.\n\n**Idempotency:** send an `X-Idempotency-Key` header to make retries safe; a replay within 24 hours returns the original response.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"operatorBalance":{"type":"number","nullable":true,"description":"Your balance after the transfer, as a JSON number; null when your balance did not move"},"subBalance":{"type":"number","description":"The sub-account balance after the transfer, as a JSON number"}},"required":["operatorBalance","subBalance"],"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"application:write","x-idempotent":true,"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"X-Idempotency-Key","in":"header","required":false,"description":"Any unique string (a UUID is ideal). Replays within 24 hours return the first response instead of acting twice.","schema":{"type":"string","maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"amount":{"type":"number","exclusiveMinimum":true,"minimum":0}},"required":["amount"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"amount":1}},"x-px-billable":{"kind":"money","note":"Moves money between your balance and a sub-account."}}},"/api/v1/application/sub-accounts/{id}/debit":{"post":{"operationId":"postApplicationSubAccountsByIdDebit","tags":["Application Manager"],"summary":"Return funds from a sub-account to your balance","description":"Works on closed sub-accounts too, so a balance can be handed back after closure.\n\n**Auth:** API key or JWT. Scoped keys need `application:write`.\n\n**Idempotency:** send an `X-Idempotency-Key` header to make retries safe; a replay within 24 hours returns the original response.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"operatorBalance":{"type":"number","nullable":true,"description":"Your balance after the transfer, as a JSON number; null when your balance did not move"},"subBalance":{"type":"number","description":"The sub-account balance after the transfer, as a JSON number"}},"required":["operatorBalance","subBalance"],"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"application:write","x-idempotent":true,"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"X-Idempotency-Key","in":"header","required":false,"description":"Any unique string (a UUID is ideal). Replays within 24 hours return the first response instead of acting twice.","schema":{"type":"string","maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"amount":{"type":"number","exclusiveMinimum":true,"minimum":0},"reason":{"type":"string","minLength":1,"maxLength":500}},"required":["amount","reason"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"amount":1,"reason":"Example"}},"x-px-billable":{"kind":"money","note":"Moves money between your balance and a sub-account."}}},"/api/v1/application/sub-accounts/{id}/payment":{"post":{"operationId":"postApplicationSubAccountsByIdPayment","tags":["Application Manager"],"summary":"Record a payment a sub-account made to you","description":"Credits the sub-account for money it paid you outside the platform. Your own balance does not move.\n\n**Auth:** API key or JWT. Scoped keys need `application:write`.\n\n**Idempotency:** send an `X-Idempotency-Key` header to make retries safe; a replay within 24 hours returns the original response.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"operatorBalance":{"type":"number","nullable":true,"description":"Your balance after the transfer, as a JSON number; null when your balance did not move"},"subBalance":{"type":"number","description":"The sub-account balance after the transfer, as a JSON number"}},"required":["operatorBalance","subBalance"],"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"application:write","x-idempotent":true,"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"X-Idempotency-Key","in":"header","required":false,"description":"Any unique string (a UUID is ideal). Replays within 24 hours return the first response instead of acting twice.","schema":{"type":"string","maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"amount":{"type":"number","exclusiveMinimum":true,"minimum":0},"reason":{"type":"string","minLength":1,"maxLength":500}},"required":["amount"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"amount":1}},"x-px-billable":{"kind":"money","note":"Moves money between your balance and a sub-account."}}},"/api/v1/application/sub-accounts/{id}/payment-correction":{"post":{"operationId":"postApplicationSubAccountsByIdPaymentCorrection","tags":["Application Manager"],"summary":"Reverse a recorded sub-account payment","description":"Debits the sub-account to correct a payment recorded in error. Your own balance does not move.\n\n**Auth:** API key or JWT. Scoped keys need `application:write`.\n\n**Idempotency:** send an `X-Idempotency-Key` header to make retries safe; a replay within 24 hours returns the original response.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"operatorBalance":{"type":"number","nullable":true,"description":"Your balance after the transfer, as a JSON number; null when your balance did not move"},"subBalance":{"type":"number","description":"The sub-account balance after the transfer, as a JSON number"}},"required":["operatorBalance","subBalance"],"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"application:write","x-idempotent":true,"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"X-Idempotency-Key","in":"header","required":false,"description":"Any unique string (a UUID is ideal). Replays within 24 hours return the first response instead of acting twice.","schema":{"type":"string","maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"amount":{"type":"number","exclusiveMinimum":true,"minimum":0},"reason":{"type":"string","minLength":1,"maxLength":500}},"required":["amount","reason"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"amount":1,"reason":"Example"}},"x-px-billable":{"kind":"money","note":"Moves money between your balance and a sub-account."}}},"/api/v1/application/sub-accounts/{id}/api-keys":{"post":{"operationId":"postApplicationSubAccountsByIdApiKeys","tags":["Application Manager"],"summary":"Issue an API key for a sub-account","description":"The key is returned ONCE. It can reach only the sub-account traffic endpoints.\n\n**Auth:** API key or JWT. Scoped keys need `application:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"apiKey":{"type":"string"},"prefix":{"type":"string"}},"required":["id","apiKey","prefix"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"application:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}},"get":{"operationId":"getApplicationSubAccountsByIdApiKeys","tags":["Application Manager"],"summary":"List a sub-account's API keys","description":"**Auth:** API key or JWT. Scoped keys need `application:write`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"keyPrefix":{"type":"string"},"label":{"type":"string"},"lastUsedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"expiresAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true}},"required":["id","keyPrefix","label","lastUsedAt","createdAt","expiresAt"]}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"application:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/application/sub-accounts/{id}/api-keys/{keyId}":{"delete":{"operationId":"deleteApplicationSubAccountsByIdApiKeysByKeyId","tags":["Application Manager"],"summary":"Revoke a sub-account API key","description":"**Auth:** API key or JWT. Scoped keys need `application:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"revoked":{"type":"boolean","enum":[true]}},"required":["revoked"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"application:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"keyId","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>","keyId":"<keyId>"},"query":{}}}},"/api/v1/application/sub-accounts/{id}/portal-invite":{"post":{"operationId":"postApplicationSubAccountsByIdPortalInvite","tags":["Application Manager"],"summary":"Set a sub-account's portal email and send a sign-in link","description":"Send `email: null` to clear it. The link is only emailed to active sub-accounts.\n\n**Auth:** API key or JWT. Scoped keys need `application:write`.\n\n**Rate limit:** 10 requests per hour per caller.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SubAccount"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"application:write","x-rate-limit":{"max":10,"window":"hour"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","format":"email","maxLength":255,"nullable":true},"sendInvite":{"type":"boolean","default":true}},"required":["email"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"email":"you@example.com"}},"x-px-billable":{"kind":"email","note":"Sends an email to a third party."}}},"/api/v1/application/sub-accounts/{id}/close":{"post":{"operationId":"postApplicationSubAccountsByIdClose","tags":["Application Manager"],"summary":"Close a sub-account","description":"Ends service: revokes its keys and stops its campaigns. No money moves; return any balance separately with the debit endpoint. Idempotent.\n\n**Auth:** API key or JWT. Scoped keys need `application:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SubAccount"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"application:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/application/sub-accounts/{id}/sip-password":{"post":{"operationId":"postApplicationSubAccountsByIdSipPassword","tags":["Application Manager"],"summary":"Regenerate a sub-account SIP password","description":"The new password is returned ONCE; the old one stops working immediately.\n\n**Auth:** API key or JWT. Scoped keys need `application:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"sipUsername":{"type":"string","nullable":true},"sipPassword":{"type":"string"}},"required":["sipUsername","sipPassword"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"application:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/application/sub-accounts/{id}/usage":{"get":{"operationId":"getApplicationSubAccountsByIdUsage","tags":["Application Manager"],"summary":"Get lifetime usage for a sub-account","description":"**Auth:** API key or JWT. Scoped keys need `application:write`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"records":{"type":"integer"},"totalCost":{"type":"number","description":"USD as a JSON number"},"totalSeconds":{"type":"integer"},"totalSegments":{"type":"integer"}},"required":["records","totalCost","totalSeconds","totalSegments"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"application:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/application/sub-accounts/{id}/analytics":{"get":{"operationId":"getApplicationSubAccountsByIdAnalytics","tags":["Application Manager"],"summary":"Get analytics for one sub-account","description":"**Auth:** API key or JWT. Scoped keys need `application:write`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"period":{"type":"object","properties":{"days":{"type":"integer"}},"required":["days"]},"summary":{"type":"object","properties":{"calls":{"type":"integer"},"sms":{"type":"integer"},"minutes":{"type":"integer"},"revenue":{"type":"number","description":"USD, JSON number (analytics rollup)"},"margin":{"type":"number","description":"USD, JSON number (analytics rollup)"},"asr":{"type":"number","nullable":true,"description":"Answer rate percent over customer sessions; null with no calls"},"acd":{"type":"number"}},"required":["calls","sms","minutes","revenue","margin","asr","acd"],"additionalProperties":true},"timeseries":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string","description":"YYYY-MM-DD"},"calls":{"type":"integer"},"sms":{"type":"integer"},"revenue":{"type":"number"},"margin":{"type":"number"}},"required":["date","calls","sms","revenue","margin"]}}},"required":["period","summary","timeseries"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"application:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"days","in":"query","required":false,"description":"Trailing window in days (default 30)","schema":{"type":"integer","minimum":1,"maximum":365}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/application/sub-accounts/{id}/cdrs":{"get":{"operationId":"getApplicationSubAccountsByIdCdrs","tags":["Application Manager"],"summary":"List call records for a sub-account","description":"Newest first, offset-paginated.\n\n**Auth:** API key or JWT. Scoped keys need `application:write`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true,"description":"A call record row"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"application:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0}},{"name":"kind","in":"query","required":false,"schema":{"type":"string","enum":["voice","sms"]}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/application/sub-accounts/{id}/statement":{"get":{"operationId":"getApplicationSubAccountsByIdStatement","tags":["Application Manager"],"summary":"Get a monthly statement for a sub-account","description":"Spend in USD and in the sub-account's display currency, split by voice and SMS, with a resale-tax block. Derived, not stored.\n\n**Auth:** API key or JWT. Scoped keys need `application:write`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"subAccountId":{"type":"string","format":"uuid"},"label":{"type":"string"},"month":{"type":"string"},"periodStart":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"periodEnd":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"currency":{"type":"string"},"fxRate":{"type":"number"},"records":{"type":"integer"},"spend":{"type":"object","properties":{"usd":{"type":"number"},"inCurrency":{"type":"number"}},"required":["usd","inCurrency"]},"byKind":{"type":"object","properties":{"voice":{"type":"object","properties":{"usd":{"type":"number"},"inCurrency":{"type":"number"}},"required":["usd","inCurrency"]},"sms":{"type":"object","properties":{"usd":{"type":"number"},"inCurrency":{"type":"number"}},"required":["usd","inCurrency"]}},"required":["voice","sms"]},"tax":{"type":"object","properties":{},"additionalProperties":true,"description":"base, ratePct, taxAmount, total, treatment, label, note"}},"required":["subAccountId","label","month","periodStart","periodEnd","currency","fxRate","records","spend","byKind","tax"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"application:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"month","in":"query","required":true,"description":"YYYY-MM","schema":{"type":"string","pattern":"^\\d{4}-\\d{2}$"}}],"x-px-example":{"path":{"id":"<id>"},"query":{"month":"<month>"}}}},"/api/v1/application/sub-accounts/{id}/cdrs/export":{"get":{"operationId":"getApplicationSubAccountsByIdCdrsExport","tags":["Application Manager"],"summary":"Export a sub-account's call records as CSV","description":"**Auth:** API key or JWT. Scoped keys need `application:write`.","responses":{"200":{"description":"Every call record for the sub-account, as CSV.","content":{"text/csv":{"schema":{"type":"string"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"application:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/route-plans":{"get":{"operationId":"getSwitchRoutePlans","tags":["Switch: routing"],"summary":"List route groups","description":"Route groups (stored as route plans): ordered supplier chains with failover rules. Newest change first, with entry counts.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"operatorId":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"enabled":{"type":"boolean"},"failoverSipCodes":{"type":"array","items":{"type":"integer"},"description":"SIP results that move the call to the next supplier"},"maxAttempts":{"type":"integer","description":"1 to 6"},"selectionMode":{"type":"string","enum":["priority","least_cost","weighted"],"description":"How the first supplier is picked; failover is always sequential"},"failoverTimeoutSeconds":{"type":"integer","nullable":true,"description":"null = the platform budget"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"entryCount":{"type":"integer"}},"required":["id","operatorId","name","description","enabled","failoverSipCodes","maxAttempts","selectionMode","failoverTimeoutSeconds","createdAt","updatedAt","entryCount"],"additionalProperties":true}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}},"post":{"operationId":"postSwitchRoutePlans","tags":["Switch: routing"],"summary":"Create a route group","description":"Names must be unique per operator. Defaults: priority selection, 3 attempts, the platform failover timeout.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchRouteGroup"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"description":{"type":"string","maxLength":2000,"nullable":true},"selectionMode":{"type":"string","enum":["priority","least_cost","weighted"]},"failoverSipCodes":{"type":"array","items":{"type":"integer"},"maxItems":40},"maxAttempts":{"type":"integer","minimum":1,"maximum":6},"failoverTimeoutSeconds":{"type":"integer","minimum":5,"maximum":600,"nullable":true}},"required":["name"]}}}},"x-px-example":{"path":{},"query":{},"body":{"name":"Acme"}}}},"/api/v1/switch/route-plans/{id}":{"get":{"operationId":"getSwitchRoutePlansById","tags":["Switch: routing"],"summary":"Get a route group with its suppliers","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"operatorId":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"enabled":{"type":"boolean"},"failoverSipCodes":{"type":"array","items":{"type":"integer"},"description":"SIP results that move the call to the next supplier"},"maxAttempts":{"type":"integer","description":"1 to 6"},"selectionMode":{"type":"string","enum":["priority","least_cost","weighted"],"description":"How the first supplier is picked; failover is always sequential"},"failoverTimeoutSeconds":{"type":"integer","nullable":true,"description":"null = the platform budget"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"entries":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"prefix":{"type":"string","description":"\"\" = any destination"},"routeId":{"type":"string","format":"uuid","nullable":true,"description":"A marketplace route you bought"},"vendorTrunkId":{"type":"string","format":"uuid","nullable":true,"description":"One of your supplier trunks"},"priority":{"type":"integer"},"weightPct":{"type":"integer","nullable":true},"minAsr":{"type":"string","nullable":true,"description":"ASR gate in percent, as a decimal string; null = off"},"maxPdd":{"type":"integer","nullable":true,"description":"PDD gate in ms; null = off"},"enabled":{"type":"boolean"},"destinationName":{"type":"string","nullable":true},"country":{"type":"string","nullable":true},"external":{"type":"boolean","description":"True for a supplier trunk, false for a marketplace route"},"supplierLabel":{"type":"string"},"supplierMeta":{"type":"string"},"trunkLabel":{"type":"string","nullable":true},"trunkHost":{"type":"string","nullable":true,"description":"Withheld (null) for marketplace-promoted trunks"},"trunkStatus":{"type":"string","nullable":true}},"required":["id","prefix","routeId","vendorTrunkId","priority","weightPct","minAsr","maxPdd","enabled","destinationName","country","external","supplierLabel","supplierMeta","trunkLabel","trunkHost","trunkStatus"],"additionalProperties":true}}},"required":["id","operatorId","name","description","enabled","failoverSipCodes","maxAttempts","selectionMode","failoverTimeoutSeconds","createdAt","updatedAt","entries"],"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}},"patch":{"operationId":"patchSwitchRoutePlansById","tags":["Switch: routing"],"summary":"Update a route group's settings","description":"Send `failoverTimeoutSeconds: null` to go back to the platform budget; omit it to leave it unchanged.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchRouteGroup"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"description":{"type":"string","maxLength":2000,"nullable":true},"enabled":{"type":"boolean"},"selectionMode":{"type":"string","enum":["priority","least_cost","weighted"]},"failoverSipCodes":{"type":"array","items":{"type":"integer"},"maxItems":40},"maxAttempts":{"type":"integer","minimum":1,"maximum":6},"failoverTimeoutSeconds":{"type":"integer","minimum":5,"maximum":600,"nullable":true}}}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"name":"Acme","description":"Example"}}},"delete":{"operationId":"deleteSwitchRoutePlansById","tags":["Switch: routing"],"summary":"Delete a route group","description":"Customers assigned to it are detached and fall back to their routing strategy.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"deleted":{"type":"boolean","enum":[true]}},"required":["deleted"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/route-plans/{id}/clone":{"post":{"operationId":"postSwitchRoutePlansByIdClone","tags":["Switch: routing"],"summary":"Clone a route group with all its suppliers","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"entriesCloned":{"type":"integer"}},"required":["id","name","entriesCloned"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/route-plans/{id}/entries":{"put":{"operationId":"putSwitchRoutePlansByIdEntries","tags":["Switch: routing"],"summary":"Replace the suppliers in a route group","description":"Up to 200 entries, each naming exactly one supplier: a marketplace route you bought or one of your active supplier trunks. Duplicate supplier for the same prefix is refused.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"operatorId":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"enabled":{"type":"boolean"},"failoverSipCodes":{"type":"array","items":{"type":"integer"},"description":"SIP results that move the call to the next supplier"},"maxAttempts":{"type":"integer","description":"1 to 6"},"selectionMode":{"type":"string","enum":["priority","least_cost","weighted"],"description":"How the first supplier is picked; failover is always sequential"},"failoverTimeoutSeconds":{"type":"integer","nullable":true,"description":"null = the platform budget"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"entries":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"prefix":{"type":"string","description":"\"\" = any destination"},"routeId":{"type":"string","format":"uuid","nullable":true,"description":"A marketplace route you bought"},"vendorTrunkId":{"type":"string","format":"uuid","nullable":true,"description":"One of your supplier trunks"},"priority":{"type":"integer"},"weightPct":{"type":"integer","nullable":true},"minAsr":{"type":"string","nullable":true,"description":"ASR gate in percent, as a decimal string; null = off"},"maxPdd":{"type":"integer","nullable":true,"description":"PDD gate in ms; null = off"},"enabled":{"type":"boolean"},"destinationName":{"type":"string","nullable":true},"country":{"type":"string","nullable":true},"external":{"type":"boolean","description":"True for a supplier trunk, false for a marketplace route"},"supplierLabel":{"type":"string"},"supplierMeta":{"type":"string"},"trunkLabel":{"type":"string","nullable":true},"trunkHost":{"type":"string","nullable":true,"description":"Withheld (null) for marketplace-promoted trunks"},"trunkStatus":{"type":"string","nullable":true}},"required":["id","prefix","routeId","vendorTrunkId","priority","weightPct","minAsr","maxPdd","enabled","destinationName","country","external","supplierLabel","supplierMeta","trunkLabel","trunkHost","trunkStatus"],"additionalProperties":true}}},"required":["id","operatorId","name","description","enabled","failoverSipCodes","maxAttempts","selectionMode","failoverTimeoutSeconds","createdAt","updatedAt","entries"],"additionalProperties":true}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"entries":{"type":"array","items":{"type":"object","properties":{"prefix":{"type":"string","maxLength":24},"routeId":{"type":"string","format":"uuid","nullable":true},"vendorTrunkId":{"type":"string","format":"uuid","nullable":true},"priority":{"type":"integer","minimum":1,"maximum":99},"weightPct":{"type":"integer","minimum":0,"maximum":100,"nullable":true},"minAsr":{"type":"number","minimum":0,"maximum":100,"nullable":true},"maxPdd":{"type":"integer","minimum":0,"nullable":true},"enabled":{"type":"boolean"}}},"maxItems":200}},"required":["entries"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"entries":[{"prefix":"44","routeId":"<routeId>"}]}}}},"/api/v1/switch/dialplans":{"get":{"operationId":"getSwitchDialplans","tags":["Switch: routing"],"summary":"List dialplans","description":"Dialplans are ordered rules above route groups: match a number, rewrite it and the caller ID, then route or block.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"operatorId":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"enabled":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"ruleCount":{"type":"integer"}},"required":["id","operatorId","name","description","enabled","createdAt","updatedAt","ruleCount"],"additionalProperties":true}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}},"post":{"operationId":"postSwitchDialplans","tags":["Switch: routing"],"summary":"Create a dialplan","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchDialplan"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"description":{"type":"string","maxLength":2000,"nullable":true}},"required":["name"]}}}},"x-px-example":{"path":{},"query":{},"body":{"name":"Acme"}}}},"/api/v1/switch/dialplans/{id}":{"get":{"operationId":"getSwitchDialplansById","tags":["Switch: routing"],"summary":"Get a dialplan with its rules","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"operatorId":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"enabled":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"rules":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"dialplanId":{"type":"string","format":"uuid"},"position":{"type":"integer"},"label":{"type":"string","nullable":true},"enabled":{"type":"boolean"},"matchPrefix":{"type":"string","description":"\"\" = any dialled number"},"matchRegex":{"type":"string","nullable":true},"minLen":{"type":"integer","nullable":true},"maxLen":{"type":"integer","nullable":true},"matchCli":{"type":"string","nullable":true},"jurisdiction":{"type":"string","enum":["any","intrastate","interstate","local","international","domestic"]},"timeStart":{"type":"string","nullable":true,"description":"HH:MM in your timezone"},"timeEnd":{"type":"string","nullable":true},"daysOfWeek":{"type":"array","items":{"type":"integer"},"nullable":true,"description":"0 = Sunday; null = every day"},"stripDigits":{"type":"integer"},"prependDigits":{"type":"string"},"cliMode":{"type":"string","enum":["passthrough","set","strip","prepend","anonymous","did"]},"cliValue":{"type":"string","nullable":true},"action":{"type":"string","enum":["route_group","block"]},"routeGroupId":{"type":"string","format":"uuid","nullable":true},"blockCause":{"type":"integer","description":"SIP code sent when action = block"}},"required":["id","dialplanId","position","label","enabled","matchPrefix","matchRegex","minLen","maxLen","matchCli","jurisdiction","timeStart","timeEnd","daysOfWeek","stripDigits","prependDigits","cliMode","cliValue","action","routeGroupId","blockCause"],"additionalProperties":true}}},"required":["id","operatorId","name","description","enabled","createdAt","updatedAt","rules"],"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}},"patch":{"operationId":"patchSwitchDialplansById","tags":["Switch: routing"],"summary":"Rename, describe, enable or disable a dialplan","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchDialplan"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"description":{"type":"string","maxLength":2000,"nullable":true},"enabled":{"type":"boolean"}}}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"name":"Acme","description":"Example"}}},"delete":{"operationId":"deleteSwitchDialplansById","tags":["Switch: routing"],"summary":"Delete a dialplan","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"deleted":{"type":"boolean","enum":[true]}},"required":["deleted"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/dialplans/{id}/clone":{"post":{"operationId":"postSwitchDialplansByIdClone","tags":["Switch: routing"],"summary":"Clone a dialplan with all its rules","description":"Cloned rules keep their route-group targets.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"rulesCloned":{"type":"integer"}},"required":["id","name","rulesCloned"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/dialplans/{id}/rules":{"put":{"operationId":"putSwitchDialplansByIdRules","tags":["Switch: routing"],"summary":"Replace the rules in a dialplan","description":"Up to 200 rules, evaluated in `position` order. A route_group action must name one of your route groups; regular expressions that risk catastrophic backtracking are refused.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"operatorId":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"enabled":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"rules":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"dialplanId":{"type":"string","format":"uuid"},"position":{"type":"integer"},"label":{"type":"string","nullable":true},"enabled":{"type":"boolean"},"matchPrefix":{"type":"string","description":"\"\" = any dialled number"},"matchRegex":{"type":"string","nullable":true},"minLen":{"type":"integer","nullable":true},"maxLen":{"type":"integer","nullable":true},"matchCli":{"type":"string","nullable":true},"jurisdiction":{"type":"string","enum":["any","intrastate","interstate","local","international","domestic"]},"timeStart":{"type":"string","nullable":true,"description":"HH:MM in your timezone"},"timeEnd":{"type":"string","nullable":true},"daysOfWeek":{"type":"array","items":{"type":"integer"},"nullable":true,"description":"0 = Sunday; null = every day"},"stripDigits":{"type":"integer"},"prependDigits":{"type":"string"},"cliMode":{"type":"string","enum":["passthrough","set","strip","prepend","anonymous","did"]},"cliValue":{"type":"string","nullable":true},"action":{"type":"string","enum":["route_group","block"]},"routeGroupId":{"type":"string","format":"uuid","nullable":true},"blockCause":{"type":"integer","description":"SIP code sent when action = block"}},"required":["id","dialplanId","position","label","enabled","matchPrefix","matchRegex","minLen","maxLen","matchCli","jurisdiction","timeStart","timeEnd","daysOfWeek","stripDigits","prependDigits","cliMode","cliValue","action","routeGroupId","blockCause"],"additionalProperties":true}}},"required":["id","operatorId","name","description","enabled","createdAt","updatedAt","rules"],"additionalProperties":true}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"rules":{"type":"array","items":{"type":"object","properties":{"position":{"type":"integer"},"label":{"type":"string","maxLength":120,"nullable":true},"enabled":{"type":"boolean"},"matchPrefix":{"type":"string","maxLength":24},"matchRegex":{"type":"string","maxLength":400,"nullable":true},"minLen":{"type":"integer","minimum":0,"maximum":24,"nullable":true},"maxLen":{"type":"integer","minimum":0,"maximum":24,"nullable":true},"matchCli":{"type":"string","maxLength":48,"nullable":true},"jurisdiction":{"type":"string","enum":["any","intrastate","interstate","local","international","domestic"]},"timeStart":{"type":"string","pattern":"^\\d{2}:\\d{2}$","nullable":true},"timeEnd":{"type":"string","pattern":"^\\d{2}:\\d{2}$","nullable":true},"daysOfWeek":{"type":"array","items":{"type":"integer","minimum":0,"maximum":6},"nullable":true},"stripDigits":{"type":"integer","minimum":0,"maximum":20},"prependDigits":{"type":"string","maxLength":24},"cliMode":{"type":"string","enum":["passthrough","set","strip","prepend","anonymous","did"]},"cliValue":{"type":"string","maxLength":32,"nullable":true},"action":{"type":"string","enum":["route_group","block"]},"routeGroupId":{"type":"string","format":"uuid","nullable":true},"blockCause":{"type":"integer","minimum":400,"maximum":699}}},"maxItems":200}},"required":["rules"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"rules":[{"position":1,"label":"Acme"}]}}}},"/api/v1/switch/customers/{id}/routing":{"get":{"operationId":"getSwitchCustomersByIdRouting","tags":["Switch: customers"],"summary":"Get a Switch customer routing assignment","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchCustomerRoutingAssignment"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}},"post":{"operationId":"postSwitchCustomersByIdRouting","tags":["Switch: customers"],"summary":"Assign routing to a Switch customer","description":"Sets the dialplan, route group, failover group, strategy or a direct supplier on the customer's first trunk. Use the per-trunk routing endpoint for a specific trunk. Send `X-If-Unchanged-Since: <updatedAt you loaded>` to have the save refused with 409 STALE_WRITE if someone changed the record since.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchCustomerRoutingAssignment"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"dialplanId":{"type":"string","format":"uuid","nullable":true},"routePlanId":{"type":"string","format":"uuid","nullable":true},"failoverRoutePlanId":{"type":"string","format":"uuid","nullable":true},"strategyOverride":{"type":"string","enum":["cheapest","best_quality","balanced"],"nullable":true},"directRouteId":{"type":"string","format":"uuid","nullable":true},"directVendorTrunkId":{"type":"string","format":"uuid","nullable":true}}}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"dialplanId":"<dialplanId>","routePlanId":"<routePlanId>"}}}},"/api/v1/switch/routing/preview":{"get":{"operationId":"getSwitchRoutingPreview","tags":["Switch: routing"],"summary":"Preview how a number would route","description":"Read-only: the dialplan rule matched, number and caller-ID rewrites, the route group, the ordered supplier chain, any customer or trunk restriction that would refuse the call, and candidates that were skipped. Failover is always sequential. For the full reasoning use POST /routing/trace.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"dialplanId":{"type":"string","format":"uuid","nullable":true},"dialplanName":{"type":"string","nullable":true},"matched":{"type":"boolean"},"ruleId":{"type":"string","format":"uuid","nullable":true},"ruleLabel":{"type":"string","nullable":true},"blocked":{"type":"boolean"},"blockCause":{"type":"integer","nullable":true},"translatedNumber":{"type":"string"},"outCli":{"type":"string","nullable":true},"routeGroupId":{"type":"string","format":"uuid","nullable":true},"routeGroupName":{"type":"string","nullable":true},"kind":{"type":"string","description":"fixed route or route group"},"selectionMode":{"type":"string","nullable":true},"failoverMode":{"type":"string","enum":["sequential"]},"failoverSipCodes":{"type":"array","items":{"type":"integer"}},"maxAttempts":{"type":"integer"},"setupBudgetSeconds":{"type":"number","nullable":true},"refusal":{"type":"object","properties":{},"additionalProperties":true,"nullable":true,"description":"Why the chain is empty on purpose"},"restriction":{"type":"object","properties":{},"additionalProperties":true,"nullable":true,"description":"A customer or trunk restriction that would refuse this call"},"skipped":{"type":"array","items":{"type":"object","properties":{"supplier":{"type":"string"},"reason":{"type":"string"},"detail":{"type":"string","nullable":true},"vendorTrunkId":{"type":"string","format":"uuid","nullable":true}},"required":["supplier","reason","detail","vendorTrunkId"]}},"candidates":{"type":"array","items":{"type":"object","properties":{"attempt":{"type":"integer"},"routeId":{"type":"string"},"destination":{"type":"string","nullable":true},"country":{"type":"string","nullable":true},"pricePerUnit":{"type":"string","description":"Cost per minute of this supplier, 6-decimal string"},"matchedPrefix":{"type":"string","nullable":true},"priority":{"type":"integer","nullable":true},"external":{"type":"boolean"},"supplier":{"type":"string","enum":["external trunk","marketplace"]},"endpoint":{"type":"string","nullable":true}},"required":["attempt","routeId","destination","country","pricePerUnit","matchedPrefix","priority","external","supplier","endpoint"],"additionalProperties":true}}},"required":["dialplanId","dialplanName","matched","ruleId","ruleLabel","blocked","blockCause","translatedNumber","outCli","routeGroupId","routeGroupName","kind","selectionMode","failoverMode","failoverSipCodes","maxAttempts","setupBudgetSeconds","refusal","restriction","skipped","candidates"],"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"to","in":"query","required":true,"description":"Dialled number","schema":{"type":"string"}},{"name":"cli","in":"query","required":false,"schema":{"type":"string"}},{"name":"type","in":"query","required":false,"schema":{"type":"string","enum":["voice","sms"]}},{"name":"subAccountId","in":"query","required":false,"description":"The customer","schema":{"type":"string","format":"uuid"}},{"name":"customerTrunkId","in":"query","required":false,"description":"Name the trunk for an exact restriction check","schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{},"query":{"to":"+447700900123"}}}},"/api/v1/switch/routing/trace":{"post":{"operationId":"postSwitchRoutingTrace","tags":["Switch: routing"],"summary":"Run a route trace for a number","description":"Explains the routing decision end to end: normalisation, the policy matched, the sell price, every eligible supplier with its buy rate, capacity and margin, and why each excluded supplier was excluded. Uses the same resolvers as live calls but is NOT a call: no call record, balance movement or capacity use. The result is kept for an hour so it can be saved.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchRouteTrace"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"to":{"type":"string","minLength":1,"maxLength":32},"cli":{"type":"string","maxLength":32,"nullable":true},"type":{"type":"string","enum":["voice","sms"]},"subAccountId":{"type":"string","format":"uuid","nullable":true,"description":"The customer"},"customerTrunkId":{"type":"string","format":"uuid","nullable":true}},"required":["to"]}}}},"x-px-example":{"path":{},"query":{},"body":{"to":"+447700900123"}}}},"/api/v1/switch/routing/traces":{"post":{"operationId":"postSwitchRoutingTraces","tags":["Switch: routing"],"summary":"Save a route trace","description":"Keeps a trace run within the last hour, by its traceId, with an optional note. The stored copy is the server's own result. Saving the same trace twice returns `alreadySaved: true`.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"traceId":{"type":"string","format":"uuid"},"alreadySaved":{"type":"boolean"}},"required":["id","traceId","alreadySaved"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"traceId":{"type":"string","format":"uuid"},"note":{"type":"string","maxLength":2000,"nullable":true}},"required":["traceId"]}}}},"x-px-example":{"path":{},"query":{},"body":{"traceId":"<traceId>"}}},"get":{"operationId":"getSwitchRoutingTraces","tags":["Switch: routing"],"summary":"List saved route traces","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"traceId":{"type":"string","format":"uuid"},"note":{"type":"string","nullable":true},"destination":{"type":"string"},"cli":{"type":"string","nullable":true},"callType":{"type":"string"},"subAccountId":{"type":"string","format":"uuid","nullable":true},"customerTrunkId":{"type":"string","format":"uuid","nullable":true},"routes":{"type":"boolean"},"sipCode":{"type":"integer","nullable":true},"reason":{"type":"string","nullable":true},"summary":{"type":"string"},"selectedLabel":{"type":"string","nullable":true},"buyRate":{"type":"string","nullable":true,"description":"Decimal string"},"sellRate":{"type":"string","nullable":true,"description":"Decimal string"},"savedBy":{"type":"string","nullable":true},"ranAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","traceId","note","destination","cli","callType","subAccountId","customerTrunkId","routes","sipCode","reason","summary","selectedLabel","buyRate","sellRate","savedBy","ranAt","createdAt"],"additionalProperties":true}},"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"}},"required":["items","total","limit","offset"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"limit","in":"query","required":false,"description":"Default 25","schema":{"type":"integer","minimum":1,"maximum":100}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/switch/routing/traces/{id}":{"get":{"operationId":"getSwitchRoutingTracesById","tags":["Switch: routing"],"summary":"Get a saved route trace","description":"The snapshot as it was saved. It is never re-run; running again produces a new trace.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchRouteTrace"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}},"delete":{"operationId":"deleteSwitchRoutingTracesById","tags":["Switch: routing"],"summary":"Delete a saved route trace","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"}},"required":["id"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/cost-analysis":{"get":{"operationId":"getSwitchCostAnalysis","tags":["Switch: rating"],"summary":"Analyse the cost and configured margin of a destination","description":"Resolves the route a call from this customer trunk would take (the same resolver the switch uses), prices every eligible supplier with its own increment and deck, and estimates margin on a call of `seconds` length. Read-only: no call record, balance or capacity is touched. This is an estimate; see /margin/realised for what was actually earned.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchCostAnalysis"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"destination","in":"query","required":true,"schema":{"type":"string","minLength":1,"maxLength":32}},{"name":"origin","in":"query","required":false,"schema":{"type":"string","maxLength":32}},{"name":"customerId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"customerTrunkId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"seconds","in":"query","required":false,"description":"Reference call length for the margin estimate","schema":{"type":"integer","minimum":1,"maximum":21600}}],"x-px-example":{"path":{},"query":{"destination":"+447700900123"}}}},"/api/v1/switch/cost-analysis/suppliers":{"get":{"operationId":"getSwitchCostAnalysisSuppliers","tags":["Switch: rating"],"summary":"List the suppliers that can carry a customer's traffic","description":"Destination-independent: which supplier trunks the customer's routing makes eligible, and whether each can be priced. Name a customer or a customer trunk. When a customer has several trunks with different routing, `ambiguous` says so.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"suppliers":{"type":"array","items":{"$ref":"#/components/schemas/SwitchEligibleSupplier"}},"routing":{"type":"object","properties":{"kind":{"type":"string","enum":["fixed","group","dialplan","none"]},"name":{"type":"string","nullable":true},"selectionMode":{"type":"string","nullable":true},"maxAttempts":{"type":"integer","nullable":true},"trunkIds":{"type":"array","items":{"type":"string","format":"uuid"}}},"required":["kind","name","selectionMode","maxAttempts","trunkIds"]},"ambiguous":{"type":"string","nullable":true}},"required":["suppliers","routing","ambiguous"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"customerId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"customerTrunkId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/switch/margin/realised":{"get":{"operationId":"getSwitchMarginRealised","tags":["Switch: rating"],"summary":"Get realised margin over a period","description":"What customers were actually charged minus what suppliers actually cost, including the estimated cost of answered attempts that did not win. All amounts are JSON numbers in USD. `exposure` lists what makes the figure less reliable (for example sessions billed with no supplier cost).\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"kind":{"type":"string","enum":["realised_actual"]},"window":{"type":"object","properties":{"from":{"type":"string"},"to":{"type":"string"},"label":{"type":"string"}},"required":["from","to","label"]},"basis":{"type":"object","properties":{},"additionalProperties":true},"answer":{"type":"object","properties":{},"additionalProperties":true},"revenue":{"type":"object","properties":{"customerCharges":{"type":"number","description":"USD as a JSON number (engine output, up to 6 decimal places)"},"platformFee":{"type":"number","description":"USD as a JSON number (engine output, up to 6 decimal places)"},"feeCertainty":{"type":"string","enum":["exact","upper_bound"]},"operatorRevenue":{"type":"number","description":"USD as a JSON number (engine output, up to 6 decimal places)"}},"required":["customerCharges","platformFee","feeCertainty","operatorRevenue"]},"cost":{"type":"object","properties":{"booked":{"type":"number","description":"USD as a JSON number (engine output, up to 6 decimal places)"},"unbookedAttemptCost":{"type":"number","description":"USD as a JSON number (engine output, up to 6 decimal places)"},"unbookedAttempts":{"type":"integer"},"total":{"type":"number","description":"USD as a JSON number (engine output, up to 6 decimal places)"}},"required":["booked","unbookedAttemptCost","unbookedAttempts","total"]},"gross":{"type":"number","description":"USD as a JSON number (engine output, up to 6 decimal places)"},"grossPct":{"type":"number","nullable":true},"exposure":{"type":"object","properties":{},"additionalProperties":true}},"required":["kind","window","basis","answer","revenue","cost","gross","grossPct","exposure"],"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"from","in":"query","required":false,"description":"ISO timestamp; default 24 hours before `to`","schema":{"type":"string"}},{"name":"to","in":"query","required":false,"description":"ISO timestamp; default now","schema":{"type":"string"}},{"name":"customerId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"customerTrunkId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"supplierTrunkId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"kind","in":"query","required":false,"description":"voice (default) or all, which includes SMS","schema":{"type":"string","enum":["voice","all"]}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/switch/margin/realised/sessions":{"get":{"operationId":"getSwitchMarginRealisedSessions","tags":["Switch: rating"],"summary":"List per-call realised margin","description":"One row per session with its charge and every supplier attempt beneath it. Paged (limit up to 200).\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"rows":{"type":"array","items":{"$ref":"#/components/schemas/SwitchSessionMargin"}},"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"}},"required":["rows","total","limit","offset"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"from","in":"query","required":false,"description":"ISO timestamp; default 24 hours before `to`","schema":{"type":"string"}},{"name":"to","in":"query","required":false,"description":"ISO timestamp; default now","schema":{"type":"string"}},{"name":"customerId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"customerTrunkId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"supplierTrunkId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"kind","in":"query","required":false,"description":"voice (default) or all, which includes SMS","schema":{"type":"string","enum":["voice","all"]}},{"name":"negativeOnly","in":"query","required":false,"description":"Only sessions that lost money","schema":{"type":"boolean"}},{"name":"failoverOnly","in":"query","required":false,"description":"Only sessions that needed more than one attempt","schema":{"type":"boolean"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/switch/margin/realised/sessions/{callUuid}":{"get":{"operationId":"getSwitchMarginRealisedSessionsByCallUuid","tags":["Switch: rating"],"summary":"Get the realised margin of one call","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchSessionMargin"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"callUuid","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"callUuid":"<callUuid>"},"query":{}}}},"/api/v1/switch/customer-trunks/auth-modes":{"get":{"operationId":"getSwitchCustomerTrunksAuthModes","tags":["Switch: customer trunks"],"summary":"List the trunk authentication methods available to you","description":"For each method: what the customer must send and what the switch checks. Methods the platform cannot honour for you are omitted.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"mode":{"type":"string","enum":["ip","credentials","ip_and_credentials","registration","certificate"]},"title":{"type":"string"},"summary":{"type":"string"},"sends":{"type":"array","items":{"type":"string"},"description":"What the customer must send"},"checks":{"type":"array","items":{"type":"string"},"description":"What the switch checks on every call"},"requires":{"type":"array","items":{"type":"string","enum":["addresses","credentials"]}},"needsPlatformSupport":{"type":"boolean"}},"required":["mode","title","summary","sends","checks","requires"]}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/switch/customers/{id}/trunks":{"get":{"operationId":"getSwitchCustomersByIdTrunks","tags":["Switch: customers"],"summary":"List a Switch customer trunks with traffic","description":"Each trunk with its authentication readiness, identification, addresses, routing, inherited limits and traffic over the chosen period.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/SwitchCustomerTrunkListRow"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"scope","in":"query","required":false,"description":"Default operational (excludes archived)","schema":{"type":"string","enum":["operational","archived","all"]}},{"name":"periodHours","in":"query","required":false,"description":"Window for the traffic figures; unrecognised values fall back to 24","schema":{"type":"integer"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}},"post":{"operationId":"postSwitchCustomersByIdTrunks","tags":["Switch: customers"],"summary":"Add a trunk to a Switch customer","description":"If `sipPassword` is set it is echoed back ONCE in the response.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"subAccountId":{"type":"string","format":"uuid","description":"The customer this trunk belongs to"},"label":{"type":"string"},"status":{"type":"string","enum":["active","disabled","archived"]},"authMode":{"type":"string","enum":["ip","credentials","ip_and_credentials","registration","certificate"]},"sipUsername":{"type":"string","nullable":true},"maxConcurrentCalls":{"type":"integer","nullable":true,"description":"Null inherits the customer ceiling"},"maxCps":{"type":"integer","nullable":true},"markupPct":{"type":"string","nullable":true},"billingIncrement":{"type":"string","nullable":true},"techPrefix":{"type":"string","nullable":true},"mediaMode":{"type":"string","enum":["proxy","direct"]},"cliRewrite":{"type":"object","additionalProperties":{},"nullable":true},"allowedPrefixes":{"type":"array","items":{"type":"string"},"nullable":true},"allowedCountries":{"type":"array","items":{"type":"string"},"nullable":true},"blockedCountries":{"type":"array","items":{"type":"string"},"nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"sipPassword":{"type":"string","nullable":true}},"required":["id","subAccountId","label","status","sipUsername","maxConcurrentCalls","maxCps","markupPct","billingIncrement","techPrefix","cliRewrite","allowedPrefixes","allowedCountries","blockedCountries","createdAt","updatedAt","sipPassword"],"additionalProperties":true}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string","maxLength":120},"authMode":{"type":"string","enum":["ip","credentials","ip_and_credentials","registration","certificate"],"description":"What the customer must present; the service refuses a mode the trunk is not configured for"},"sipUsername":{"type":"string","maxLength":64,"nullable":true},"sipPassword":{"type":"string","maxLength":64,"nullable":true},"maxConcurrentCalls":{"type":"integer","minimum":0,"maximum":100000,"nullable":true},"maxCps":{"type":"integer","minimum":0,"maximum":10000,"nullable":true},"markupPct":{"type":"number","minimum":0,"maximum":10000,"nullable":true},"billingIncrement":{"type":"string","maxLength":10,"nullable":true},"blockedPrefixes":{"type":"string","maxLength":8000,"nullable":true},"status":{"type":"string","enum":["active","disabled"]},"mediaMode":{"type":"string","enum":["proxy","direct"]},"techPrefix":{"type":"string","maxLength":24,"nullable":true},"cliRewrite":{"anyOf":[{"type":"object","properties":{"mode":{"type":"string","enum":["none"]}},"required":["mode"]},{"type":"object","properties":{"mode":{"type":"string","enum":["fixed"]},"value":{"type":"string","maxLength":24}},"required":["mode","value"]},{"type":"object","properties":{"mode":{"type":"string","enum":["prefix"]},"strip":{"type":"integer","minimum":0,"maximum":15},"add":{"type":"string","maxLength":12}},"required":["mode"]},{"type":"object","properties":{"mode":{"type":"string","enum":["pattern"]},"match":{"type":"string","maxLength":200},"replace":{"type":"string","maxLength":200}},"required":["mode","match","replace"]}],"nullable":true},"allowedPrefixes":{"type":"array","items":{"type":"string","maxLength":24},"maxItems":500,"nullable":true},"allowedCountries":{"type":"array","items":{"type":"string","maxLength":2},"maxItems":300,"nullable":true},"blockedCountries":{"type":"array","items":{"type":"string","maxLength":2},"maxItems":300,"nullable":true},"maxCallDurationSeconds":{"type":"integer","minimum":1,"maximum":21600,"nullable":true},"requireCli":{"type":"boolean"},"allowedClis":{"type":"array","items":{"type":"string","maxLength":24},"maxItems":500,"nullable":true},"marginProtectionMode":{"type":"string","enum":["off","monitor","enforce"]},"minMarginPct":{"type":"number","minimum":0,"maximum":99.999,"nullable":true},"minMarginAbs":{"type":"number","minimum":0,"maximum":1000,"nullable":true},"maxLossPerMinute":{"type":"number","minimum":0,"maximum":1000,"nullable":true},"dailyLossLimit":{"type":"number","minimum":0,"maximum":10000000,"nullable":true,"description":"Warns only; never blocks"},"dailyLossLimitPct":{"type":"number","minimum":0,"maximum":100000,"nullable":true}}}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"label":"Acme","authMode":"ip"}}}},"/api/v1/switch/customer-trunks/{trunkId}":{"patch":{"operationId":"patchSwitchCustomerTrunksByTrunkId","tags":["Switch: customer trunks"],"summary":"Update a Switch customer trunk","description":"Setting `status` to disabled stops new calls but keeps the trunk configurable. A `sipPassword` sent here is echoed back once. Archived trunks are frozen: restore first. Send `X-If-Unchanged-Since: <updatedAt you loaded>` to have the save refused with 409 STALE_WRITE if someone changed the record since.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchCustomerTrunk"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"trunkId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string","maxLength":120},"authMode":{"type":"string","enum":["ip","credentials","ip_and_credentials","registration","certificate"],"description":"What the customer must present; the service refuses a mode the trunk is not configured for"},"sipUsername":{"type":"string","maxLength":64,"nullable":true},"sipPassword":{"type":"string","maxLength":64,"nullable":true},"maxConcurrentCalls":{"type":"integer","minimum":0,"maximum":100000,"nullable":true},"maxCps":{"type":"integer","minimum":0,"maximum":10000,"nullable":true},"markupPct":{"type":"number","minimum":0,"maximum":10000,"nullable":true},"billingIncrement":{"type":"string","maxLength":10,"nullable":true},"blockedPrefixes":{"type":"string","maxLength":8000,"nullable":true},"status":{"type":"string","enum":["active","disabled"]},"mediaMode":{"type":"string","enum":["proxy","direct"]},"techPrefix":{"type":"string","maxLength":24,"nullable":true},"cliRewrite":{"anyOf":[{"type":"object","properties":{"mode":{"type":"string","enum":["none"]}},"required":["mode"]},{"type":"object","properties":{"mode":{"type":"string","enum":["fixed"]},"value":{"type":"string","maxLength":24}},"required":["mode","value"]},{"type":"object","properties":{"mode":{"type":"string","enum":["prefix"]},"strip":{"type":"integer","minimum":0,"maximum":15},"add":{"type":"string","maxLength":12}},"required":["mode"]},{"type":"object","properties":{"mode":{"type":"string","enum":["pattern"]},"match":{"type":"string","maxLength":200},"replace":{"type":"string","maxLength":200}},"required":["mode","match","replace"]}],"nullable":true},"allowedPrefixes":{"type":"array","items":{"type":"string","maxLength":24},"maxItems":500,"nullable":true},"allowedCountries":{"type":"array","items":{"type":"string","maxLength":2},"maxItems":300,"nullable":true},"blockedCountries":{"type":"array","items":{"type":"string","maxLength":2},"maxItems":300,"nullable":true},"maxCallDurationSeconds":{"type":"integer","minimum":1,"maximum":21600,"nullable":true},"requireCli":{"type":"boolean"},"allowedClis":{"type":"array","items":{"type":"string","maxLength":24},"maxItems":500,"nullable":true},"marginProtectionMode":{"type":"string","enum":["off","monitor","enforce"]},"minMarginPct":{"type":"number","minimum":0,"maximum":99.999,"nullable":true},"minMarginAbs":{"type":"number","minimum":0,"maximum":1000,"nullable":true},"maxLossPerMinute":{"type":"number","minimum":0,"maximum":1000,"nullable":true},"dailyLossLimit":{"type":"number","minimum":0,"maximum":10000000,"nullable":true,"description":"Warns only; never blocks"},"dailyLossLimitPct":{"type":"number","minimum":0,"maximum":100000,"nullable":true}}}}}},"x-px-example":{"path":{"trunkId":"<trunkId>"},"query":{},"body":{"label":"Acme","authMode":"ip"}}},"delete":{"operationId":"deleteSwitchCustomerTrunksByTrunkId","tags":["Switch: customer trunks"],"summary":"Delete an unused Switch customer trunk","description":"Refused, naming the dependency, once the trunk has carried traffic, holds rates or routing, or is the customer's last trunk. Archive it instead. Check removability first.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"deleted":{"type":"boolean","enum":[true]},"label":{"type":"string"}},"required":["deleted","label"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"trunkId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"trunkId":"<trunkId>"},"query":{}}}},"/api/v1/switch/customer-trunks/{trunkId}/effective-config":{"get":{"operationId":"getSwitchCustomerTrunksByTrunkIdEffectiveConfig","tags":["Switch: customer trunks"],"summary":"Show the configuration actually in force on a trunk","description":"Every setting with the value a call would meet and the level it was inherited from, resolved by the same code as the call path. Read-only.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchTrunkEffectiveConfig"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"trunkId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"trunkId":"<trunkId>"},"query":{}}}},"/api/v1/switch/customer-trunks/{trunkId}/archive":{"post":{"operationId":"postSwitchCustomerTrunksByTrunkIdArchive","tags":["Switch: customer trunks"],"summary":"Archive a Switch customer trunk","description":"Takes the trunk out of service and out of operational lists, and freezes it. Nothing is destroyed; restore brings it back disabled.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchCustomerTrunk"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"trunkId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","maxLength":500,"nullable":true}}}}}},"x-px-example":{"path":{"trunkId":"<trunkId>"},"query":{},"body":{"reason":"Example"}}}},"/api/v1/switch/customer-trunks/{trunkId}/restore":{"post":{"operationId":"postSwitchCustomerTrunksByTrunkIdRestore","tags":["Switch: customer trunks"],"summary":"Restore an archived Switch customer trunk","description":"Comes back disabled, so no traffic starts until you enable it.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchCustomerTrunk"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"trunkId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"trunkId":"<trunkId>"},"query":{}}}},"/api/v1/switch/customer-trunks/{trunkId}/service-impact":{"get":{"operationId":"getSwitchCustomerTrunksByTrunkIdServiceImpact","tags":["Switch: customer trunks"],"summary":"Preview what disabling, enabling or archiving a trunk would do","description":"Live channels, recent traffic, whether it is the customer's last enabled trunk, and what survives.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"action":{"type":"string","enum":["disable","enable","archive","restore"]},"trunk":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"label":{"type":"string"},"status":{"type":"string"}},"required":["id","label","status"]},"customer":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"label":{"type":"string"},"status":{"type":"string"}},"required":["id","label","status"]},"liveChannels":{"type":"integer"},"last24h":{"type":"object","additionalProperties":{}},"siblingsEnabled":{"type":"integer"},"stopsCustomer":{"type":"boolean","description":"True when this is the customer's last enabled trunk"},"reversible":{"type":"boolean"},"consequences":{"type":"array","items":{"type":"string"}},"preserved":{"type":"array","items":{"type":"string"}}},"required":["action","trunk","customer","liveChannels","last24h","siblingsEnabled","stopsCustomer","reversible","consequences","preserved"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"trunkId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"action","in":"query","required":false,"description":"Default disable","schema":{"type":"string","enum":["disable","enable","archive","restore"]}}],"x-px-example":{"path":{"trunkId":"<trunkId>"},"query":{}}}},"/api/v1/switch/customer-trunks/{trunkId}/removability":{"get":{"operationId":"getSwitchCustomerTrunksByTrunkIdRemovability","tags":["Switch: customer trunks"],"summary":"Check whether a Switch customer trunk can be deleted","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"trunk":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"label":{"type":"string"},"status":{"type":"string"}},"required":["id","label","status"]},"deletable":{"type":"boolean"},"blockers":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","enum":["traffic","refusals","billing","rates","routing","audit","last_trunk"]},"count":{"type":"integer"},"detail":{"type":"string"}},"required":["kind","count","detail"]}}},"required":["trunk","deletable","blockers"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"trunkId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"trunkId":"<trunkId>"},"query":{}}}},"/api/v1/switch/customer-trunks/{trunkId}/clone":{"post":{"operationId":"postSwitchCustomerTrunksByTrunkIdClone","tags":["Switch: customer trunks"],"summary":"Clone a Switch customer trunk","description":"Copies the trunk's settings and sell rates to a new trunk on the same customer.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"subAccountId":{"type":"string","format":"uuid","description":"The customer this trunk belongs to"},"label":{"type":"string"},"status":{"type":"string","enum":["active","disabled","archived"]},"authMode":{"type":"string","enum":["ip","credentials","ip_and_credentials","registration","certificate"]},"sipUsername":{"type":"string","nullable":true},"sipPasswordSet":{"type":"boolean"},"maxConcurrentCalls":{"type":"integer","nullable":true,"description":"Null inherits the customer ceiling"},"maxCps":{"type":"integer","nullable":true},"markupPct":{"type":"string","nullable":true},"billingIncrement":{"type":"string","nullable":true},"techPrefix":{"type":"string","nullable":true},"mediaMode":{"type":"string","enum":["proxy","direct"]},"cliRewrite":{"type":"object","additionalProperties":{},"nullable":true},"allowedPrefixes":{"type":"array","items":{"type":"string"},"nullable":true},"allowedCountries":{"type":"array","items":{"type":"string"},"nullable":true},"blockedCountries":{"type":"array","items":{"type":"string"},"nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"copiedRates":{"type":"integer"}},"required":["id","subAccountId","label","status","sipUsername","sipPasswordSet","maxConcurrentCalls","maxCps","markupPct","billingIncrement","techPrefix","cliRewrite","allowedPrefixes","allowedCountries","blockedCountries","createdAt","updatedAt","copiedRates"],"additionalProperties":true}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"trunkId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":120}},"required":["label"]}}}},"x-px-example":{"path":{"trunkId":"<trunkId>"},"query":{},"body":{"label":"Acme"}}}},"/api/v1/switch/customer-trunks/{trunkId}/ips":{"get":{"operationId":"getSwitchCustomerTrunksByTrunkIdIps","tags":["Switch: customer trunks"],"summary":"List a trunk's allowed source addresses","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"cidr":{"type":"string"},"description":{"type":"string","nullable":true}},"required":["id","cidr","description"]}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"trunkId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"trunkId":"<trunkId>"},"query":{}}},"post":{"operationId":"postSwitchCustomerTrunksByTrunkIdIps","tags":["Switch: customer trunks"],"summary":"Allow a source address on a trunk","description":"Stored in canonical form. Refused when it cannot be saved (see addresses/preview); overlaps with other entries are returned in `conflicts`. Applies to new calls only.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"cidr":{"type":"string"},"description":{"type":"string","nullable":true},"conflicts":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string"},"otherId":{"type":"string","format":"uuid"},"otherCidr":{"type":"string"},"otherTrunkId":{"type":"string","format":"uuid","nullable":true},"otherTrunkLabel":{"type":"string","nullable":true},"otherCustomerId":{"type":"string","format":"uuid","nullable":true},"otherCustomerLabel":{"type":"string","nullable":true}},"required":["kind","otherId","otherCidr","otherTrunkId","otherTrunkLabel","otherCustomerId","otherCustomerLabel"],"additionalProperties":true}}},"required":["id","cidr","description","conflicts"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"trunkId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"cidr":{"type":"string","minLength":7,"maxLength":64,"description":"An IP address or CIDR block"},"description":{"type":"string","maxLength":160}},"required":["cidr"]}}}},"x-px-example":{"path":{"trunkId":"<trunkId>"},"query":{},"body":{"cidr":"<cidr>"}}}},"/api/v1/switch/customer-trunks/{trunkId}/addresses":{"get":{"operationId":"getSwitchCustomerTrunksByTrunkIdAddresses","tags":["Switch: customer trunks"],"summary":"List a trunk's addresses with overlaps and customer-level entries","description":"The richer form of /ips: each entry with its canonical form and every overlapping entry on your switch, including addresses added on the customer.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchTrunkAddressPanel"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"trunkId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"trunkId":"<trunkId>"},"query":{}}}},"/api/v1/switch/customer-trunks/{trunkId}/addresses/preview":{"post":{"operationId":"postSwitchCustomerTrunksByTrunkIdAddressesPreview","tags":["Switch: customer trunks"],"summary":"Preview an address before allowing it on a trunk","description":"Read-only: the canonical form, size, whether it would be refused, and what it overlaps.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"canonical":{"type":"string"},"prefixBits":{"type":"integer"},"addressCount":{"type":"number"},"blocked":{"type":"object","properties":{"reason":{"type":"string"}},"required":["reason"],"nullable":true,"description":"Set when the address cannot be saved at all"},"conflicts":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string"},"otherId":{"type":"string","format":"uuid"},"otherCidr":{"type":"string"},"otherTrunkId":{"type":"string","format":"uuid","nullable":true},"otherTrunkLabel":{"type":"string","nullable":true},"otherCustomerId":{"type":"string","format":"uuid","nullable":true},"otherCustomerLabel":{"type":"string","nullable":true}},"required":["kind","otherId","otherCidr","otherTrunkId","otherTrunkLabel","otherCustomerId","otherCustomerLabel"],"additionalProperties":true}}},"required":["canonical","prefixBits","addressCount","blocked","conflicts"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"trunkId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"cidr":{"type":"string","minLength":1,"maxLength":64}},"required":["cidr"]}}}},"x-px-example":{"path":{"trunkId":"<trunkId>"},"query":{},"body":{"cidr":"<cidr>"}}}},"/api/v1/switch/customer-trunks/cli-rewrite/preview":{"post":{"operationId":"postSwitchCustomerTrunksCliRewritePreview","tags":["Switch: customer trunks"],"summary":"Test a caller-ID rewrite rule against a sample number","description":"Dry run; saves nothing and needs no trunk.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"ok":{"type":"boolean"},"result":{"type":"string","nullable":true},"error":{"type":"string"}},"required":["ok","result"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"rule":{"description":"A cliRewrite rule as used on a trunk"},"sample":{"type":"string","minLength":1,"maxLength":32}},"required":["sample"]}}}},"x-px-example":{"path":{},"query":{},"body":{"sample":"<sample>"}}}},"/api/v1/switch/customer-trunks/{trunkId}/ips/{aclId}":{"delete":{"operationId":"deleteSwitchCustomerTrunksByTrunkIdIpsByAclId","tags":["Switch: customer trunks"],"summary":"Remove an allowed source address from a trunk","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"cidr":{"type":"string"},"description":{"type":"string","nullable":true},"deleted":{"type":"boolean","enum":[true]}},"required":["id","cidr","description","deleted"],"additionalProperties":true}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"trunkId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"aclId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"trunkId":"<trunkId>","aclId":"<aclId>"},"query":{}}}},"/api/v1/switch/customer-trunks/{trunkId}/routing":{"post":{"operationId":"postSwitchCustomerTrunksByTrunkIdRouting","tags":["Switch: customer trunks"],"summary":"Set routing on a Switch customer trunk","description":"Route group, failover group, dialplan, strategy or a direct supplier for this trunk. Send `X-If-Unchanged-Since: <updatedAt you loaded>` to have the save refused with 409 STALE_WRITE if someone changed the record since.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchCustomerRoutingAssignment"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"trunkId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"routePlanId":{"type":"string","format":"uuid","nullable":true},"failoverRoutePlanId":{"type":"string","format":"uuid","nullable":true},"directRouteId":{"type":"string","format":"uuid","nullable":true},"directVendorTrunkId":{"type":"string","format":"uuid","nullable":true},"dialplanId":{"type":"string","format":"uuid","nullable":true},"strategyOverride":{"type":"string","maxLength":24,"nullable":true}}}}}},"x-px-example":{"path":{"trunkId":"<trunkId>"},"query":{},"body":{"routePlanId":"<routePlanId>","failoverRoutePlanId":"<failoverRoutePlanId>"}}}},"/api/v1/switch/customer-trunks/{trunkId}/routing-path":{"get":{"operationId":"getSwitchCustomerTrunksByTrunkIdRoutingPath","tags":["Switch: customer trunks"],"summary":"Show the route wired up for a trunk","description":"Customer, trunk, fixed route or route group, then supplier trunks, with ids. For what a specific number would do, use /switch/routing/preview.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"customer":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"label":{"type":"string"}},"required":["id","label"],"nullable":true},"customerTrunk":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"label":{"type":"string"},"status":{"type":"string"},"techPrefix":{"type":"string","nullable":true}},"required":["id","label","status","techPrefix"]},"kind":{"type":"string","enum":["fixed","group","none"],"description":"Fixed route, route group, or nothing wired"},"fixed":{"type":"object","additionalProperties":{},"nullable":true},"group":{"type":"object","additionalProperties":{},"nullable":true},"failoverGroup":{"type":"object","additionalProperties":{},"nullable":true},"dialplan":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"}},"required":["id","name"],"nullable":true},"strategyOverride":{"type":"string","nullable":true},"unrouted":{"type":"boolean"}},"required":["customer","customerTrunk","kind","fixed","group","failoverGroup","dialplan","strategyOverride","unrouted"],"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"trunkId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"trunkId":"<trunkId>"},"query":{}}}},"/api/v1/switch/customers":{"get":{"operationId":"getSwitchCustomers","tags":["Switch: customers"],"summary":"List your Switch customers with live and 24-hour figures","description":"Every customer with trunk health, live calls, 24-hour traffic, credit used, primary contact and problem flags.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/SwitchCustomerListRow"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}},"post":{"operationId":"postSwitchCustomers","tags":["Switch: customers"],"summary":"Create a Switch customer","description":"Creates the customer, a \"Default\" trunk carrying the same credentials and limits, an empty routing row, and the customer's first API key. The SIP password and API key are returned ONCE in this response.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchCustomerCreated"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":160},"source":{"type":"string","enum":["marketplace","external"]},"status":{"type":"string","enum":["draft","active"]},"externalRef":{"type":"string","maxLength":255,"nullable":true},"creditLimit":{"type":"number","minimum":0,"nullable":true},"markupPct":{"type":"number","minimum":0,"maximum":100000,"nullable":true},"billingIncrement":{"type":"string","maxLength":10,"nullable":true},"currency":{"type":"string","minLength":3,"maxLength":3,"nullable":true},"minMarginPct":{"type":"number","minimum":0,"maximum":100000,"nullable":true},"marginFloorAction":{"type":"string","enum":["block","alert"],"nullable":true},"dailySpendCap":{"type":"number","minimum":0,"nullable":true},"maxConcurrentCalls":{"type":"integer","minimum":0,"nullable":true},"maxCps":{"type":"integer","minimum":0,"nullable":true},"blockedPrefixes":{"type":"array","items":{"type":"string","pattern":"^[0-9]+$","maxLength":24},"maxItems":200},"portalEmail":{"type":"string","format":"email","maxLength":255,"nullable":true},"taxCountry":{"type":"string","maxLength":2,"nullable":true},"taxId":{"type":"string","maxLength":64,"nullable":true}},"required":["label"]}}}},"x-px-example":{"path":{},"query":{},"body":{"label":"Acme"}}}},"/api/v1/switch/customers/{id}/overview":{"get":{"operationId":"getSwitchCustomersByIdOverview","tags":["Switch: customers"],"summary":"Get a Switch customer command-centre overview","description":"KPIs, live traffic, quality, activity, setup state and data freshness in one read.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchCustomerOverview"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/customers/{id}":{"get":{"operationId":"getSwitchCustomersById","tags":["Switch: customers"],"summary":"Get a Switch customer","description":"Includes customer-level IP allow-list entries in `ipAcls`. The SIP password is never returned here; see the credentials endpoint.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"label":{"type":"string"},"source":{"type":"string","enum":["marketplace","external"]},"status":{"type":"string","enum":["draft","active","suspended","closed"]},"externalRef":{"type":"string","nullable":true},"balance":{"allOf":[{"$ref":"#/components/schemas/Money"}],"description":"Prepaid wallet balance (negative = owed), 6-decimal USD string"},"creditLimit":{"type":"string","description":"USD decimal string as stored (2 decimal places), e.g. \"5000.00\""},"currency":{"type":"string","nullable":true},"markupPct":{"type":"string","nullable":true,"description":"Default markup over cost, percent as a decimal string"},"billingIncrement":{"type":"string","nullable":true,"description":"e.g. \"60/60\" or \"6/6\""},"minMarginPct":{"type":"string","nullable":true},"marginFloorAction":{"type":"string","enum":["block","alert"],"nullable":true},"dailySpendCap":{"type":"string","nullable":true,"description":"USD decimal string as stored (2 decimal places), e.g. \"5000.00\""},"maxConcurrentCalls":{"type":"integer","nullable":true},"maxCps":{"type":"integer","nullable":true},"blockedPrefixes":{"type":"array","items":{"type":"string"},"nullable":true},"sipUsername":{"type":"string","nullable":true},"sipPasswordSet":{"type":"boolean","description":"Whether an inbound SIP password is set. The value itself is only ever returned by the audited credentials endpoint."},"portalEmail":{"type":"string","nullable":true},"taxCountry":{"type":"string","nullable":true},"taxId":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"ipAcls":{"type":"array","items":{"type":"object","additionalProperties":{}}}},"required":["id","label","source","status","externalRef","balance","creditLimit","currency","markupPct","billingIncrement","minMarginPct","marginFloorAction","dailySpendCap","maxConcurrentCalls","maxCps","blockedPrefixes","sipUsername","sipPasswordSet","portalEmail","taxCountry","taxId","createdAt","updatedAt","ipAcls"],"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}},"patch":{"operationId":"patchSwitchCustomersById","tags":["Switch: customers"],"summary":"Update a Switch customer","description":"Any field from create, all optional. A `status` change is applied as the matching lifecycle action, with the same guards and history entry as POST /lifecycle. Send `X-If-Unchanged-Since: <updatedAt you loaded>` to have the save refused with 409 STALE_WRITE if someone changed the record since.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchCustomer"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":160},"source":{"type":"string","enum":["marketplace","external"]},"status":{"type":"string","enum":["draft","active","suspended","closed"]},"externalRef":{"type":"string","maxLength":255,"nullable":true},"creditLimit":{"type":"number","minimum":0,"nullable":true},"markupPct":{"type":"number","minimum":0,"maximum":100000,"nullable":true},"billingIncrement":{"type":"string","maxLength":10,"nullable":true},"currency":{"type":"string","minLength":3,"maxLength":3,"nullable":true},"minMarginPct":{"type":"number","minimum":0,"maximum":100000,"nullable":true},"marginFloorAction":{"type":"string","enum":["block","alert"],"nullable":true},"dailySpendCap":{"type":"number","minimum":0,"nullable":true},"maxConcurrentCalls":{"type":"integer","minimum":0,"nullable":true},"maxCps":{"type":"integer","minimum":0,"nullable":true},"blockedPrefixes":{"type":"array","items":{"type":"string","pattern":"^[0-9]+$","maxLength":24},"maxItems":200},"portalEmail":{"type":"string","format":"email","maxLength":255,"nullable":true},"taxCountry":{"type":"string","maxLength":2,"nullable":true},"taxId":{"type":"string","maxLength":64,"nullable":true},"statusReason":{"type":"string","maxLength":2000,"nullable":true}}}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"label":"Acme","source":"marketplace"}}},"delete":{"operationId":"deleteSwitchCustomersById","tags":["Switch: customers"],"summary":"Delete a draft Switch customer","description":"Only for a customer that never carried traffic or held financial records. Offboard a real customer with the close lifecycle action instead.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"deleted":{"type":"boolean","enum":[true]},"id":{"type":"string","format":"uuid"},"label":{"type":"string"}},"required":["deleted","id","label"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/customers/{id}/lifecycle":{"get":{"operationId":"getSwitchCustomersByIdLifecycle","tags":["Switch: customers"],"summary":"Get a Switch customer lifecycle state and financial position","description":"Which lifecycle actions are available now, live calls, trunk counts, recent history and the money position a close or suspend would leave.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchCustomerLifecycle"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}},"post":{"operationId":"postSwitchCustomersByIdLifecycle","tags":["Switch: customers"],"summary":"Activate, suspend, reactivate, close or reopen a Switch customer","description":"The one write path for a customer's state. Live calls keep talking unless `disconnectLiveCalls` is true. Send `X-If-Unchanged-Since: <updatedAt you loaded>` to have the save refused with 409 STALE_WRITE if someone changed the record since.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"label":{"type":"string"},"status":{"type":"string","enum":["draft","active","suspended","closed"]},"previousStatus":{"type":"string","enum":["draft","active","suspended","closed"]},"action":{"type":"string"},"liveCallsAtChange":{"type":"integer"},"disconnectedLiveCalls":{"type":"boolean"},"disconnectIncomplete":{"type":"boolean"},"apiKeysRevoked":{"type":"integer"},"financialsUnchanged":{"type":"boolean","enum":[true]}},"required":["id","label","status","previousStatus","action","liveCallsAtChange","disconnectedLiveCalls","financialsUnchanged"],"additionalProperties":true}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","enum":["activate","suspend","reactivate","close","reopen"]},"reason":{"type":"string","maxLength":2000,"nullable":true},"disconnectLiveCalls":{"type":"boolean"}},"required":["action"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"action":"activate"}}}},"/api/v1/switch/customers/{id}/history":{"get":{"operationId":"getSwitchCustomersByIdHistory","tags":["Switch: customers"],"summary":"List a Switch customer lifecycle history","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/SwitchCustomerLifecycleEntry"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","required":false,"description":"Default 50","schema":{"type":"integer","minimum":1,"maximum":200}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/customers/{id}/sip-password":{"post":{"operationId":"postSwitchCustomersByIdSipPassword","tags":["Switch: customers"],"summary":"Rotate a Switch customer inbound SIP password","description":"Generates a new password and returns it ONCE. The old password stops working immediately.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchCustomerSipCredentials"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/customers/{id}/credentials":{"get":{"operationId":"getSwitchCustomersByIdCredentials","tags":["Switch: customers"],"summary":"Reveal a Switch customer inbound SIP credentials","description":"Returns the current username and password without changing them. Every reveal is recorded in the audit log.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchCustomerSipCredentials"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/customer-trunks/{trunkId}/credentials":{"get":{"operationId":"getSwitchCustomerTrunksByTrunkIdCredentials","tags":["Switch: customer trunks"],"summary":"Reveal a Switch customer trunk's SIP credentials","description":"Returns the current username and password without changing them. Every reveal is recorded in the audit log.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchCustomerSipCredentials"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"trunkId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"trunkId":"<trunkId>"},"query":{}}}},"/api/v1/switch/customer-trunks/{trunkId}/credential-status":{"get":{"operationId":"getSwitchCustomerTrunksByTrunkIdCredentialStatus","tags":["Switch: customer trunks"],"summary":"Get a trunk's credential history and last successful authentication","description":"Everything about the credential except its value: username, storage, last change and reveal, and the last call identified with it.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchTrunkCredentialStatus"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"trunkId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"trunkId":"<trunkId>"},"query":{}}}},"/api/v1/switch/customer-trunks/{trunkId}/credentials/copied":{"post":{"operationId":"postSwitchCustomerTrunksByTrunkIdCredentialsCopied","tags":["Switch: customer trunks"],"summary":"Record that a trunk credential was copied","description":"Writes an audit entry only. Call it when your interface copies a credential to the clipboard.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"202":{"$ref":"#/components/responses/ApprovalRequired"},"204":{"description":"Recorded."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"trunkId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"field":{"type":"string","enum":["sipPassword","sipUsername"],"default":"sipPassword"}}}}}},"x-px-example":{"path":{"trunkId":"<trunkId>"},"query":{},"body":{"field":"sipPassword"}}}},"/api/v1/switch/customer-trunks/{trunkId}/sip-password":{"post":{"operationId":"postSwitchCustomerTrunksByTrunkIdSipPassword","tags":["Switch: customer trunks"],"summary":"Replace a Switch customer trunk's SIP password","description":"Generate one, or set one by hand with `mode: \"manual\"`. The new password is returned ONCE and the old one stops working immediately (no overlap window).\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"trunkId":{"type":"string","format":"uuid"},"username":{"type":"string","nullable":true},"password":{"type":"string","description":"The new password in plain text. Returned ONCE, here."},"mode":{"type":"string","enum":["generate","manual"]},"changedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"overlapWindow":{"enum":["null"],"nullable":true,"description":"There is no grace period: the old password stops working immediately"},"note":{"type":"string"}},"required":["trunkId","username","password","mode","changedAt","overlapWindow","note"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"trunkId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"mode":{"type":"string","enum":["generate","manual"],"default":"generate"},"password":{"type":"string","maxLength":128,"description":"Required when mode is manual"}}}}}},"x-px-example":{"path":{"trunkId":"<trunkId>"},"query":{},"body":{"mode":"generate","password":"correct-horse-battery-staple"}}}},"/api/v1/switch/customers/{id}/attention":{"get":{"operationId":"getSwitchCustomersByIdAttention","tags":["Switch: customers"],"summary":"List what needs attention on a Switch customer","description":"A compact projection of the customer's open operational issues: quality, margin, credit and setup problems.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/SwitchCustomerAttentionItem"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/customers/{id}/issues":{"get":{"operationId":"getSwitchCustomersByIdIssues","tags":["Switch: customers"],"summary":"List operational issues on a Switch customer","description":"The full issue records behind the attention feed, with trigger, recovery rule, evidence and ownership.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/SwitchCustomerIssue"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/customers/{id}/contacts":{"get":{"operationId":"getSwitchCustomersByIdContacts","tags":["Switch: customers"],"summary":"List a Switch customer contacts","description":"Ordered by role, then priority. A contact is a person to reach, never a login.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/SwitchCustomerContact"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}},"post":{"operationId":"postSwitchCustomersByIdContacts","tags":["Switch: customers"],"summary":"Add a Switch customer contact","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchCustomerContact"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"role":{"type":"string","enum":["technical","noc","billing","escalation","commercial"]},"email":{"type":"string","format":"email","maxLength":255,"nullable":true},"phone":{"type":"string","maxLength":48,"nullable":true},"priority":{"type":"integer","minimum":1,"maximum":99},"isPrimary":{"type":"boolean"},"preferredMethod":{"type":"string","enum":["email","phone","either"]},"availability":{"type":"string","enum":["24x7","business_hours","on_call"],"nullable":true},"timezone":{"type":"string","maxLength":64,"nullable":true},"notes":{"type":"string","maxLength":2000,"nullable":true}},"required":["name","role"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"name":"Acme","role":"technical"}}}},"/api/v1/switch/customers/{id}/contacts/{contactId}":{"patch":{"operationId":"patchSwitchCustomersByIdContactsByContactId","tags":["Switch: customers"],"summary":"Update a Switch customer contact","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchCustomerContact"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"contactId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"role":{"type":"string","enum":["technical","noc","billing","escalation","commercial"]},"email":{"type":"string","format":"email","maxLength":255,"nullable":true},"phone":{"type":"string","maxLength":48,"nullable":true},"priority":{"type":"integer","minimum":1,"maximum":99},"isPrimary":{"type":"boolean"},"preferredMethod":{"type":"string","enum":["email","phone","either"]},"availability":{"type":"string","enum":["24x7","business_hours","on_call"],"nullable":true},"timezone":{"type":"string","maxLength":64,"nullable":true},"notes":{"type":"string","maxLength":2000,"nullable":true}}}}}},"x-px-example":{"path":{"id":"<id>","contactId":"<contactId>"},"query":{},"body":{"name":"Acme","role":"technical"}}},"delete":{"operationId":"deleteSwitchCustomersByIdContactsByContactId","tags":["Switch: customers"],"summary":"Delete a Switch customer contact","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"deleted":{"type":"boolean","enum":[true]}},"required":["deleted"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"contactId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>","contactId":"<contactId>"},"query":{}}}},"/api/v1/switch/customers/{id}/notes":{"get":{"operationId":"getSwitchCustomersByIdNotes","tags":["Switch: customers"],"summary":"List internal notes on a Switch customer","description":"Operator-private notes with the author name. Never visible to the customer.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"subAccountId":{"type":"string","format":"uuid"},"body":{"type":"string"},"type":{"type":"string","enum":["general","technical","billing","warning"]},"pinned":{"type":"boolean"},"followUpAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"createdBy":{"type":"string","format":"uuid","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"authorName":{"type":"string","nullable":true}},"required":["id","subAccountId","body","type","pinned","followUpAt","createdBy","createdAt","updatedAt","authorName"],"additionalProperties":true}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}},"post":{"operationId":"postSwitchCustomersByIdNotes","tags":["Switch: customers"],"summary":"Add an internal note to a Switch customer","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchCustomerNote"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"body":{"type":"string","minLength":1,"maxLength":4000},"type":{"type":"string","enum":["general","technical","billing","warning"]},"pinned":{"type":"boolean"},"followUpAt":{"type":"string","format":"date-time","nullable":true}},"required":["body"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"body":"Hello from Acme"}}}},"/api/v1/switch/customers/{id}/notes/{noteId}":{"patch":{"operationId":"patchSwitchCustomersByIdNotesByNoteId","tags":["Switch: customers"],"summary":"Edit, pin or flag a Switch customer note","description":"The author and creation time never change.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchCustomerNote"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"noteId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"body":{"type":"string","minLength":1,"maxLength":4000},"type":{"type":"string","enum":["general","technical","billing","warning"]},"pinned":{"type":"boolean"},"followUpAt":{"type":"string","format":"date-time","nullable":true}}}}}},"x-px-example":{"path":{"id":"<id>","noteId":"<noteId>"},"query":{},"body":{"body":"Hello from Acme","type":"general"}}},"delete":{"operationId":"deleteSwitchCustomersByIdNotesByNoteId","tags":["Switch: customers"],"summary":"Delete a Switch customer note","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"deleted":{"type":"boolean","enum":[true]}},"required":["deleted"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"noteId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>","noteId":"<noteId>"},"query":{}}}},"/api/v1/switch/customers/{id}/quality":{"get":{"operationId":"getSwitchCustomersByIdQuality","tags":["Switch: customers"],"summary":"Get per-destination quality for a Switch customer","description":"ASR, NER and PDD per destination over a window, with verdicts. The KPI row and the table are both computed from the same filtered set.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchCustomerQuality"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"window","in":"query","required":false,"description":"Hours: 1, 24 or 168. Default 24","schema":{"type":"integer"}},{"name":"from","in":"query","required":false,"description":"Explicit window start (ISO-8601); overrides `window`","schema":{"type":"string"}},{"name":"to","in":"query","required":false,"description":"Explicit window end (ISO-8601)","schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/customers/{id}/quality/destination":{"get":{"operationId":"getSwitchCustomersByIdQualityDestination","tags":["Switch: customers"],"summary":"Drill into one destination for a Switch customer","description":"Which customer trunks sent it, which supplier trunks carried it, which route groups send it there, and how far the sessions got. Uses the same window and filters as the quality table.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"windowHours":{"type":"number"},"window":{"type":"object","properties":{"from":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"to":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"label":{"type":"string"}},"required":["from","to","label"]},"destinationDigits":{"type":"integer"}},"required":["windowHours","window","destinationDigits"],"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"window","in":"query","required":false,"description":"Hours: 1, 24 or 168. Default 24","schema":{"type":"integer"}},{"name":"from","in":"query","required":false,"description":"Explicit window start (ISO-8601); overrides `window`","schema":{"type":"string"}},{"name":"to","in":"query","required":false,"description":"Explicit window end (ISO-8601)","schema":{"type":"string"}},{"name":"prefix","in":"query","required":true,"description":"The destination prefix to open","schema":{"type":"string","minLength":1,"maxLength":24}}],"x-px-example":{"path":{"id":"<id>"},"query":{"prefix":"44"}}}},"/api/v1/switch/customers/{id}/billing-summary":{"get":{"operationId":"getSwitchCustomersByIdBillingSummary","tags":["Switch: customers"],"summary":"Get a Switch customer receivables summary","description":"What is owed, unbilled and unrated, payments recorded and ageing. Credit headroom is a separate endpoint (credit-position).\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchCustomerBillingSummary"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/customers/{id}/credit-position":{"get":{"operationId":"getSwitchCustomersByIdCreditPosition","tags":["Switch: customers"],"summary":"Get a Switch customer credit position","description":"Credit limit, exposure, funds reserved by live calls, available credit and whether the next call would be admitted. Read-only; it reports the admission arithmetic without performing it.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchCustomerCreditPosition"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/customers/{id}/payments/preview":{"get":{"operationId":"getSwitchCustomersByIdPaymentsPreview","tags":["Switch: customers"],"summary":"Preview how a payment would be allocated to invoices","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"billingMode":{"type":"string"},"currency":{"type":"string"},"wouldAllocate":{"type":"array","items":{"type":"object","properties":{"invoiceId":{"type":"string","format":"uuid"},"invoiceNumber":{"type":"string"},"applied":{"type":"number","description":"US dollars as a JSON number (computed figure)"},"clearsInvoice":{"type":"boolean"}},"required":["invoiceId","invoiceNumber","applied","clearsInvoice"]}},"wouldLeaveUnapplied":{"type":"number","description":"US dollars as a JSON number (computed figure)"}},"required":["billingMode","currency","wouldAllocate","wouldLeaveUnapplied"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"amount","in":"query","required":false,"description":"USD amount to preview","schema":{"type":"number"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/customers/{id}/payments":{"post":{"operationId":"postSwitchCustomersByIdPayments","tags":["Switch: customers"],"summary":"Record a payment received from a Switch customer","description":"Records money the customer already paid you (nothing is collected). It credits the wallet and pays open invoices oldest-due first in one transaction; anything left is held unapplied.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Idempotency:** send an `X-Idempotency-Key` header to make retries safe; a replay within 24 hours returns the original response.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchCustomerPayment"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"x-idempotent":true,"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"X-Idempotency-Key","in":"header","required":false,"description":"Any unique string (a UUID is ideal). Replays within 24 hours return the first response instead of acting twice.","schema":{"type":"string","maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"amount":{"type":"number","exclusiveMinimum":true,"minimum":0,"description":"USD"},"reference":{"type":"string","maxLength":160,"nullable":true,"description":"Bank or remittance reference, for matching later"},"method":{"type":"string","maxLength":32,"nullable":true},"paidAt":{"type":"string","nullable":true,"description":"When the money was received (ISO-8601); default now"}},"required":["amount"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"amount":1}},"x-px-billable":{"kind":"money","note":"Records or reverses a payment on a Switch customer ledger."}}},"/api/v1/switch/customers/{id}/payments/{transactionId}/reverse":{"post":{"operationId":"postSwitchCustomersByIdPaymentsByTransactionIdReverse","tags":["Switch: customers"],"summary":"Reverse a recorded Switch customer payment","description":"A posted payment is never edited or deleted. This posts a linked reversal and unwinds its invoice allocations; both entries stay on the record.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"kind":{"type":"string","enum":["reversal"]},"reversesTransactionId":{"type":"string","format":"uuid"},"transactionId":{"type":"string","format":"uuid"},"amount":{"type":"number","description":"US dollars as a JSON number (computed figure)"},"currency":{"type":"string"},"reason":{"type":"string"},"unwound":{"type":"array","items":{"type":"object","additionalProperties":{}}},"positionAfter":{"type":"object","additionalProperties":{}}},"required":["kind","reversesTransactionId","transactionId","amount","currency","reason","unwound","positionAfter"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"transactionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","minLength":1,"maxLength":500}},"required":["reason"]}}}},"x-px-example":{"path":{"id":"<id>","transactionId":"<transactionId>"},"query":{},"body":{"reason":"Example"}},"x-px-billable":{"kind":"money","note":"Records or reverses a payment on a Switch customer ledger."}}},"/api/v1/switch/customers/{id}/invoice-preview":{"post":{"operationId":"postSwitchCustomersByIdInvoicePreview","tags":["Switch: customers"],"summary":"Preview an invoice for a Switch customer unbilled period","description":"The period runs from the last invoice's end (or the customer's creation) to now. Issues nothing; returns a `reviewToken` for generate-invoice.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchCustomerInvoicePreview"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"notes":{"type":"string","maxLength":2000,"nullable":true},"includeBroughtForward":{"type":"boolean"},"applyCredits":{"type":"boolean"},"excludeUnrated":{"type":"object","properties":{"reason":{"type":"string","minLength":8,"maxLength":2000}},"required":["reason"],"nullable":true,"description":"Issue despite unrated usage in the period, with the reason recorded on the invoice"}}}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"notes":"Example","includeBroughtForward":true}}}},"/api/v1/switch/customers/{id}/generate-invoice":{"post":{"operationId":"postSwitchCustomersByIdGenerateInvoice","tags":["Switch: customers"],"summary":"Issue the reviewed invoice for a Switch customer","description":"Requires the `reviewToken` from invoice-preview; refused with 409 INVOICE_REVIEW_STALE if the data changed since, or INVOICE_UNRATED_USAGE if unrated usage remains and was not excluded.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchCustomerIssuedInvoice"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["INVOICE_REVIEW_STALE","INVOICE_UNRATED_USAGE","STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"notes":{"type":"string","maxLength":2000,"nullable":true},"includeBroughtForward":{"type":"boolean"},"applyCredits":{"type":"boolean"},"excludeUnrated":{"type":"object","properties":{"reason":{"type":"string","minLength":8,"maxLength":2000}},"required":["reason"],"nullable":true,"description":"Issue despite unrated usage in the period, with the reason recorded on the invoice"},"reviewToken":{"type":"string","minLength":8,"maxLength":120}},"required":["reviewToken"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"reviewToken":"<reviewToken>"}}}},"/api/v1/switch/customers/{id}/billing-profile":{"get":{"operationId":"getSwitchCustomersByIdBillingProfile","tags":["Switch: customers"],"summary":"Get a Switch customer billing profile","description":"`profile` is what was entered (null if none); `resolved` is what an invoice issued now would freeze, including fallbacks.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"profile":{"allOf":[{"$ref":"#/components/schemas/SwitchCustomerBillingProfile"}],"nullable":true},"resolved":{"type":"object","properties":{"source":{"type":"string","enum":["profile","fallback"]},"profileId":{"type":"string","format":"uuid","nullable":true},"profileVersion":{"type":"integer","nullable":true},"customer":{"type":"object","additionalProperties":{}},"billingAddress":{"type":"object","additionalProperties":{},"nullable":true},"issuer":{"type":"object","additionalProperties":{}},"terms":{"type":"object","properties":{"currency":{"type":"string"},"billingCycle":{"type":"string","nullable":true},"billingTimezone":{"type":"string"},"paymentTermsDays":{"type":"integer"},"purchaseOrderRef":{"type":"string","nullable":true},"paymentInstructions":{"type":"string","nullable":true}},"required":["currency","billingCycle","billingTimezone","paymentTermsDays","purchaseOrderRef","paymentInstructions"]},"recipients":{}},"required":["source","profileId","profileVersion","customer","billingAddress","issuer","terms"],"additionalProperties":true}},"required":["profile","resolved"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}},"put":{"operationId":"putSwitchCustomersByIdBillingProfile","tags":["Switch: customers"],"summary":"Save a Switch customer billing profile","description":"The customer's legal and billing identity. Frozen onto invoices issued afterwards; never changes an invoice already issued. Send `X-If-Unchanged-Since: <updatedAt you loaded>` to have the save refused with 409 STALE_WRITE if someone changed the record since.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchCustomerBillingProfile"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"legalName":{"type":"string","minLength":1,"maxLength":200},"tradingName":{"type":"string","maxLength":200,"nullable":true},"registrationNumber":{"type":"string","maxLength":64,"nullable":true},"addressLine1":{"type":"string","maxLength":200,"nullable":true},"addressLine2":{"type":"string","maxLength":200,"nullable":true},"city":{"type":"string","maxLength":120,"nullable":true},"region":{"type":"string","maxLength":120,"nullable":true},"postcode":{"type":"string","maxLength":32,"nullable":true},"country":{"type":"string","minLength":2,"maxLength":2,"nullable":true},"billingAddressLine1":{"type":"string","maxLength":200,"nullable":true},"billingAddressLine2":{"type":"string","maxLength":200,"nullable":true},"billingCity":{"type":"string","maxLength":120,"nullable":true},"billingRegion":{"type":"string","maxLength":120,"nullable":true},"billingPostcode":{"type":"string","maxLength":32,"nullable":true},"billingCountry":{"type":"string","minLength":2,"maxLength":2,"nullable":true},"taxCountry":{"type":"string","minLength":2,"maxLength":2,"nullable":true},"taxId":{"type":"string","maxLength":64,"nullable":true},"taxTreatment":{"type":"string","enum":["standard","reverse_charge","zero_rated","exempt"],"nullable":true},"invoiceCurrency":{"type":"string","minLength":3,"maxLength":3},"billingCycle":{"type":"string","enum":["weekly","biweekly","monthly","manual"],"nullable":true},"billingTimezone":{"type":"string","maxLength":64},"paymentTermsDays":{"type":"integer","minimum":0,"maximum":365,"nullable":true},"purchaseOrderRef":{"type":"string","maxLength":64,"nullable":true},"invoiceRecipients":{"type":"array","items":{"type":"string","format":"email"},"maxItems":20}}}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"legalName":"<legalName>","tradingName":"<tradingName>"}}}},"/api/v1/switch/providers":{"get":{"operationId":"getSwitchProviders","tags":["Switch: suppliers"],"summary":"List providers with their trunks","description":"Every provider on your switch, each with its trunks (secrets redacted) and endpoint counts, plus trunks not yet assigned to a provider.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchProviderList"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}},"post":{"operationId":"postSwitchProviders","tags":["Switch: suppliers"],"summary":"Create a provider","description":"A provider is the carrier or company that owns one or more supplier trunks.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchProvider"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":160},"accountCode":{"type":"string","maxLength":40,"nullable":true},"legalName":{"type":"string","maxLength":200,"nullable":true},"tradingName":{"type":"string","maxLength":200,"nullable":true},"providerType":{"type":"string","enum":["carrier","aggregator","mno","mvno","sip_provider"],"nullable":true},"registrationNumber":{"type":"string","maxLength":80,"nullable":true},"taxId":{"type":"string","maxLength":80,"nullable":true},"vatId":{"type":"string","maxLength":80,"nullable":true},"address":{"type":"string","maxLength":600,"nullable":true},"country":{"type":"string","maxLength":2,"nullable":true},"accountManager":{"type":"string","maxLength":160,"nullable":true},"tags":{"type":"array","items":{"type":"string","maxLength":40},"maxItems":20,"nullable":true},"services":{"type":"array","items":{"type":"string","enum":["termination","origination","did","sms"]},"nullable":true},"portalEmail":{"type":"string","format":"email","maxLength":255,"nullable":true},"notes":{"type":"string","maxLength":4000,"nullable":true},"currency":{"type":"string","minLength":3,"maxLength":3,"nullable":true},"status":{"type":"string","enum":["draft","pending_approval","testing","active","suspended","terminated"],"description":"Accepted on create only; later changes go through POST /{id}/status"},"contractStart":{"type":"string","maxLength":10,"nullable":true},"contractEnd":{"type":"string","maxLength":10,"nullable":true},"autoRenew":{"type":"boolean"},"rateNoticeDays":{"anyOf":[{"type":"number"},{"type":"string"}],"nullable":true},"disputeDays":{"anyOf":[{"type":"number"},{"type":"string"}],"nullable":true},"billingMode":{"type":"string","enum":["prepaid","postpaid"],"nullable":true},"creditLimit":{"anyOf":[{"type":"number"},{"type":"string"}],"nullable":true},"paymentTermsDays":{"anyOf":[{"type":"number"},{"type":"string"}],"nullable":true},"invoiceCycle":{"type":"string","enum":["weekly","biweekly","monthly"],"nullable":true},"billingTimezone":{"type":"string","maxLength":64,"nullable":true}},"required":["name"]}}}},"x-px-example":{"path":{},"query":{},"body":{"name":"Acme"}}}},"/api/v1/switch/providers/{id}":{"get":{"operationId":"getSwitchProvidersById","tags":["Switch: suppliers"],"summary":"Get a provider with its trunks, endpoints and contacts","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchProviderDetail"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}},"patch":{"operationId":"patchSwitchProvidersById","tags":["Switch: suppliers"],"summary":"Update a provider","description":"Partial update; status is changed through POST /{id}/status instead. Send `X-If-Unchanged-Since: <updatedAt you loaded>` to be refused with 409 STALE_WRITE if someone else saved in between.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchProvider"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":160},"accountCode":{"type":"string","maxLength":40,"nullable":true},"legalName":{"type":"string","maxLength":200,"nullable":true},"tradingName":{"type":"string","maxLength":200,"nullable":true},"providerType":{"type":"string","enum":["carrier","aggregator","mno","mvno","sip_provider"],"nullable":true},"registrationNumber":{"type":"string","maxLength":80,"nullable":true},"taxId":{"type":"string","maxLength":80,"nullable":true},"vatId":{"type":"string","maxLength":80,"nullable":true},"address":{"type":"string","maxLength":600,"nullable":true},"country":{"type":"string","maxLength":2,"nullable":true},"accountManager":{"type":"string","maxLength":160,"nullable":true},"tags":{"type":"array","items":{"type":"string","maxLength":40},"maxItems":20,"nullable":true},"services":{"type":"array","items":{"type":"string","enum":["termination","origination","did","sms"]},"nullable":true},"portalEmail":{"type":"string","format":"email","maxLength":255,"nullable":true},"notes":{"type":"string","maxLength":4000,"nullable":true},"currency":{"type":"string","minLength":3,"maxLength":3,"nullable":true},"status":{"type":"string","enum":["draft","pending_approval","testing","active","suspended","terminated"],"description":"Accepted on create only; later changes go through POST /{id}/status"},"contractStart":{"type":"string","maxLength":10,"nullable":true},"contractEnd":{"type":"string","maxLength":10,"nullable":true},"autoRenew":{"type":"boolean"},"rateNoticeDays":{"anyOf":[{"type":"number"},{"type":"string"}],"nullable":true},"disputeDays":{"anyOf":[{"type":"number"},{"type":"string"}],"nullable":true},"billingMode":{"type":"string","enum":["prepaid","postpaid"],"nullable":true},"creditLimit":{"anyOf":[{"type":"number"},{"type":"string"}],"nullable":true},"paymentTermsDays":{"anyOf":[{"type":"number"},{"type":"string"}],"nullable":true},"invoiceCycle":{"type":"string","enum":["weekly","biweekly","monthly"],"nullable":true},"billingTimezone":{"type":"string","maxLength":64,"nullable":true}}}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"name":"Acme","accountCode":"<accountCode>"}}},"delete":{"operationId":"deleteSwitchProvidersById","tags":["Switch: suppliers"],"summary":"Delete a provider","description":"Deletes the provider and its trunks in one transaction, with the same effect as deleting each trunk (route group entries that use them are removed; call records are kept). Refused with 409 CONFLICT while any of its trunks can still carry calls: disable them, or set the provider to suspended or terminated, first.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"deleted":{"type":"boolean","enum":[true]},"deletedTrunks":{"type":"integer"}},"required":["deleted","deletedTrunks"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE","CONFLICT"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/providers/{id}/status":{"post":{"operationId":"postSwitchProvidersByIdStatus","tags":["Switch: suppliers"],"summary":"Change a provider lifecycle status","description":"Stops or resumes traffic on every trunk of the provider. The response says whether traffic changed and how many active trunks were affected.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"accountCode":{"type":"string","nullable":true},"legalName":{"type":"string","nullable":true},"tradingName":{"type":"string","nullable":true},"providerType":{"type":"string","enum":["carrier","aggregator","mno","mvno","sip_provider"],"nullable":true},"country":{"type":"string","nullable":true},"services":{"type":"array","items":{"type":"string"},"nullable":true},"portalEmail":{"type":"string","nullable":true},"currency":{"type":"string"},"status":{"type":"string","enum":["draft","pending_approval","testing","active","suspended","terminated"]},"statusNote":{"type":"string","nullable":true},"statusChangedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"routable":{"type":"boolean","description":"Whether this provider admits new calls at all, given its status"},"contractStart":{"type":"string","nullable":true,"description":"YYYY-MM-DD"},"contractEnd":{"type":"string","nullable":true},"autoRenew":{"type":"boolean"},"rateNoticeDays":{"type":"integer","nullable":true},"disputeDays":{"type":"integer","nullable":true},"billingMode":{"type":"string","enum":["prepaid","postpaid"]},"creditLimit":{"type":"string","nullable":true,"description":"Decimal string with 2 decimal places, e.g. \"5000.00\""},"balance":{"$ref":"#/components/schemas/Money"},"paymentTermsDays":{"type":"integer","nullable":true},"invoiceCycle":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"trafficChange":{"type":"string","enum":["none","resumed","stopped"]},"affectedTrunks":{"type":"integer"}},"required":["id","name","accountCode","legalName","tradingName","providerType","country","services","portalEmail","currency","status","statusNote","statusChangedAt","routable","contractStart","contractEnd","autoRenew","rateNoticeDays","disputeDays","billingMode","creditLimit","balance","paymentTermsDays","invoiceCycle","createdAt","updatedAt","trafficChange","affectedTrunks"],"additionalProperties":true}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["draft","pending_approval","testing","active","suspended","terminated"]},"note":{"type":"string","maxLength":1000,"nullable":true}},"required":["status"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"status":"draft"}}}},"/api/v1/switch/providers/{id}/contacts":{"get":{"operationId":"getSwitchProvidersByIdContacts","tags":["Switch: suppliers"],"summary":"List a provider contacts","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/SwitchProviderContact"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}},"post":{"operationId":"postSwitchProvidersByIdContacts","tags":["Switch: suppliers"],"summary":"Add a provider contact","description":"One contact per role (NOC, rates, billing, finance, fraud, account, emergency).\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchProviderContact"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"role":{"type":"string","enum":["noc","rates","billing","finance","fraud","account","emergency"]},"name":{"type":"string","maxLength":160,"nullable":true},"email":{"type":"string","maxLength":255,"nullable":true},"phone":{"type":"string","maxLength":40,"nullable":true},"timezone":{"type":"string","maxLength":64,"nullable":true},"notify":{"type":"boolean"},"notes":{"type":"string","maxLength":1000,"nullable":true}},"required":["role"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"role":"noc"}}}},"/api/v1/switch/providers/{id}/contacts/{contactId}":{"patch":{"operationId":"patchSwitchProvidersByIdContactsByContactId","tags":["Switch: suppliers"],"summary":"Update a provider contact","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchProviderContact"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"contactId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"role":{"type":"string","enum":["noc","rates","billing","finance","fraud","account","emergency"]},"name":{"type":"string","maxLength":160,"nullable":true},"email":{"type":"string","maxLength":255,"nullable":true},"phone":{"type":"string","maxLength":40,"nullable":true},"timezone":{"type":"string","maxLength":64,"nullable":true},"notify":{"type":"boolean"},"notes":{"type":"string","maxLength":1000,"nullable":true}}}}}},"x-px-example":{"path":{"id":"<id>","contactId":"<contactId>"},"query":{},"body":{"role":"noc","name":"Acme"}}},"delete":{"operationId":"deleteSwitchProvidersByIdContactsByContactId","tags":["Switch: suppliers"],"summary":"Delete a provider contact","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"deleted":{"type":"boolean","enum":[true]}},"required":["deleted"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"contactId","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>","contactId":"<contactId>"},"query":{}}}},"/api/v1/switch/supplier-accounts":{"get":{"operationId":"getSwitchSupplierAccounts","tags":["Switch: suppliers"],"summary":"List providers with their trunks","description":"Every provider on your switch, each with its trunks (secrets redacted) and endpoint counts, plus trunks not yet assigned to a provider. Deprecated alias of the same operation under /switch/providers.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","deprecated":true,"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchProviderList"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}},"post":{"operationId":"postSwitchSupplierAccounts","tags":["Switch: suppliers"],"summary":"Create a provider","description":"A provider is the carrier or company that owns one or more supplier trunks. Deprecated alias of the same operation under /switch/providers.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","deprecated":true,"responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchProvider"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":160},"accountCode":{"type":"string","maxLength":40,"nullable":true},"legalName":{"type":"string","maxLength":200,"nullable":true},"tradingName":{"type":"string","maxLength":200,"nullable":true},"providerType":{"type":"string","enum":["carrier","aggregator","mno","mvno","sip_provider"],"nullable":true},"registrationNumber":{"type":"string","maxLength":80,"nullable":true},"taxId":{"type":"string","maxLength":80,"nullable":true},"vatId":{"type":"string","maxLength":80,"nullable":true},"address":{"type":"string","maxLength":600,"nullable":true},"country":{"type":"string","maxLength":2,"nullable":true},"accountManager":{"type":"string","maxLength":160,"nullable":true},"tags":{"type":"array","items":{"type":"string","maxLength":40},"maxItems":20,"nullable":true},"services":{"type":"array","items":{"type":"string","enum":["termination","origination","did","sms"]},"nullable":true},"portalEmail":{"type":"string","format":"email","maxLength":255,"nullable":true},"notes":{"type":"string","maxLength":4000,"nullable":true},"currency":{"type":"string","minLength":3,"maxLength":3,"nullable":true},"status":{"type":"string","enum":["draft","pending_approval","testing","active","suspended","terminated"],"description":"Accepted on create only; later changes go through POST /{id}/status"},"contractStart":{"type":"string","maxLength":10,"nullable":true},"contractEnd":{"type":"string","maxLength":10,"nullable":true},"autoRenew":{"type":"boolean"},"rateNoticeDays":{"anyOf":[{"type":"number"},{"type":"string"}],"nullable":true},"disputeDays":{"anyOf":[{"type":"number"},{"type":"string"}],"nullable":true},"billingMode":{"type":"string","enum":["prepaid","postpaid"],"nullable":true},"creditLimit":{"anyOf":[{"type":"number"},{"type":"string"}],"nullable":true},"paymentTermsDays":{"anyOf":[{"type":"number"},{"type":"string"}],"nullable":true},"invoiceCycle":{"type":"string","enum":["weekly","biweekly","monthly"],"nullable":true},"billingTimezone":{"type":"string","maxLength":64,"nullable":true}},"required":["name"]}}}},"x-px-example":{"path":{},"query":{},"body":{"name":"Acme"}}}},"/api/v1/switch/supplier-accounts/{id}":{"get":{"operationId":"getSwitchSupplierAccountsById","tags":["Switch: suppliers"],"summary":"Get a provider with its trunks, endpoints and contacts","description":"Deprecated alias of the same operation under /switch/providers.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","deprecated":true,"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchProviderDetail"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}},"patch":{"operationId":"patchSwitchSupplierAccountsById","tags":["Switch: suppliers"],"summary":"Update a provider","description":"Partial update; status is changed through POST /{id}/status instead. Send `X-If-Unchanged-Since: <updatedAt you loaded>` to be refused with 409 STALE_WRITE if someone else saved in between. Deprecated alias of the same operation under /switch/providers.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","deprecated":true,"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchProvider"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":160},"accountCode":{"type":"string","maxLength":40,"nullable":true},"legalName":{"type":"string","maxLength":200,"nullable":true},"tradingName":{"type":"string","maxLength":200,"nullable":true},"providerType":{"type":"string","enum":["carrier","aggregator","mno","mvno","sip_provider"],"nullable":true},"registrationNumber":{"type":"string","maxLength":80,"nullable":true},"taxId":{"type":"string","maxLength":80,"nullable":true},"vatId":{"type":"string","maxLength":80,"nullable":true},"address":{"type":"string","maxLength":600,"nullable":true},"country":{"type":"string","maxLength":2,"nullable":true},"accountManager":{"type":"string","maxLength":160,"nullable":true},"tags":{"type":"array","items":{"type":"string","maxLength":40},"maxItems":20,"nullable":true},"services":{"type":"array","items":{"type":"string","enum":["termination","origination","did","sms"]},"nullable":true},"portalEmail":{"type":"string","format":"email","maxLength":255,"nullable":true},"notes":{"type":"string","maxLength":4000,"nullable":true},"currency":{"type":"string","minLength":3,"maxLength":3,"nullable":true},"status":{"type":"string","enum":["draft","pending_approval","testing","active","suspended","terminated"],"description":"Accepted on create only; later changes go through POST /{id}/status"},"contractStart":{"type":"string","maxLength":10,"nullable":true},"contractEnd":{"type":"string","maxLength":10,"nullable":true},"autoRenew":{"type":"boolean"},"rateNoticeDays":{"anyOf":[{"type":"number"},{"type":"string"}],"nullable":true},"disputeDays":{"anyOf":[{"type":"number"},{"type":"string"}],"nullable":true},"billingMode":{"type":"string","enum":["prepaid","postpaid"],"nullable":true},"creditLimit":{"anyOf":[{"type":"number"},{"type":"string"}],"nullable":true},"paymentTermsDays":{"anyOf":[{"type":"number"},{"type":"string"}],"nullable":true},"invoiceCycle":{"type":"string","enum":["weekly","biweekly","monthly"],"nullable":true},"billingTimezone":{"type":"string","maxLength":64,"nullable":true}}}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"name":"Acme","accountCode":"<accountCode>"}}},"delete":{"operationId":"deleteSwitchSupplierAccountsById","tags":["Switch: suppliers"],"summary":"Delete a provider","description":"Deletes the provider and its trunks in one transaction, with the same effect as deleting each trunk (route group entries that use them are removed; call records are kept). Refused with 409 CONFLICT while any of its trunks can still carry calls: disable them, or set the provider to suspended or terminated, first. Deprecated alias of the same operation under /switch/providers.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","deprecated":true,"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"deleted":{"type":"boolean","enum":[true]},"deletedTrunks":{"type":"integer"}},"required":["deleted","deletedTrunks"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE","CONFLICT"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/supplier-accounts/{id}/status":{"post":{"operationId":"postSwitchSupplierAccountsByIdStatus","tags":["Switch: suppliers"],"summary":"Change a provider lifecycle status","description":"Stops or resumes traffic on every trunk of the provider. The response says whether traffic changed and how many active trunks were affected. Deprecated alias of the same operation under /switch/providers.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","deprecated":true,"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"accountCode":{"type":"string","nullable":true},"legalName":{"type":"string","nullable":true},"tradingName":{"type":"string","nullable":true},"providerType":{"type":"string","enum":["carrier","aggregator","mno","mvno","sip_provider"],"nullable":true},"country":{"type":"string","nullable":true},"services":{"type":"array","items":{"type":"string"},"nullable":true},"portalEmail":{"type":"string","nullable":true},"currency":{"type":"string"},"status":{"type":"string","enum":["draft","pending_approval","testing","active","suspended","terminated"]},"statusNote":{"type":"string","nullable":true},"statusChangedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"routable":{"type":"boolean","description":"Whether this provider admits new calls at all, given its status"},"contractStart":{"type":"string","nullable":true,"description":"YYYY-MM-DD"},"contractEnd":{"type":"string","nullable":true},"autoRenew":{"type":"boolean"},"rateNoticeDays":{"type":"integer","nullable":true},"disputeDays":{"type":"integer","nullable":true},"billingMode":{"type":"string","enum":["prepaid","postpaid"]},"creditLimit":{"type":"string","nullable":true,"description":"Decimal string with 2 decimal places, e.g. \"5000.00\""},"balance":{"$ref":"#/components/schemas/Money"},"paymentTermsDays":{"type":"integer","nullable":true},"invoiceCycle":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"trafficChange":{"type":"string","enum":["none","resumed","stopped"]},"affectedTrunks":{"type":"integer"}},"required":["id","name","accountCode","legalName","tradingName","providerType","country","services","portalEmail","currency","status","statusNote","statusChangedAt","routable","contractStart","contractEnd","autoRenew","rateNoticeDays","disputeDays","billingMode","creditLimit","balance","paymentTermsDays","invoiceCycle","createdAt","updatedAt","trafficChange","affectedTrunks"],"additionalProperties":true}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["draft","pending_approval","testing","active","suspended","terminated"]},"note":{"type":"string","maxLength":1000,"nullable":true}},"required":["status"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"status":"draft"}}}},"/api/v1/switch/supplier-accounts/{id}/contacts":{"get":{"operationId":"getSwitchSupplierAccountsByIdContacts","tags":["Switch: suppliers"],"summary":"List a provider contacts","description":"Deprecated alias of the same operation under /switch/providers.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","deprecated":true,"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/SwitchProviderContact"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}},"post":{"operationId":"postSwitchSupplierAccountsByIdContacts","tags":["Switch: suppliers"],"summary":"Add a provider contact","description":"One contact per role (NOC, rates, billing, finance, fraud, account, emergency). Deprecated alias of the same operation under /switch/providers.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","deprecated":true,"responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchProviderContact"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"role":{"type":"string","enum":["noc","rates","billing","finance","fraud","account","emergency"]},"name":{"type":"string","maxLength":160,"nullable":true},"email":{"type":"string","maxLength":255,"nullable":true},"phone":{"type":"string","maxLength":40,"nullable":true},"timezone":{"type":"string","maxLength":64,"nullable":true},"notify":{"type":"boolean"},"notes":{"type":"string","maxLength":1000,"nullable":true}},"required":["role"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"role":"noc"}}}},"/api/v1/switch/supplier-accounts/{id}/contacts/{contactId}":{"patch":{"operationId":"patchSwitchSupplierAccountsByIdContactsByContactId","tags":["Switch: suppliers"],"summary":"Update a provider contact","description":"Deprecated alias of the same operation under /switch/providers.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","deprecated":true,"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchProviderContact"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"contactId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"role":{"type":"string","enum":["noc","rates","billing","finance","fraud","account","emergency"]},"name":{"type":"string","maxLength":160,"nullable":true},"email":{"type":"string","maxLength":255,"nullable":true},"phone":{"type":"string","maxLength":40,"nullable":true},"timezone":{"type":"string","maxLength":64,"nullable":true},"notify":{"type":"boolean"},"notes":{"type":"string","maxLength":1000,"nullable":true}}}}}},"x-px-example":{"path":{"id":"<id>","contactId":"<contactId>"},"query":{},"body":{"role":"noc","name":"Acme"}}},"delete":{"operationId":"deleteSwitchSupplierAccountsByIdContactsByContactId","tags":["Switch: suppliers"],"summary":"Delete a provider contact","description":"Deprecated alias of the same operation under /switch/providers.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","deprecated":true,"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"deleted":{"type":"boolean","enum":[true]}},"required":["deleted"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"contactId","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>","contactId":"<contactId>"},"query":{}}}},"/api/v1/switch/rate-decks":{"get":{"operationId":"getSwitchRateDecks","tags":["Switch: rating"],"summary":"List supplier rate decks","description":"Newest first, up to 500, with row counts and the supplier trunks each deck prices.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"decks":{"type":"array","items":{"$ref":"#/components/schemas/SwitchRateDeck"}}},"required":["decks"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"supplierId","in":"query","required":false,"description":"Only decks from this provider","schema":{"type":"string","format":"uuid"}},{"name":"trunkId","in":"query","required":false,"description":"Only decks that price this supplier trunk","schema":{"type":"string","format":"uuid"}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["draft","uploaded","invalid","validated","pending_approval","scheduled","active","expired","rolled_back"]}}],"x-px-example":{"path":{},"query":{}}},"post":{"operationId":"postSwitchRateDecks","tags":["Switch: rating"],"summary":"Create a supplier rate deck","description":"Creates a draft deck (version 1, or the next version of an existing name for that provider). Load rows with PUT /rate-decks/{id}/rows.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchRateDeck"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"supplierId":{"type":"string","format":"uuid","nullable":true},"name":{"type":"string","minLength":1,"maxLength":160},"currency":{"type":"string","minLength":3,"maxLength":3},"source":{"type":"string","enum":["portal","csv","api","email","sftp"],"nullable":true},"sourceRef":{"type":"string","maxLength":500,"nullable":true},"effectiveFrom":{"type":"string","maxLength":40,"nullable":true},"expiresAt":{"type":"string","maxLength":40,"nullable":true},"trunkIds":{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":200},"notes":{"type":"string","maxLength":4000,"nullable":true}},"required":["name"]}}}},"x-px-example":{"path":{},"query":{},"body":{"name":"Acme"}}}},"/api/v1/switch/rate-decks/{id}":{"get":{"operationId":"getSwitchRateDecksById","tags":["Switch: rating"],"summary":"Get a supplier rate deck","description":"The deck, its trunks and row count. Rows themselves are read from the supplier trunk rates.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchRateDeck"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}},"delete":{"operationId":"deleteSwitchRateDecksById","tags":["Switch: rating"],"summary":"Delete a rate deck","description":"Deletes the deck and its rows. An active deck must be rolled back first.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"deleted":{"type":"boolean","enum":[true]}},"required":["deleted"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/rate-decks/{id}/history":{"get":{"operationId":"getSwitchRateDecksByIdHistory","tags":["Switch: rating"],"summary":"List every version of a rate deck","description":"All versions sharing this deck's name and provider, newest first.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"name":{"type":"string"},"versions":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"supplierId":{"type":"string","format":"uuid","nullable":true,"description":"The provider who sent it; null for a deck recorded before its provider was"},"name":{"type":"string"},"currency":{"type":"string","minLength":3,"maxLength":3},"version":{"type":"integer"},"status":{"type":"string","enum":["draft","uploaded","invalid","validated","pending_approval","scheduled","active","expired","rolled_back"]},"effectiveFrom":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"expiresAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"source":{"type":"string","enum":["portal","csv","api","email","sftp"],"nullable":true},"sourceRef":{"type":"string","nullable":true},"approvedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"validation":{"type":"object","properties":{"checkedAt":{"type":"string"},"rows":{"type":"integer"},"destinations":{"type":"integer"},"errors":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true,"description":"One validation finding (code, message and the rows it concerns)"}},"warnings":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true,"description":"One validation finding (code, message and the rows it concerns)"}},"maxIncreasePct":{"type":"number"}},"required":["checkedAt","rows","destinations","errors","warnings"],"nullable":true,"description":"The last validation result; null before the deck is validated"},"supersedesId":{"type":"string","format":"uuid","nullable":true},"rolledBackAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"notes":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","supplierId","name","currency","version","status","effectiveFrom","expiresAt","source","sourceRef","approvedAt","validation","supersedesId","rolledBackAt","notes","createdAt","updatedAt"],"additionalProperties":true}}},"required":["name","versions"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/rate-decks/{id}/diff":{"get":{"operationId":"getSwitchRateDecksByIdDiff","tags":["Switch: rating"],"summary":"Compare a rate deck with the prices in force","description":"Per supplier trunk the deck covers, what activating it would change against the rows pricing calls now. Writes nothing.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"deckId":{"type":"string","format":"uuid"},"name":{"type":"string"},"version":{"type":"integer"},"status":{"type":"string","enum":["draft","uploaded","invalid","validated","pending_approval","scheduled","active","expired","rolled_back"]},"effectiveFrom":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"trunks":{"type":"array","items":{"type":"object","properties":{"trunkId":{"type":"string","format":"uuid"},"label":{"type":"string"},"diff":{"$ref":"#/components/schemas/SwitchRateDeckDiff"},"originScoped":{"type":"integer"}},"required":["trunkId","label","diff","originScoped"]}}},"required":["deckId","name","version","status","effectiveFrom","trunks"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/rate-decks/{id}/trunks":{"put":{"operationId":"putSwitchRateDecksByIdTrunks","tags":["Switch: rating"],"summary":"Set which supplier trunks a rate deck prices","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchRateDeck"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"trunkIds":{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":200}},"required":["trunkIds"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"trunkIds":["<trunkId>"]}}}},"/api/v1/switch/rate-decks/{id}/rows":{"put":{"operationId":"putSwitchRateDecksByIdRows","tags":["Switch: rating"],"summary":"Replace the rows of a draft rate deck","description":"Up to 200,000 rows, replacing whatever the deck held. Rows are stored pending and price nothing until the deck is activated. Validation runs straight after, and the validated deck is returned. Rows can only be changed while the deck is draft, uploaded, invalid or validated (`mutable: true`); an active deck is changed by opening a new version.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchRateDeck"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"rows":{"type":"array","items":{"type":"object","properties":{"prefix":{"type":"string","maxLength":24},"rate":{"anyOf":[{"type":"number"},{"type":"string"}],"description":"Price per minute; a number or a decimal string. Blank is refused, 0 is a real price."},"origin":{"type":"string","maxLength":24,"description":"Caller-origin prefix; omit for any origin"},"destinationName":{"type":"string","maxLength":96,"nullable":true},"country":{"type":"string","maxLength":64,"nullable":true},"mcc":{"type":"string","maxLength":8,"nullable":true},"mnc":{"type":"string","maxLength":8,"nullable":true},"jurisdiction":{"type":"string","maxLength":16,"nullable":true},"connectionFee":{"anyOf":[{"type":"number"},{"type":"string"}],"nullable":true},"minChargedSeconds":{"type":"integer","minimum":0,"nullable":true},"billingIncrement":{"type":"string","maxLength":10,"nullable":true},"effectiveFrom":{"type":"string","maxLength":40,"nullable":true},"endDate":{"type":"string","maxLength":40,"nullable":true}},"required":["prefix","rate"]},"maxItems":200000}},"required":["rows"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"rows":[{"prefix":"44","rate":1}]}}}},"/api/v1/switch/rate-decks/{id}/versions":{"post":{"operationId":"postSwitchRateDecksByIdVersions","tags":["Switch: rating"],"summary":"Open a new draft version of a rate deck","description":"Copies this deck's rows and trunks into version n+1 as a draft, so an active deck can be repriced without editing it in place.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchRateDeck"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/rate-decks/{id}/validate":{"post":{"operationId":"postSwitchRateDecksByIdValidate","tags":["Switch: rating"],"summary":"Validate a rate deck","description":"Checks the rows (missing prices, duplicate prefixes, increases) and stores the result on the deck. A deck with errors becomes invalid and cannot be activated.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchRateDeck"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/rate-decks/{id}/submit":{"post":{"operationId":"postSwitchRateDecksByIdSubmit","tags":["Switch: rating"],"summary":"Submit a rate deck for approval","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchRateDeck"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/rate-decks/{id}/approve":{"post":{"operationId":"postSwitchRateDecksByIdApprove","tags":["Switch: rating"],"summary":"Approve a rate deck, now or from a future date","description":"With no effectiveFrom (or a past one) the deck is activated immediately. A future effectiveFrom schedules it and emits the cost_rate.scheduled webhook.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchRateDeck"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"effectiveFrom":{"type":"string","maxLength":40,"nullable":true}}}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"effectiveFrom":"<effectiveFrom>"}}}},"/api/v1/switch/rate-decks/{id}/activate":{"post":{"operationId":"postSwitchRateDecksByIdActivate","tags":["Switch: rating"],"summary":"Activate a rate deck","description":"Makes the deck's rows price calls on its trunks from now on and supersedes the deck they replace. Exactly one deck is active per trunk.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchRateDeck"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/rate-decks/{id}/rollback":{"post":{"operationId":"postSwitchRateDecksByIdRollback","tags":["Switch: rating"],"summary":"Roll back an active rate deck","description":"Withdraws the deck and restores the one it superseded (named in restoredDeckId). Emits the cost_rate.rolled_back webhook.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"supplierId":{"type":"string","format":"uuid","nullable":true,"description":"The provider who sent it; null for a deck recorded before its provider was"},"name":{"type":"string"},"currency":{"type":"string","minLength":3,"maxLength":3},"version":{"type":"integer"},"status":{"type":"string","enum":["draft","uploaded","invalid","validated","pending_approval","scheduled","active","expired","rolled_back"]},"effectiveFrom":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"expiresAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"source":{"type":"string","enum":["portal","csv","api","email","sftp"],"nullable":true},"sourceRef":{"type":"string","nullable":true},"approvedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"validation":{"type":"object","properties":{"checkedAt":{"type":"string"},"rows":{"type":"integer"},"destinations":{"type":"integer"},"errors":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true,"description":"One validation finding (code, message and the rows it concerns)"}},"warnings":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true,"description":"One validation finding (code, message and the rows it concerns)"}},"maxIncreasePct":{"type":"number"}},"required":["checkedAt","rows","destinations","errors","warnings"],"nullable":true,"description":"The last validation result; null before the deck is validated"},"supersedesId":{"type":"string","format":"uuid","nullable":true},"rolledBackAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"notes":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"rowCount":{"type":"integer"},"trunks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"label":{"type":"string"}},"required":["id","label"]},"description":"Supplier trunks the deck prices"},"mutable":{"type":"boolean","description":"Whether rows can still be edited"},"restoredDeckId":{"type":"string","format":"uuid","nullable":true}},"required":["id","supplierId","name","currency","version","status","effectiveFrom","expiresAt","source","sourceRef","approvedAt","validation","supersedesId","rolledBackAt","notes","createdAt","updatedAt","rowCount","trunks","mutable","restoredDeckId"],"additionalProperties":true}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/providers/{id}/call-records":{"get":{"operationId":"getSwitchProvidersByIdCallRecords","tags":["Switch: suppliers"],"summary":"Get call totals for a provider across its trunks","description":"Calls, answer rate, minutes and cost over a window, overall and per trunk. `cost` and `minutes` are JSON numbers here (report figures, not ledger amounts).\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"window":{"type":"object","properties":{"from":{"type":"string"},"to":{"type":"string"}},"required":["from","to"]},"summary":{"type":"object","properties":{"calls":{"type":"number"},"answered":{"type":"number"},"asr":{"type":"number","nullable":true},"minutes":{"type":"number"},"cost":{"type":"number"},"acd":{"type":"number","nullable":true},"avgPddMs":{"type":"number","nullable":true}},"required":["calls","answered","asr","minutes","cost","acd","avgPddMs"],"additionalProperties":true},"byTrunk":{"type":"array","items":{"type":"object","properties":{"trunkId":{"type":"string","format":"uuid","nullable":true},"label":{"type":"string"},"calls":{"type":"number"},"answered":{"type":"number"},"asr":{"type":"number","nullable":true},"minutes":{"type":"number"},"cost":{"type":"number"}},"required":["trunkId","label","calls","answered","asr","minutes","cost"],"additionalProperties":true}}},"required":["window","summary","byTrunk"],"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"from","in":"query","required":false,"description":"ISO start of the window","schema":{"type":"string"}},{"name":"to","in":"query","required":false,"description":"ISO end of the window","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"string"}},{"name":"offset","in":"query","required":false,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/providers/{id}/invoices":{"get":{"operationId":"getSwitchProvidersByIdInvoices","tags":["Switch: suppliers"],"summary":"List a provider payables and unbilled cost","description":"The provider billing terms, its payable documents, and cost carried since the last one that has not been raised yet (a JSON number).\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"currency":{"type":"string"},"billingMode":{"type":"string"},"creditLimit":{"type":"string","nullable":true,"description":"Decimal string with 2 decimal places, e.g. \"5000.00\""},"paymentTermsDays":{"type":"integer","nullable":true},"invoiceCycle":{"type":"string","nullable":true},"invoices":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}},"unbilled":{"type":"object","properties":{"since":{"type":"string","nullable":true},"calls":{"type":"number"},"minutes":{"type":"number"},"cost":{"type":"number"}},"required":["since","calls","minutes","cost"],"additionalProperties":true}},"required":["currency","billingMode","creditLimit","paymentTermsDays","invoiceCycle","invoices","unbilled"],"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/providers/{id}/alerts":{"get":{"operationId":"getSwitchProvidersByIdAlerts","tags":["Switch: suppliers"],"summary":"List what is wrong with a provider right now","description":"Derived on every read, never stored: unroutable status, trunks in fault or draining, expiring credentials, expired trunks.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"alerts":{"type":"array","items":{"type":"object","properties":{"severity":{"type":"string","enum":["critical","warning","info"]},"code":{"type":"string"},"message":{"type":"string"},"trunkId":{"type":"string","format":"uuid"}},"required":["severity","code","message"]}}},"required":["alerts"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/providers/{id}/audit":{"get":{"operationId":"getSwitchProvidersByIdAudit","tags":["Switch: suppliers"],"summary":"Get the change history for a provider and its trunks","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"entries":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}}},"required":["entries"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Max entries (default 100)","schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/providers/{id}/disputes":{"get":{"operationId":"getSwitchProvidersByIdDisputes","tags":["Switch: suppliers"],"summary":"List billing disputes with a provider","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/SwitchProviderDispute"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}},"post":{"operationId":"postSwitchProvidersByIdDisputes","tags":["Switch: suppliers"],"summary":"Open a billing dispute with a provider","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchProviderDispute"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"periodStart":{"type":"string","maxLength":40,"nullable":true},"periodEnd":{"type":"string","maxLength":40,"nullable":true},"ourAmount":{"anyOf":[{"type":"number"},{"type":"string"}],"nullable":true},"theirAmount":{"anyOf":[{"type":"number"},{"type":"string"}],"nullable":true},"currency":{"type":"string","minLength":3,"maxLength":3,"nullable":true},"reason":{"type":"string","maxLength":4000,"nullable":true},"resolution":{"type":"string","maxLength":4000,"nullable":true},"invoiceRef":{"type":"string","maxLength":120,"nullable":true},"status":{"type":"string","enum":["open","submitted","accepted","rejected","settled","withdrawn"]}}}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"periodStart":"<periodStart>","periodEnd":"<periodEnd>"}}}},"/api/v1/switch/providers/{id}/disputes/{disputeId}":{"patch":{"operationId":"patchSwitchProvidersByIdDisputesByDisputeId","tags":["Switch: suppliers"],"summary":"Update a billing dispute","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchProviderDispute"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"disputeId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"periodStart":{"type":"string","maxLength":40,"nullable":true},"periodEnd":{"type":"string","maxLength":40,"nullable":true},"ourAmount":{"anyOf":[{"type":"number"},{"type":"string"}],"nullable":true},"theirAmount":{"anyOf":[{"type":"number"},{"type":"string"}],"nullable":true},"currency":{"type":"string","minLength":3,"maxLength":3,"nullable":true},"reason":{"type":"string","maxLength":4000,"nullable":true},"resolution":{"type":"string","maxLength":4000,"nullable":true},"invoiceRef":{"type":"string","maxLength":120,"nullable":true},"status":{"type":"string","enum":["open","submitted","accepted","rejected","settled","withdrawn"]}}}}}},"x-px-example":{"path":{"id":"<id>","disputeId":"<disputeId>"},"query":{},"body":{"periodStart":"<periodStart>","periodEnd":"<periodEnd>"}}}},"/api/v1/switch/suppliers/{id}/endpoints":{"get":{"operationId":"getSwitchSuppliersByIdEndpoints","tags":["Switch: suppliers"],"summary":"List SIP endpoints of a supplier trunk","description":"Primary and backup addresses with derived health and flap reports. A trunk with an address but no endpoint rows has its address adopted as endpoint 1 on first read.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/SwitchTrunkEndpoint"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}},"post":{"operationId":"postSwitchSuppliersByIdEndpoints","tags":["Switch: suppliers"],"summary":"Add a SIP endpoint to a supplier trunk","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchTrunkEndpoint"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"role":{"type":"string","enum":["primary","backup"]},"host":{"type":"string","minLength":1,"maxLength":255},"port":{"anyOf":[{"type":"number"},{"type":"string"}],"nullable":true},"transport":{"type":"string","enum":["udp","tcp","tls"]},"priority":{"anyOf":[{"type":"number"},{"type":"string"}]},"weightPct":{"anyOf":[{"type":"number"},{"type":"string"}],"nullable":true},"enabled":{"type":"boolean"},"optionsIntervalSeconds":{"anyOf":[{"type":"number"},{"type":"string"}],"nullable":true},"failureThreshold":{"anyOf":[{"type":"number"},{"type":"string"}]},"recoveryThreshold":{"anyOf":[{"type":"number"},{"type":"string"}]},"autoDisable":{"type":"boolean"}},"required":["host"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"host":"203.0.113.10"}}}},"/api/v1/switch/suppliers/{id}/endpoints/{endpointId}":{"patch":{"operationId":"patchSwitchSuppliersByIdEndpointsByEndpointId","tags":["Switch: suppliers"],"summary":"Update a SIP endpoint","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchTrunkEndpoint"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"endpointId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"role":{"type":"string","enum":["primary","backup"]},"host":{"type":"string","minLength":1,"maxLength":255},"port":{"anyOf":[{"type":"number"},{"type":"string"}],"nullable":true},"transport":{"type":"string","enum":["udp","tcp","tls"]},"priority":{"anyOf":[{"type":"number"},{"type":"string"}]},"weightPct":{"anyOf":[{"type":"number"},{"type":"string"}],"nullable":true},"enabled":{"type":"boolean"},"optionsIntervalSeconds":{"anyOf":[{"type":"number"},{"type":"string"}],"nullable":true},"failureThreshold":{"anyOf":[{"type":"number"},{"type":"string"}]},"recoveryThreshold":{"anyOf":[{"type":"number"},{"type":"string"}]},"autoDisable":{"type":"boolean"}}}}}},"x-px-example":{"path":{"id":"<id>","endpointId":"<endpointId>"},"query":{},"body":{"role":"primary","host":"203.0.113.10"}}},"delete":{"operationId":"deleteSwitchSuppliersByIdEndpointsByEndpointId","tags":["Switch: suppliers"],"summary":"Remove a SIP endpoint","description":"The last endpoint of a trunk cannot be removed: add its replacement first.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"deleted":{"type":"boolean","enum":[true]}},"required":["deleted"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"endpointId","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>","endpointId":"<endpointId>"},"query":{}}}},"/api/v1/switch/suppliers/{id}/sbc-profile":{"get":{"operationId":"getSwitchSuppliersByIdSbcProfile","tags":["Switch: suppliers"],"summary":"Render the SBC gateway configuration for a supplier trunk","description":"Read-only. Names which settings are profile-level (and so need a deploy) rather than applied per call. Each read is recorded in the audit log.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchSbcProfile"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/providers/{id}/sbc-profile":{"get":{"operationId":"getSwitchProvidersByIdSbcProfile","tags":["Switch: suppliers"],"summary":"Render the SBC gateway configuration for a provider","description":"Read-only. One rendered profile per trunk; `needsReload` says whether any of it needs deploying. Each read is recorded in the audit log.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"supplierId":{"type":"string","format":"uuid"},"supplierName":{"type":"string"},"trunks":{"type":"array","items":{"$ref":"#/components/schemas/SwitchSbcProfile"}},"needsReload":{"type":"boolean"}},"required":["supplierId","supplierName","trunks","needsReload"],"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/suppliers/{id}/health-events":{"get":{"operationId":"getSwitchSuppliersByIdHealthEvents","tags":["Switch: suppliers"],"summary":"List health events for a supplier trunk","description":"Probe results, up/down transitions, auto-disables, restores and degradations. Probe rows are kept 7 days, state changes 90 days. Page with `before` = the previous `nextBefore`.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"events":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}},"windowDays":{"type":"integer"},"retention":{"type":"object","properties":{"probeDays":{"type":"integer"},"eventDays":{"type":"integer"}},"required":["probeDays","eventDays"]},"nextBefore":{"type":"string","nullable":true}},"required":["events","windowDays","retention","nextBefore"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"endpointId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"days","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":90}},{"name":"kinds","in":"query","required":false,"description":"Comma-separated: probe, transition, auto_disable, restore, degraded","schema":{"type":"string","maxLength":120}},{"name":"before","in":"query","required":false,"description":"ISO cursor from nextBefore","schema":{"type":"string","maxLength":40}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/suppliers/{id}/flap-report":{"get":{"operationId":"getSwitchSuppliersByIdFlapReport","tags":["Switch: suppliers"],"summary":"Get the flap report for a supplier trunk","description":"Endpoints that changed state repeatedly in the window. Observe-only: nothing is disabled because of it.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"windowHours":{"type":"number"},"minTransitions":{"type":"integer"},"endpoints":{"type":"array","items":{"type":"object","properties":{"endpointId":{"type":"string","format":"uuid","nullable":true},"host":{"type":"string","nullable":true},"transitions":{"type":"integer"},"firstAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"lastAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"flapping":{"type":"boolean"}},"required":["endpointId","host","transitions","firstAt","lastAt","flapping"]}},"flapping":{"type":"boolean"}},"required":["windowHours","minTransitions","endpoints","flapping"],"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/suppliers/{id}/test-call":{"post":{"operationId":"postSwitchSuppliersByIdTestCall","tags":["Switch: suppliers"],"summary":"Send a test call to a supplier trunk","description":"A real INVITE from every media worker, on demand. Never touches health counters or state. Address details are withheld for a marketplace trunk. Audited.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Rate limit:** 6 requests per minute per caller.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"ranAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"host":{"type":"string","nullable":true},"port":{"type":"integer","nullable":true},"techPrefix":{"type":"string","nullable":true},"verdict":{"type":"string"},"latencyMs":{"type":"integer"},"diagnostics":{"type":"object","properties":{},"additionalProperties":true},"endpointHidden":{"type":"boolean"}},"required":["ranAt","host","port","techPrefix","verdict","latencyMs","diagnostics"],"additionalProperties":true}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-rate-limit":{"max":6,"window":"minute"},"x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"endpointId":{"type":"string","format":"uuid","nullable":true}}}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"endpointId":"<endpointId>"}},"x-px-billable":{"kind":"traffic","note":"Places a real test call or sends a real test SMS over the trunk."}}},"/api/v1/switch/suppliers/{id}/assign-account":{"post":{"operationId":"postSwitchSuppliersByIdAssignAccount","tags":["Switch: suppliers"],"summary":"Move a supplier trunk to another provider","description":"Pass `supplierId: null` to ungroup the trunk.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchSupplierTrunk"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"supplierId":{"type":"string","format":"uuid","nullable":true}},"required":["supplierId"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"supplierId":"<supplierId>"}}}},"/api/v1/switch/suppliers":{"get":{"operationId":"getSwitchSuppliers","tags":["Switch: suppliers"],"summary":"List supplier trunks","description":"Every vendor trunk on your switch, newest first. SIP and SMPP secrets are replaced by *Set booleans.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/SwitchSupplierTrunk"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}},"post":{"operationId":"postSwitchSuppliers","tags":["Switch: suppliers"],"summary":"Create a supplier trunk","description":"A trunk needs at least one reachable endpoint: a SIP host, an HTTPS SMS delivery URL, or an SMPP host.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchSupplierTrunk"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":160},"supplierId":{"type":"string","format":"uuid","nullable":true},"sipHost":{"type":"string","maxLength":255,"nullable":true},"sipPort":{"type":"integer","minimum":1,"maximum":65535,"nullable":true},"transport":{"type":"string","enum":["udp","tcp","tls"],"nullable":true},"techPrefix":{"type":"string","maxLength":24,"nullable":true},"sipAuthUsername":{"type":"string","maxLength":128,"nullable":true},"sipAuthPassword":{"type":"string","maxLength":128,"nullable":true},"supportedCodecs":{"type":"array","items":{"type":"string","maxLength":24},"maxItems":16,"nullable":true},"defaultRatePerUnit":{"type":"number","minimum":0,"nullable":true},"mediaMode":{"type":"string","enum":["proxy","direct"]},"billingIncrement":{"type":"string","maxLength":10,"nullable":true},"currency":{"type":"string","minLength":3,"maxLength":3,"nullable":true},"capacity":{"type":"integer","minimum":0,"nullable":true},"maxCps":{"type":"integer","minimum":0,"nullable":true},"status":{"type":"string","enum":["active","disabled","draft","testing","draining","fault"]},"settlementMode":{"type":"string","enum":["ap","prepaid"]},"balance":{"type":"number","minimum":0,"nullable":true},"portalEmail":{"type":"string","format":"email","maxLength":255,"nullable":true},"smsDeliveryUrl":{"type":"string","format":"uri","maxLength":500,"nullable":true},"smsDeliveryMethod":{"type":"string","enum":["http","smpp"],"nullable":true},"smppHost":{"type":"string","maxLength":255,"nullable":true},"smppPort":{"type":"integer","minimum":1,"maximum":65535,"nullable":true},"smppSystemId":{"type":"string","nullable":true},"smppPassword":{"type":"string","maxLength":64,"nullable":true},"smppBindType":{"type":"string","enum":["transceiver","transmitter"],"nullable":true},"smppSystemType":{"type":"string","maxLength":13,"nullable":true},"smppTps":{"type":"integer","minimum":1,"maximum":1000,"nullable":true},"code":{"type":"string","maxLength":40,"nullable":true},"description":{"type":"string","maxLength":2000,"nullable":true},"product":{"type":"string","maxLength":32,"nullable":true},"direction":{"type":"string","enum":["termination","origination","bidirectional"]},"testMode":{"type":"boolean"},"activationDate":{"type":"string","maxLength":10,"nullable":true},"expirationDate":{"type":"string","maxLength":10,"nullable":true},"tags":{"type":"array","items":{"type":"string","maxLength":40},"maxItems":20,"nullable":true},"notes":{"type":"string","maxLength":4000,"nullable":true},"credentialExpiresAt":{"type":"string","maxLength":40,"nullable":true},"credentialRotatedAt":{"type":"string","maxLength":40,"nullable":true},"allowedSourceNetworks":{"type":"array","items":{"type":"string","maxLength":64},"maxItems":64,"nullable":true},"requestRateLimit":{"type":"integer","minimum":0,"maximum":100000,"nullable":true},"sipRegister":{"type":"boolean"},"sipRealm":{"type":"string","maxLength":255,"nullable":true},"incomingTechPrefix":{"type":"string","maxLength":24,"nullable":true},"techPrefixMode":{"type":"string","enum":["add","remove","replace"]},"techPrefixSeparator":{"type":"string","maxLength":4,"nullable":true},"cliRewrite":{"nullable":true},"dnisRewrite":{"nullable":true},"cliPolicy":{"type":"string","enum":["passthrough","replace","remove","pool"]},"cliPoolId":{"type":"string","format":"uuid","nullable":true},"anonymousPolicy":{"type":"string","enum":["passthrough","reject","substitute"]},"e164Normalise":{"type":"boolean"},"dnisFormat":{"type":"string","enum":["plus","digits"],"nullable":true},"cliFormat":{"type":"string","enum":["plus","digits"],"nullable":true},"defaultCountryCode":{"type":"string","maxLength":6,"nullable":true},"minDnisLength":{"type":"integer","minimum":0,"maximum":32,"nullable":true},"maxDnisLength":{"type":"integer","minimum":0,"maximum":32,"nullable":true},"paiPolicy":{"type":"string","enum":["omit","passthrough","generate"]},"rpidPolicy":{"type":"string","enum":["omit","passthrough","generate"]},"diversionPolicy":{"type":"string","enum":["omit","passthrough","generate"]},"historyInfoPolicy":{"type":"string","enum":["omit","passthrough","generate"]},"lrnPolicy":{"type":"string","enum":["none","passthrough","strip"]},"packetizationMs":{"type":"integer","minimum":10,"maximum":120,"nullable":true},"codecMode":{"type":"string","enum":["transparent","transcode"]},"forcedCodec":{"type":"string","maxLength":24,"nullable":true},"srtpMode":{"type":"string","enum":["disabled","optional","required"]},"dtmfMode":{"type":"string","enum":["rfc2833","info","inband","auto"]},"t38Mode":{"type":"string","enum":["disabled","passthrough","relay"]},"comfortNoise":{"type":"boolean"},"silenceSuppression":{"type":"boolean"},"symmetricRtp":{"type":"boolean"},"inviteTimeoutSeconds":{"type":"integer","minimum":1,"maximum":600,"nullable":true},"pddTimeoutSeconds":{"type":"integer","minimum":1,"maximum":600,"nullable":true},"ringTimeoutSeconds":{"type":"integer","minimum":1,"maximum":600,"nullable":true},"sessionExpiresSeconds":{"type":"integer","minimum":90,"maximum":86400,"nullable":true},"minSeSeconds":{"type":"integer","minimum":90,"maximum":86400,"nullable":true},"prackMode":{"type":"string","enum":["disabled","supported","required"]},"allowReinvite":{"type":"boolean"},"allowUpdate":{"type":"boolean"},"allowRefer":{"type":"boolean"},"earlyMediaPolicy":{"type":"string","enum":["passthrough","generate_ringback","suppress"]},"recordRoute":{"type":"boolean"},"customHeaders":{"type":"object","additionalProperties":{"type":"string","maxLength":200},"nullable":true},"q850Map":{"type":"object","additionalProperties":{"type":"integer","minimum":0,"maximum":255},"nullable":true},"cpsBurst":{"type":"integer","minimum":0,"maximum":10000,"nullable":true},"queueLimit":{"type":"integer","minimum":0,"maximum":100000,"nullable":true},"maxChannelsPerDestination":{"type":"integer","minimum":0,"maximum":100000,"nullable":true},"maxCpsPerDestination":{"type":"integer","minimum":0,"maximum":10000,"nullable":true},"minCallSeconds":{"type":"integer","minimum":0,"maximum":86400,"nullable":true},"maxCallSeconds":{"type":"integer","minimum":0,"maximum":86400,"nullable":true},"dailyMinutesCap":{"type":"integer","minimum":0,"nullable":true},"dailySpendCap":{"anyOf":[{"type":"number"},{"type":"string"}],"nullable":true},"monthlySpendCap":{"anyOf":[{"type":"number"},{"type":"string"}],"nullable":true},"rampupChannels":{"type":"integer","minimum":0,"maximum":100000,"nullable":true},"rampupDays":{"type":"integer","minimum":0,"maximum":365,"nullable":true},"allowedPrefixes":{"type":"array","items":{"type":"string","maxLength":24},"maxItems":500,"nullable":true},"blockedPrefixes":{"type":"array","items":{"type":"string","maxLength":24},"maxItems":500,"nullable":true},"allowedCountries":{"type":"array","items":{"type":"string","maxLength":4},"maxItems":300,"nullable":true},"blockedCountries":{"type":"array","items":{"type":"string","maxLength":4},"maxItems":300,"nullable":true},"allowMobile":{"type":"boolean"},"allowFixed":{"type":"boolean"},"allowSatellite":{"type":"boolean"},"allowPremium":{"type":"boolean"},"allowTollfree":{"type":"boolean"},"allowEmergency":{"type":"boolean"},"jurisdictionPolicy":{"type":"string","enum":["any","interstate","intrastate","local"]},"schedule":{"type":"array","items":{"type":"object","properties":{"days":{"type":"array","items":{"type":"integer","minimum":1,"maximum":7},"maxItems":7},"from":{"type":"string","maxLength":5},"to":{"type":"string","maxLength":5},"tz":{"type":"string","maxLength":64}},"required":["days","from","to","tz"]},"maxItems":20,"nullable":true},"maintenanceWindows":{"type":"array","items":{"type":"object","properties":{"from":{"type":"string","maxLength":40},"to":{"type":"string","maxLength":40},"note":{"type":"string","maxLength":200}},"required":["from","to"]},"maxItems":50,"nullable":true},"routingEnabled":{"type":"boolean"},"lcrEligible":{"type":"boolean"},"qualityEligible":{"type":"boolean"},"popRegion":{"type":"string","maxLength":40,"nullable":true},"allowedCustomerGroups":{"type":"array","items":{"type":"string","maxLength":40},"maxItems":50,"nullable":true},"allowedProducts":{"type":"array","items":{"type":"string","maxLength":40},"maxItems":50,"nullable":true},"minMarginPct":{"anyOf":[{"type":"number"},{"type":"string"}],"nullable":true},"minMarginAbs":{"anyOf":[{"type":"number"},{"type":"string"}],"nullable":true},"maxBuyRate":{"anyOf":[{"type":"number"},{"type":"string"}],"nullable":true},"overflowTrunkId":{"type":"string","format":"uuid","nullable":true},"retryableSipCodes":{"type":"array","items":{"type":"integer","minimum":100,"maximum":699},"maxItems":60,"nullable":true},"terminalSipCodes":{"type":"array","items":{"type":"integer","minimum":100,"maximum":699},"maxItems":60,"nullable":true},"retryPolicy":{"type":"string","enum":["same_endpoint","next_endpoint","next_trunk"]},"maxAttemptsPerCall":{"type":"integer","minimum":1,"maximum":10,"nullable":true},"qosThresholds":{"type":"object","properties":{"asrMin":{"type":"number","minimum":0,"maximum":100},"acdMin":{"type":"number","minimum":0,"maximum":86400},"nerMin":{"type":"number","minimum":0,"maximum":100},"pddMaxMs":{"type":"integer","minimum":0,"maximum":600000},"mosMin":{"type":"number","minimum":1,"maximum":5},"shortCallMaxPct":{"type":"number","minimum":0,"maximum":100},"minCalls":{"type":"integer","minimum":1,"maximum":1000000},"windowMinutes":{"type":"integer","minimum":5,"maximum":10080},"action":{"type":"string","enum":["alert","demote","reduce_cps","block_destination","disable_trunk"]},"mode":{"type":"string","enum":["observe","enforce"]}},"nullable":true},"fraudControls":{"type":"object","properties":{"shortCallSeconds":{"type":"integer","minimum":1,"maximum":3600},"longCallSeconds":{"type":"integer","minimum":1,"maximum":86400},"duplicateDetect":{"type":"boolean"},"spikeMultiple":{"type":"number","minimum":1.1,"maximum":1000},"spendVelocityPerHour":{"type":"number","minimum":0,"maximum":1000000},"highCostRate":{"type":"number","minimum":0,"maximum":10000},"action":{"type":"string","enum":["alert","demote","reduce_cps","block_destination","disable_trunk"]},"mode":{"type":"string","enum":["observe","enforce"]}},"nullable":true}},"required":["label"]}}}},"x-px-example":{"path":{},"query":{},"body":{"label":"Acme"}}}},"/api/v1/switch/suppliers/live":{"get":{"operationId":"getSwitchSuppliersLive","tags":["Switch: suppliers"],"summary":"Get live metrics for active supplier trunks","description":"Concurrent channels, peak CPS, reachability and the last hour of answer rate and post-dial delay per active trunk, plus the calls per second arriving at your switch (cpsIngress*) with the split by where each call went first. Meant to be polled.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"trunks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"label":{"type":"string"},"capacity":{"type":"integer","nullable":true},"maxCps":{"type":"integer","nullable":true},"reachable":{"type":"boolean","nullable":true},"health":{"type":"object","properties":{},"additionalProperties":true,"description":"Derived health state (what routing believes), with its counters and thresholds"},"asr":{"type":"number","nullable":true,"description":"Last-hour answer rate %, null when idle"},"asrSessions":{"type":"integer"},"pddP95Ms":{"type":"integer","nullable":true},"lastSipCode":{"type":"integer","nullable":true},"lastCause":{"type":"string","nullable":true},"liveChannels":{"type":"integer"},"cps":{"type":"integer"},"capacityPct":{"type":"integer","nullable":true},"flapping":{"type":"boolean"}},"required":["id","label","capacity","maxCps","reachable","health","asr","asrSessions","pddP95Ms","lastSipCode","lastCause","liveChannels","cps","capacityPct","flapping"],"additionalProperties":true}},"totalChannels":{"type":"integer"},"peakCps":{"type":"integer","description":"Busiest second on your own supplier trunks in the last minute"},"cpsAttempts":{"type":"integer","description":"Calls started on your own supplier trunks in the last minute"},"cpsIngressAttempts60":{"type":"integer","description":"Every call that arrived at your switch in the last minute, refused calls included, counted once per call"},"cpsIngressAvg":{"type":"number","description":"cpsIngressAttempts60 over the window, one decimal: calls per second arriving at your switch"},"cpsIngressPeak":{"type":"integer","description":"Busiest single second of arriving calls in the last minute"},"cpsSupplierAttempts60":{"type":"integer","description":"Arriving calls whose first attempt went to one of your own supplier trunks"},"cpsMarketplaceAttempts60":{"type":"integer","description":"Arriving calls whose first attempt went to a marketplace route"},"cpsRefused60":{"type":"integer","description":"Arriving calls your switch refused; counted in the total only, not in the split"},"cpsIngressWindowSec":{"type":"integer","description":"Length of the ingress window in seconds (60)"}},"required":["trunks","totalChannels","peakCps","cpsAttempts","cpsIngressAttempts60","cpsIngressAvg","cpsIngressPeak","cpsSupplierAttempts60","cpsMarketplaceAttempts60","cpsRefused60","cpsIngressWindowSec"],"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/switch/suppliers/{id}/routing":{"get":{"operationId":"getSwitchSuppliersByIdRouting","tags":["Switch: suppliers"],"summary":"Show where a supplier trunk sits in routing","description":"The route groups that reference it and at what priority, and any customer trunk wired straight to it. `unrouted` is true when no traffic can reach it.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"groups":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}},"direct":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}},"unrouted":{"type":"boolean"}},"required":["groups","direct","unrouted"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/suppliers/promote":{"post":{"operationId":"postSwitchSuppliersPromote","tags":["Switch: suppliers"],"summary":"Promote a marketplace purchase to a supplier trunk","description":"Turns a route you bought on the marketplace into a trunk your switch can route to. Idempotent per route: promoting again returns the existing trunk. The seller address stays hidden.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchSupplierTrunk"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"routeId":{"type":"string","format":"uuid"}},"required":["routeId"]}}}},"x-px-example":{"path":{},"query":{},"body":{"routeId":"<routeId>"}}}},"/api/v1/switch/suppliers/{id}/credentials":{"get":{"operationId":"getSwitchSuppliersByIdCredentials","tags":["Switch: suppliers"],"summary":"Reveal a supplier trunk SIP credentials","description":"The one audited way to read a stored SIP password back. Refused (403) for a trunk promoted from the marketplace, whose login belongs to the seller.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"sipAuthUsername":{"type":"string","nullable":true},"sipAuthPassword":{"type":"string","nullable":true}},"required":["sipAuthUsername","sipAuthPassword"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/suppliers/{id}/overview":{"get":{"operationId":"getSwitchSuppliersByIdOverview","tags":["Switch: suppliers"],"summary":"Get a supplier trunk overview and today figures","description":"Trunk settings plus KPIs: today cost, minutes and calls, last-hour answer rate, ACD, PDD and MOS, live channels, CPS and outstanding payables. KPI money is a JSON number.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"supplier":{"type":"object","properties":{},"additionalProperties":true},"kpis":{"type":"object","properties":{},"additionalProperties":true}},"required":["supplier","kpis"],"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/suppliers/{id}/quality":{"get":{"operationId":"getSwitchSuppliersByIdQuality","tags":["Switch: suppliers"],"summary":"Get quality by destination for a supplier trunk","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"windowHours":{"type":"number"},"window":{"type":"object","properties":{},"additionalProperties":true},"kpis":{"type":"object","properties":{},"additionalProperties":true},"destinations":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}},"thresholds":{"type":"object","properties":{},"additionalProperties":true},"excludedMetrics":{"type":"array","items":{}},"minJudgeableSessions":{"type":"number"},"freshness":{"type":"object","properties":{},"additionalProperties":true}},"required":["windowHours","window","kpis","destinations","thresholds","excludedMetrics","minJudgeableSessions","freshness"],"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"window","in":"query","required":false,"description":"Window in hours (default 24)","schema":{"type":"integer"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/suppliers/{id}/protection-events":{"get":{"operationId":"getSwitchSuppliersByIdProtectionEvents","tags":["Switch: suppliers"],"summary":"List quality and fraud protection events for a supplier trunk","description":"What the protection sweep saw on this trunk and what it did (enforced) or would have done (observe mode).\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"vendorTrunkId":{"type":"string","format":"uuid"},"mode":{"type":"string"},"action":{"type":"string"},"enforced":{"type":"boolean"},"reason":{"type":"string"},"breaches":{"type":"array","items":{"type":"string"},"nullable":true},"measured":{},"windowMinutes":{"type":"integer"},"calls":{"type":"integer"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","vendorTrunkId","mode","action","enforced","reason","breaches","windowMinutes","calls","createdAt"],"additionalProperties":true}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/suppliers/{id}":{"get":{"operationId":"getSwitchSuppliersById","tags":["Switch: suppliers"],"summary":"Get a supplier trunk","description":"Includes its inbound IP ACLs, a loopback warning when its address is also one of your customers, and the derived health state.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchSupplierTrunkDetail"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}},"patch":{"operationId":"patchSwitchSuppliersById","tags":["Switch: suppliers"],"summary":"Update a supplier trunk","description":"Partial update. When trunk change approval is on, the change is queued for review instead and the response carries `pendingChange`. Send `X-If-Unchanged-Since: <updatedAt you loaded>` to be refused with 409 STALE_WRITE if someone else saved in between.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"supplierId":{"type":"string","format":"uuid","nullable":true,"description":"The owning provider; null = ungrouped"},"label":{"type":"string"},"source":{"type":"string","description":"\"external\" for a carrier you entered; \"marketplace\" for a trunk promoted from a marketplace purchase"},"status":{"type":"string","enum":["active","disabled","draft","testing","draining","fault"]},"sipHost":{"type":"string","nullable":true,"description":"Null on a marketplace trunk: the seller address is never disclosed"},"sipPort":{"type":"integer","nullable":true},"transport":{"type":"string","enum":["udp","tcp","tls"],"nullable":true},"techPrefix":{"type":"string","nullable":true},"sipAuthUsername":{"type":"string","nullable":true},"sipAuthPasswordSet":{"type":"boolean","description":"Whether a SIP password is stored. The value is only readable via GET /switch/suppliers/{id}/credentials"},"smppPasswordSet":{"type":"boolean"},"mediaMode":{"type":"string","enum":["proxy","direct"]},"defaultRatePerUnit":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"Cost per minute used when no deck row matches"},"billingIncrement":{"type":"string","nullable":true},"currency":{"type":"string","nullable":true},"capacity":{"type":"integer","nullable":true,"description":"Max concurrent channels"},"maxCps":{"type":"integer","nullable":true},"settlementMode":{"type":"string","enum":["ap","prepaid"]},"balance":{"allOf":[{"$ref":"#/components/schemas/Money"}],"description":"Prepaid credit remaining with this supplier (prepaid settlement)"},"smsDeliveryMethod":{"type":"string","enum":["http","smpp"],"nullable":true},"reachable":{"type":"boolean","nullable":true},"reachCheckedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"pendingChange":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"fields":{"type":"array","items":{"type":"string"}},"status":{"type":"string"}},"required":["id","fields","status"]}},"required":["id","supplierId","label","source","status","sipHost","sipPort","transport","techPrefix","sipAuthUsername","sipAuthPasswordSet","smppPasswordSet","mediaMode","defaultRatePerUnit","billingIncrement","currency","capacity","maxCps","settlementMode","balance","smsDeliveryMethod","reachable","reachCheckedAt","createdAt","updatedAt"],"additionalProperties":true,"description":"A supplier (vendor) trunk. Carries every spec section-4 policy field accepted on create/update; secrets are replaced by *Set booleans."}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":160},"supplierId":{"type":"string","format":"uuid","nullable":true},"sipHost":{"type":"string","maxLength":255,"nullable":true},"sipPort":{"type":"integer","minimum":1,"maximum":65535,"nullable":true},"transport":{"type":"string","enum":["udp","tcp","tls"],"nullable":true},"techPrefix":{"type":"string","maxLength":24,"nullable":true},"sipAuthUsername":{"type":"string","maxLength":128,"nullable":true},"sipAuthPassword":{"type":"string","maxLength":128,"nullable":true},"supportedCodecs":{"type":"array","items":{"type":"string","maxLength":24},"maxItems":16,"nullable":true},"defaultRatePerUnit":{"type":"number","minimum":0,"nullable":true},"mediaMode":{"type":"string","enum":["proxy","direct"]},"billingIncrement":{"type":"string","maxLength":10,"nullable":true},"currency":{"type":"string","minLength":3,"maxLength":3,"nullable":true},"capacity":{"type":"integer","minimum":0,"nullable":true},"maxCps":{"type":"integer","minimum":0,"nullable":true},"status":{"type":"string","enum":["active","disabled","draft","testing","draining","fault"]},"settlementMode":{"type":"string","enum":["ap","prepaid"]},"balance":{"type":"number","minimum":0,"nullable":true},"portalEmail":{"type":"string","format":"email","maxLength":255,"nullable":true},"smsDeliveryUrl":{"type":"string","format":"uri","maxLength":500,"nullable":true},"smsDeliveryMethod":{"type":"string","enum":["http","smpp"],"nullable":true},"smppHost":{"type":"string","maxLength":255,"nullable":true},"smppPort":{"type":"integer","minimum":1,"maximum":65535,"nullable":true},"smppSystemId":{"type":"string","nullable":true},"smppPassword":{"type":"string","maxLength":64,"nullable":true},"smppBindType":{"type":"string","enum":["transceiver","transmitter"],"nullable":true},"smppSystemType":{"type":"string","maxLength":13,"nullable":true},"smppTps":{"type":"integer","minimum":1,"maximum":1000,"nullable":true},"code":{"type":"string","maxLength":40,"nullable":true},"description":{"type":"string","maxLength":2000,"nullable":true},"product":{"type":"string","maxLength":32,"nullable":true},"direction":{"type":"string","enum":["termination","origination","bidirectional"]},"testMode":{"type":"boolean"},"activationDate":{"type":"string","maxLength":10,"nullable":true},"expirationDate":{"type":"string","maxLength":10,"nullable":true},"tags":{"type":"array","items":{"type":"string","maxLength":40},"maxItems":20,"nullable":true},"notes":{"type":"string","maxLength":4000,"nullable":true},"credentialExpiresAt":{"type":"string","maxLength":40,"nullable":true},"credentialRotatedAt":{"type":"string","maxLength":40,"nullable":true},"allowedSourceNetworks":{"type":"array","items":{"type":"string","maxLength":64},"maxItems":64,"nullable":true},"requestRateLimit":{"type":"integer","minimum":0,"maximum":100000,"nullable":true},"sipRegister":{"type":"boolean"},"sipRealm":{"type":"string","maxLength":255,"nullable":true},"incomingTechPrefix":{"type":"string","maxLength":24,"nullable":true},"techPrefixMode":{"type":"string","enum":["add","remove","replace"]},"techPrefixSeparator":{"type":"string","maxLength":4,"nullable":true},"cliRewrite":{"nullable":true},"dnisRewrite":{"nullable":true},"cliPolicy":{"type":"string","enum":["passthrough","replace","remove","pool"]},"cliPoolId":{"type":"string","format":"uuid","nullable":true},"anonymousPolicy":{"type":"string","enum":["passthrough","reject","substitute"]},"e164Normalise":{"type":"boolean"},"dnisFormat":{"type":"string","enum":["plus","digits"],"nullable":true},"cliFormat":{"type":"string","enum":["plus","digits"],"nullable":true},"defaultCountryCode":{"type":"string","maxLength":6,"nullable":true},"minDnisLength":{"type":"integer","minimum":0,"maximum":32,"nullable":true},"maxDnisLength":{"type":"integer","minimum":0,"maximum":32,"nullable":true},"paiPolicy":{"type":"string","enum":["omit","passthrough","generate"]},"rpidPolicy":{"type":"string","enum":["omit","passthrough","generate"]},"diversionPolicy":{"type":"string","enum":["omit","passthrough","generate"]},"historyInfoPolicy":{"type":"string","enum":["omit","passthrough","generate"]},"lrnPolicy":{"type":"string","enum":["none","passthrough","strip"]},"packetizationMs":{"type":"integer","minimum":10,"maximum":120,"nullable":true},"codecMode":{"type":"string","enum":["transparent","transcode"]},"forcedCodec":{"type":"string","maxLength":24,"nullable":true},"srtpMode":{"type":"string","enum":["disabled","optional","required"]},"dtmfMode":{"type":"string","enum":["rfc2833","info","inband","auto"]},"t38Mode":{"type":"string","enum":["disabled","passthrough","relay"]},"comfortNoise":{"type":"boolean"},"silenceSuppression":{"type":"boolean"},"symmetricRtp":{"type":"boolean"},"inviteTimeoutSeconds":{"type":"integer","minimum":1,"maximum":600,"nullable":true},"pddTimeoutSeconds":{"type":"integer","minimum":1,"maximum":600,"nullable":true},"ringTimeoutSeconds":{"type":"integer","minimum":1,"maximum":600,"nullable":true},"sessionExpiresSeconds":{"type":"integer","minimum":90,"maximum":86400,"nullable":true},"minSeSeconds":{"type":"integer","minimum":90,"maximum":86400,"nullable":true},"prackMode":{"type":"string","enum":["disabled","supported","required"]},"allowReinvite":{"type":"boolean"},"allowUpdate":{"type":"boolean"},"allowRefer":{"type":"boolean"},"earlyMediaPolicy":{"type":"string","enum":["passthrough","generate_ringback","suppress"]},"recordRoute":{"type":"boolean"},"customHeaders":{"type":"object","additionalProperties":{"type":"string","maxLength":200},"nullable":true},"q850Map":{"type":"object","additionalProperties":{"type":"integer","minimum":0,"maximum":255},"nullable":true},"cpsBurst":{"type":"integer","minimum":0,"maximum":10000,"nullable":true},"queueLimit":{"type":"integer","minimum":0,"maximum":100000,"nullable":true},"maxChannelsPerDestination":{"type":"integer","minimum":0,"maximum":100000,"nullable":true},"maxCpsPerDestination":{"type":"integer","minimum":0,"maximum":10000,"nullable":true},"minCallSeconds":{"type":"integer","minimum":0,"maximum":86400,"nullable":true},"maxCallSeconds":{"type":"integer","minimum":0,"maximum":86400,"nullable":true},"dailyMinutesCap":{"type":"integer","minimum":0,"nullable":true},"dailySpendCap":{"anyOf":[{"type":"number"},{"type":"string"}],"nullable":true},"monthlySpendCap":{"anyOf":[{"type":"number"},{"type":"string"}],"nullable":true},"rampupChannels":{"type":"integer","minimum":0,"maximum":100000,"nullable":true},"rampupDays":{"type":"integer","minimum":0,"maximum":365,"nullable":true},"allowedPrefixes":{"type":"array","items":{"type":"string","maxLength":24},"maxItems":500,"nullable":true},"blockedPrefixes":{"type":"array","items":{"type":"string","maxLength":24},"maxItems":500,"nullable":true},"allowedCountries":{"type":"array","items":{"type":"string","maxLength":4},"maxItems":300,"nullable":true},"blockedCountries":{"type":"array","items":{"type":"string","maxLength":4},"maxItems":300,"nullable":true},"allowMobile":{"type":"boolean"},"allowFixed":{"type":"boolean"},"allowSatellite":{"type":"boolean"},"allowPremium":{"type":"boolean"},"allowTollfree":{"type":"boolean"},"allowEmergency":{"type":"boolean"},"jurisdictionPolicy":{"type":"string","enum":["any","interstate","intrastate","local"]},"schedule":{"type":"array","items":{"type":"object","properties":{"days":{"type":"array","items":{"type":"integer","minimum":1,"maximum":7},"maxItems":7},"from":{"type":"string","maxLength":5},"to":{"type":"string","maxLength":5},"tz":{"type":"string","maxLength":64}},"required":["days","from","to","tz"]},"maxItems":20,"nullable":true},"maintenanceWindows":{"type":"array","items":{"type":"object","properties":{"from":{"type":"string","maxLength":40},"to":{"type":"string","maxLength":40},"note":{"type":"string","maxLength":200}},"required":["from","to"]},"maxItems":50,"nullable":true},"routingEnabled":{"type":"boolean"},"lcrEligible":{"type":"boolean"},"qualityEligible":{"type":"boolean"},"popRegion":{"type":"string","maxLength":40,"nullable":true},"allowedCustomerGroups":{"type":"array","items":{"type":"string","maxLength":40},"maxItems":50,"nullable":true},"allowedProducts":{"type":"array","items":{"type":"string","maxLength":40},"maxItems":50,"nullable":true},"minMarginPct":{"anyOf":[{"type":"number"},{"type":"string"}],"nullable":true},"minMarginAbs":{"anyOf":[{"type":"number"},{"type":"string"}],"nullable":true},"maxBuyRate":{"anyOf":[{"type":"number"},{"type":"string"}],"nullable":true},"overflowTrunkId":{"type":"string","format":"uuid","nullable":true},"retryableSipCodes":{"type":"array","items":{"type":"integer","minimum":100,"maximum":699},"maxItems":60,"nullable":true},"terminalSipCodes":{"type":"array","items":{"type":"integer","minimum":100,"maximum":699},"maxItems":60,"nullable":true},"retryPolicy":{"type":"string","enum":["same_endpoint","next_endpoint","next_trunk"]},"maxAttemptsPerCall":{"type":"integer","minimum":1,"maximum":10,"nullable":true},"qosThresholds":{"type":"object","properties":{"asrMin":{"type":"number","minimum":0,"maximum":100},"acdMin":{"type":"number","minimum":0,"maximum":86400},"nerMin":{"type":"number","minimum":0,"maximum":100},"pddMaxMs":{"type":"integer","minimum":0,"maximum":600000},"mosMin":{"type":"number","minimum":1,"maximum":5},"shortCallMaxPct":{"type":"number","minimum":0,"maximum":100},"minCalls":{"type":"integer","minimum":1,"maximum":1000000},"windowMinutes":{"type":"integer","minimum":5,"maximum":10080},"action":{"type":"string","enum":["alert","demote","reduce_cps","block_destination","disable_trunk"]},"mode":{"type":"string","enum":["observe","enforce"]}},"nullable":true},"fraudControls":{"type":"object","properties":{"shortCallSeconds":{"type":"integer","minimum":1,"maximum":3600},"longCallSeconds":{"type":"integer","minimum":1,"maximum":86400},"duplicateDetect":{"type":"boolean"},"spikeMultiple":{"type":"number","minimum":1.1,"maximum":1000},"spendVelocityPerHour":{"type":"number","minimum":0,"maximum":1000000},"highCostRate":{"type":"number","minimum":0,"maximum":10000},"action":{"type":"string","enum":["alert","demote","reduce_cps","block_destination","disable_trunk"]},"mode":{"type":"string","enum":["observe","enforce"]}},"nullable":true}}}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"label":"Acme","supplierId":"<supplierId>"}}},"delete":{"operationId":"deleteSwitchSuppliersById","tags":["Switch: suppliers"],"summary":"Delete a supplier trunk","description":"Works for a trunk under a provider and for an ungrouped trunk alike. Route group entries that use it are removed; call records are kept.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"deleted":{"type":"boolean","enum":[true]}},"required":["deleted"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/trunk-changes":{"get":{"operationId":"getSwitchTrunkChanges","tags":["Switch: customer trunks"],"summary":"List trunk configuration changes awaiting or after review","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/SwitchTrunkChangeRequest"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"trunkId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"status","in":"query","required":false,"description":"Comma-separated statuses, e.g. pending,approved","schema":{"type":"string"}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/switch/trunk-changes/{id}/approve":{"post":{"operationId":"postSwitchTrunkChangesByIdApprove","tags":["Switch: customer trunks"],"summary":"Approve and apply a trunk configuration change","description":"`applied` is the trunk after the change, redacted like every trunk read (`sipAuthPasswordSet` / `smppPasswordSet` instead of the secrets). `driftedSinceRequest` lists fields that changed on the trunk after the request was made.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"applied":{"type":"object","properties":{},"additionalProperties":true},"driftedSinceRequest":{"type":"array","items":{"type":"string"}}},"required":["applied","driftedSinceRequest"],"additionalProperties":true}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"note":{"type":"string"}}}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"note":"Example"}}}},"/api/v1/switch/trunk-changes/{id}/reject":{"post":{"operationId":"postSwitchTrunkChangesByIdReject","tags":["Switch: customer trunks"],"summary":"Reject a trunk configuration change","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"rejected":{"type":"boolean","enum":[true]}},"required":["rejected"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"note":{"type":"string"}}}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"note":"Example"}}}},"/api/v1/switch/trunk-changes/{id}/withdraw":{"post":{"operationId":"postSwitchTrunkChangesByIdWithdraw","tags":["Switch: customer trunks"],"summary":"Withdraw your own pending trunk change","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"withdrawn":{"type":"boolean","enum":[true]}},"required":["withdrawn"],"additionalProperties":true}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/trunk-approval-setting":{"get":{"operationId":"getSwitchTrunkApprovalSetting","tags":["Switch: customer trunks"],"summary":"Get whether supplier trunk changes need approval","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"requireTrunkApproval":{"type":"boolean"}},"required":["requireTrunkApproval"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}},"post":{"operationId":"postSwitchTrunkApprovalSetting","tags":["Switch: customer trunks"],"summary":"Turn supplier trunk change approval on or off","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"requireTrunkApproval":{"type":"boolean"}},"required":["requireTrunkApproval"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"requireTrunkApproval":{"type":"boolean"}},"required":["requireTrunkApproval"]}}}},"x-px-example":{"path":{},"query":{},"body":{"requireTrunkApproval":true}}}},"/api/v1/switch/suppliers/{id}/readiness":{"get":{"operationId":"getSwitchSuppliersByIdReadiness","tags":["Switch: suppliers"],"summary":"Get the production readiness checklist for a supplier trunk","description":"A pure read: it reports and never blocks. Bundle carriage trunks come back exempt with no checks.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchTrunkReadiness"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/trunk-readiness-setting":{"get":{"operationId":"getSwitchTrunkReadinessSetting","tags":["Switch: customer trunks"],"summary":"Get whether trunk readiness blocks first activation","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"requireTrunkReadiness":{"type":"boolean"}},"required":["requireTrunkReadiness"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}},"post":{"operationId":"postSwitchTrunkReadinessSetting","tags":["Switch: customer trunks"],"summary":"Turn the trunk readiness gate on or off","description":"When on, it can refuse only the first-ever activation of a new trunk; existing trunks are grandfathered and bundle trunks are exempt.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"requireTrunkReadiness":{"type":"boolean"}},"required":["requireTrunkReadiness"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"requireTrunkReadiness":{"type":"boolean"}},"required":["requireTrunkReadiness"]}}}},"x-px-example":{"path":{},"query":{},"body":{"requireTrunkReadiness":true}}}},"/api/v1/switch/suppliers/{id}/config-history":{"get":{"operationId":"getSwitchSuppliersByIdConfigHistory","tags":["Switch: suppliers"],"summary":"List configuration versions of a supplier trunk","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/SwitchTrunkConfigVersion"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/suppliers/{id}/config-history/{versionId}":{"get":{"operationId":"getSwitchSuppliersByIdConfigHistoryByVersionId","tags":["Switch: suppliers"],"summary":"Get one configuration version of a supplier trunk","description":"The full snapshot as of that version, plus the previous version snapshot for comparison.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"version":{"type":"integer"},"source":{"type":"string","description":"Which door the change came through, e.g. update, approval, api"},"changedFields":{"type":"array","items":{"type":"string"}},"diff":{"type":"object","additionalProperties":{"type":"object","properties":{"from":{},"to":{}}},"nullable":true},"note":{"type":"string","nullable":true},"checksum":{"type":"string","nullable":true},"changeRequestId":{"type":"string","format":"uuid","nullable":true},"actorUserId":{"type":"string","format":"uuid","nullable":true},"actorEmail":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"snapshot":{"type":"object","additionalProperties":{}},"previous":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"version":{"type":"integer"},"snapshot":{"type":"object","additionalProperties":{}},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","version","snapshot","createdAt"],"nullable":true}},"required":["id","version","source","changedFields","diff","note","checksum","changeRequestId","actorUserId","createdAt","snapshot","previous"],"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"versionId","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>","versionId":"<versionId>"},"query":{}}}},"/api/v1/switch/acls":{"get":{"operationId":"getSwitchAcls","tags":["Switch: routing"],"summary":"List inbound IP ACLs for a customer or trunk","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/SwitchIpAcl"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"entityType","in":"query","required":false,"schema":{"type":"string","enum":["customer","trunk"]}},{"name":"entityId","in":"query","required":true,"description":"The customer or trunk id","schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{},"query":{"entityId":"<entityId>"}}},"post":{"operationId":"postSwitchAcls","tags":["Switch: routing"],"summary":"Add an inbound IP ACL entry","description":"Authorises an address or CIDR for a customer (IP authentication) or a trunk (identity).\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchIpAcl"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"entityType":{"type":"string","enum":["customer","trunk"]},"entityId":{"type":"string","format":"uuid"},"cidr":{"type":"string","minLength":1,"maxLength":64},"description":{"type":"string","maxLength":160,"nullable":true}},"required":["entityType","entityId","cidr"]}}}},"x-px-example":{"path":{},"query":{},"body":{"entityType":"customer","entityId":"<entityId>","cidr":"<cidr>"}}}},"/api/v1/switch/acls/{id}":{"delete":{"operationId":"deleteSwitchAclsById","tags":["Switch: routing"],"summary":"Remove an inbound IP ACL entry","description":"Removing a customer address stops calls from that address immediately.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"deleted":{"type":"boolean","enum":[true]}},"required":["deleted"],"additionalProperties":true}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/inherited-defaults":{"get":{"operationId":"getSwitchInheritedDefaults","tags":["Switch: rating"],"summary":"Show what a blank rating or limit field inherits","description":"Your operator defaults, the platform fallbacks, and the inheritance chain for each field in plain words.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"operator":{"type":"object","properties":{"markupPct":{"type":"number","nullable":true},"dailySpendCap":{"type":"number","nullable":true,"description":"USD, a JSON number"},"maxConcurrentCalls":{"type":"number","nullable":true},"billingIncrement":{"type":"string","nullable":true}},"required":["markupPct","dailySpendCap","maxConcurrentCalls","billingIncrement"]},"platform":{"type":"object","properties":{"billingIncrement":{"type":"string","enum":["1/1"]},"maxConcurrentCalls":{"enum":["null"],"nullable":true},"maxCps":{"enum":["null"],"nullable":true}},"required":["billingIncrement","maxConcurrentCalls","maxCps"]},"chains":{"type":"object","additionalProperties":{"type":"string"},"description":"Field name -> how a blank resolves"}},"required":["operator","platform","chains"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/switch/sell-decks":{"get":{"operationId":"getSwitchSellDecks","tags":["Switch: rating"],"summary":"List sell decks","description":"Every version of every sell deck, with how many customers and trunks each one reaches.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"decks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"version":{"type":"integer"},"status":{"type":"string","enum":["draft","active","superseded","archived"]},"currency":{"type":"string","minLength":3,"maxLength":3},"isSystemDefault":{"type":"boolean"},"defaultRatePerUnit":{"type":"number","nullable":true,"description":"Catch-all price for destinations the deck does not list (a JSON number)"},"charging":{"type":"object","properties":{"minimumDurationSeconds":{"type":"integer","nullable":true},"firstIntervalSeconds":{"type":"integer","nullable":true},"subsequentIntervalSeconds":{"type":"integer","nullable":true},"setupFee":{"type":"number","nullable":true,"description":"Per-call setup fee (a JSON number)"},"graceSeconds":{"type":"integer","nullable":true},"rounding":{"type":"string","enum":["up","nearest","down"],"nullable":true}},"required":["minimumDurationSeconds","firstIntervalSeconds","subsequentIntervalSeconds","setupFee","graceSeconds","rounding"]},"effectiveFrom":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"notes":{"type":"string","nullable":true},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"activeRates":{"type":"integer","description":"Rows in the deck"},"customersOnIt":{"type":"integer","description":"Customers whose default deck this is"},"trunksNamingIt":{"type":"integer","description":"Trunks that name this deck directly"}},"required":["id","name","version","status","currency","isSystemDefault","defaultRatePerUnit","charging","effectiveFrom","notes","updatedAt","activeRates","customersOnIt","trunksNamingIt"],"additionalProperties":true}}},"required":["decks"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["draft","active","superseded","archived"]}}],"x-px-example":{"path":{},"query":{}}},"post":{"operationId":"postSwitchSellDecks","tags":["Switch: rating"],"summary":"Create a sell deck","description":"Creates a draft (version 1, or the next version of an existing name). Load prices, then publish.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchSellDeck"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":160},"currency":{"type":"string","minLength":3,"maxLength":3},"defaultRatePerUnit":{"anyOf":[{"type":"number"},{"type":"string"}],"nullable":true,"description":"Catch-all price; null or \"\" clears it"},"minimumDurationSeconds":{"type":"integer","minimum":0,"maximum":3600,"nullable":true},"firstIntervalSeconds":{"type":"integer","minimum":1,"maximum":3600,"nullable":true,"description":"Set together with subsequentIntervalSeconds, or neither"},"subsequentIntervalSeconds":{"type":"integer","minimum":1,"maximum":3600,"nullable":true},"setupFee":{"anyOf":[{"type":"number"},{"type":"string"}],"nullable":true},"graceSeconds":{"type":"integer","minimum":0,"maximum":120,"nullable":true},"rounding":{"type":"string","enum":["up","nearest","down"],"nullable":true},"notes":{"type":"string","nullable":true},"effectiveFrom":{"type":"string","nullable":true,"description":"ISO timestamp"}},"required":["name"]}}}},"x-px-example":{"path":{},"query":{},"body":{"name":"Acme"}}}},"/api/v1/switch/sell-decks/{deckId}":{"get":{"operationId":"getSwitchSellDecksByDeckId","tags":["Switch: rating"],"summary":"Get a sell deck with its reach and versions","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"version":{"type":"integer"},"status":{"type":"string","enum":["draft","active","superseded","archived"]},"currency":{"type":"string","minLength":3,"maxLength":3},"isSystemDefault":{"type":"boolean"},"defaultRatePerUnit":{"type":"number","nullable":true,"description":"Catch-all price for destinations the deck does not list (a JSON number)"},"charging":{"type":"object","properties":{"minimumDurationSeconds":{"type":"integer","nullable":true},"firstIntervalSeconds":{"type":"integer","nullable":true},"subsequentIntervalSeconds":{"type":"integer","nullable":true},"setupFee":{"type":"number","nullable":true,"description":"Per-call setup fee (a JSON number)"},"graceSeconds":{"type":"integer","nullable":true},"rounding":{"type":"string","enum":["up","nearest","down"],"nullable":true}},"required":["minimumDurationSeconds","firstIntervalSeconds","subsequentIntervalSeconds","setupFee","graceSeconds","rounding"]},"effectiveFrom":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"notes":{"type":"string","nullable":true},"supersedesId":{"type":"string","format":"uuid","nullable":true},"approvedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"activeRates":{"type":"integer"},"customersDefaultingToIt":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"label":{"type":"string","nullable":true}},"required":["id","label"]}},"trunksNamingIt":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"label":{"type":"string","nullable":true},"subAccountId":{"type":"string","format":"uuid"}},"required":["id","label","subAccountId"]}},"versions":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"version":{"type":"integer"},"status":{"type":"string","enum":["draft","active","superseded","archived"]},"effectiveFrom":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","version","status","effectiveFrom","createdAt"]}}},"required":["id","name","version","status","currency","isSystemDefault","defaultRatePerUnit","charging","effectiveFrom","notes","supersedesId","approvedAt","createdAt","updatedAt","activeRates","customersDefaultingToIt","trunksNamingIt","versions"],"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"deckId","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"deckId":"<deckId>"},"query":{}}},"patch":{"operationId":"patchSwitchSellDecksByDeckId","tags":["Switch: rating"],"summary":"Update a sell deck's name, notes or charging profile","description":"Superseded and archived decks cannot change. Changing the charging profile of an ACTIVE deck reprices every trunk on it from the next call, and is logged as a warning.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchSellDeck"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"deckId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":160},"currency":{"type":"string","minLength":3,"maxLength":3},"defaultRatePerUnit":{"anyOf":[{"type":"number"},{"type":"string"}],"nullable":true,"description":"Catch-all price; null or \"\" clears it"},"minimumDurationSeconds":{"type":"integer","minimum":0,"maximum":3600,"nullable":true},"firstIntervalSeconds":{"type":"integer","minimum":1,"maximum":3600,"nullable":true,"description":"Set together with subsequentIntervalSeconds, or neither"},"subsequentIntervalSeconds":{"type":"integer","minimum":1,"maximum":3600,"nullable":true},"setupFee":{"anyOf":[{"type":"number"},{"type":"string"}],"nullable":true},"graceSeconds":{"type":"integer","minimum":0,"maximum":120,"nullable":true},"rounding":{"type":"string","enum":["up","nearest","down"],"nullable":true},"notes":{"type":"string","nullable":true},"effectiveFrom":{"type":"string","nullable":true,"description":"ISO timestamp"}}}}}},"x-px-example":{"path":{"deckId":"<deckId>"},"query":{},"body":{"name":"Acme","currency":"USD"}}}},"/api/v1/switch/sell-decks/{deckId}/rates":{"get":{"operationId":"getSwitchSellDecksByDeckIdRates","tags":["Switch: rating"],"summary":"List the prices in a sell deck","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"rows":{"type":"array","items":{"$ref":"#/components/schemas/SwitchSellDeckRow"}},"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"}},"required":["rows","total","limit","offset"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"deckId","in":"path","required":true,"schema":{"type":"string"}},{"name":"search","in":"query","required":false,"description":"Prefix search (digits)","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Default 100, max 1000","schema":{"type":"integer","minimum":1,"maximum":1000}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0}}],"x-px-example":{"path":{"deckId":"<deckId>"},"query":{}}},"post":{"operationId":"postSwitchSellDecksByDeckIdRates","tags":["Switch: rating"],"summary":"Replace the prices in a draft sell deck","description":"Up to 200,000 rows, replacing whatever the draft held (last row wins per prefix and origin). Published decks are never overwritten; open a new version instead.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"loaded":{"type":"integer"}},"required":["loaded"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"deckId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"rows":{"type":"array","items":{"type":"object","properties":{"prefix":{"type":"string","maxLength":24},"rate":{"anyOf":[{"type":"number"},{"type":"string"}],"description":"A blank is refused; 0 is a real price"},"origin":{"type":"string","maxLength":24,"nullable":true},"billingIncrement":{"type":"string","nullable":true,"description":"\"first/subsequent\", e.g. 60/60; anything else is stored as inherit"}},"required":["prefix","rate"]}}},"required":["rows"]}}}},"x-px-example":{"path":{"deckId":"<deckId>"},"query":{},"body":{"rows":[{"prefix":"44","rate":1}]}}}},"/api/v1/switch/sell-decks/{deckId}/versions":{"post":{"operationId":"postSwitchSellDecksByDeckIdVersions","tags":["Switch: rating"],"summary":"Open a new draft version of a sell deck","description":"Copies the deck's charging profile and prices into version n+1 as a draft. Publishing it is what moves prices.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"version":{"type":"integer"},"status":{"type":"string","enum":["draft","active","superseded","archived"]},"currency":{"type":"string","minLength":3,"maxLength":3},"isSystemDefault":{"type":"boolean"},"defaultRatePerUnit":{"type":"number","nullable":true,"description":"Catch-all price for destinations the deck does not list (a JSON number)"},"charging":{"type":"object","properties":{"minimumDurationSeconds":{"type":"integer","nullable":true},"firstIntervalSeconds":{"type":"integer","nullable":true},"subsequentIntervalSeconds":{"type":"integer","nullable":true},"setupFee":{"type":"number","nullable":true,"description":"Per-call setup fee (a JSON number)"},"graceSeconds":{"type":"integer","nullable":true},"rounding":{"type":"string","enum":["up","nearest","down"],"nullable":true}},"required":["minimumDurationSeconds","firstIntervalSeconds","subsequentIntervalSeconds","setupFee","graceSeconds","rounding"]},"copiedRates":{"type":"integer"}},"required":["id","name","version","status","currency","isSystemDefault","defaultRatePerUnit","charging","copiedRates"],"additionalProperties":true}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"deckId","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"deckId":"<deckId>"},"query":{}}}},"/api/v1/switch/sell-decks/{deckId}/publish":{"post":{"operationId":"postSwitchSellDecksByDeckIdPublish","tags":["Switch: rating"],"summary":"Publish a sell deck (preview first, then confirm)","description":"Without `confirm: true` this only reports whose prices would change and writes nothing. With it, the deck becomes active, the previous version is superseded, and its prices are written onto every trunk that resolves to it, from the next call onward.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"anyOf":[{"type":"object","properties":{"published":{"type":"boolean","enum":[false]},"wouldChange":{"type":"object","properties":{"rates":{"type":"integer"},"trunks":{"type":"integer"},"message":{"type":"string"}},"required":["rates","trunks","message"]}},"required":["published","wouldChange"]},{"type":"object","properties":{"published":{"type":"boolean","enum":[true]},"trunks":{"type":"integer"},"rowsWritten":{"type":"integer"},"rowsSuperseded":{"type":"integer"}},"required":["published","trunks","rowsWritten","rowsSuperseded"]}]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"deckId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"confirm":{"type":"boolean"}}}}}},"x-px-example":{"path":{"deckId":"<deckId>"},"query":{},"body":{"confirm":true}}}},"/api/v1/switch/sell-decks/system-default":{"post":{"operationId":"postSwitchSellDecksSystemDefault","tags":["Switch: rating"],"summary":"Set or clear the system default sell deck","description":"The deck used by trunks set to \"system default\". Only an active deck qualifies; send `deckId: null` to clear it.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"systemDefaultDeckId":{"type":"string","format":"uuid","nullable":true}},"required":["systemDefaultDeckId"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"deckId":{"type":"string","format":"uuid","nullable":true}}}}}},"x-px-example":{"path":{},"query":{},"body":{"deckId":"<deckId>"}}}},"/api/v1/switch/customers/{id}/sell-deck":{"get":{"operationId":"getSwitchCustomersByIdSellDeck","tags":["Switch: customers"],"summary":"Get a Switch customer default sell deck and each trunk's deck","description":"An unknown customer answers 404 NOT_FOUND.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"customerId":{"type":"string","format":"uuid"},"customerLabel":{"type":"string"},"defaultDeck":{"allOf":[{"$ref":"#/components/schemas/SwitchCustomerSellDeckRef"}],"nullable":true},"systemDefault":{"allOf":[{"$ref":"#/components/schemas/SwitchCustomerSellDeckRef"}],"nullable":true},"trunks":{"type":"array","items":{"type":"object","properties":{"effective":{"$ref":"#/components/schemas/SwitchTrunkEffectiveSellDeck"}},"required":["effective"],"additionalProperties":true}},"trunksDisagree":{"type":"boolean"}},"required":["customerId","customerLabel","defaultDeck","systemDefault","trunks","trunksDisagree"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}},"put":{"operationId":"putSwitchCustomersByIdSellDeck","tags":["Switch: customers"],"summary":"Set a Switch customer default sell deck","description":"Without `confirm: true` nothing changes: the response lists the trunks whose prices would change. With it, the deck is assigned and trunks that follow the customer default reprice from the next call.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"anyOf":[{"type":"object","properties":{"changed":{"type":"boolean","enum":[false]},"wouldChange":{"type":"object","properties":{"trunks":{"type":"array","items":{"type":"string"}},"message":{"type":"string"}},"required":["trunks","message"]}},"required":["changed","wouldChange"]},{"type":"object","properties":{"changed":{"type":"boolean","enum":[true]},"trunks":{"type":"integer"}},"required":["changed","trunks"]}]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"deckId":{"type":"string","format":"uuid","nullable":true,"description":"null clears the default"},"confirm":{"type":"boolean"},"reason":{"type":"string"}}}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"deckId":"<deckId>","confirm":true}}}},"/api/v1/switch/customer-trunks/{trunkId}/sell-deck":{"get":{"operationId":"getSwitchCustomerTrunksByTrunkIdSellDeck","tags":["Switch: customer trunks"],"summary":"Get the sell deck in force on a trunk","description":"The resolved deck, plus the customer and system defaults it did not pick, and a sentence saying which won.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchTrunkEffectiveSellDeck"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"trunkId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"trunkId":"<trunkId>"},"query":{}}},"put":{"operationId":"putSwitchCustomerTrunksByTrunkIdSellDeck","tags":["Switch: customer trunks"],"summary":"Assign a sell deck to a trunk","description":"Without `confirm: true` nothing changes and the response shows what would be in force. With it, the trunk reprices from the next call.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"anyOf":[{"type":"object","properties":{"changed":{"type":"boolean","enum":[false]},"before":{"$ref":"#/components/schemas/SwitchTrunkEffectiveSellDeck"},"wouldBe":{"type":"object","properties":{"mode":{"type":"string"},"deck":{"allOf":[{"$ref":"#/components/schemas/SwitchCustomerSellDeckRef"}],"nullable":true},"rates":{},"bypassesCustomerDefault":{"type":"boolean"},"warning":{"type":"string","nullable":true},"defaultRate":{"type":"number","nullable":true},"unlistedDestinations":{"type":"string"}},"required":["mode","deck","bypassesCustomerDefault","warning","defaultRate","unlistedDestinations"]}},"required":["changed","before","wouldBe"]},{"type":"object","properties":{"changed":{"type":"boolean","enum":[true]},"before":{"$ref":"#/components/schemas/SwitchTrunkEffectiveSellDeck"},"after":{"$ref":"#/components/schemas/SwitchTrunkEffectiveSellDeck"}},"required":["changed","before","after"]}]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"trunkId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"mode":{"type":"string","enum":["customer_default","system_default","deck","none"],"description":"How a trunk picks its sell deck"},"deckId":{"type":"string","format":"uuid","nullable":true},"confirm":{"type":"boolean"},"reason":{"type":"string"}},"required":["mode"]}}}},"x-px-example":{"path":{"trunkId":"<trunkId>"},"query":{},"body":{"mode":"customer_default"}}}},"/api/v1/switch/customer-trunks/{trunkId}/sell-deck/preview":{"get":{"operationId":"getSwitchCustomerTrunksByTrunkIdSellDeckPreview","tags":["Switch: customer trunks"],"summary":"Preview a sell-deck assignment for a trunk","description":"What would be in force under a mode, computed by the same resolver. Writes nothing.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"mode":{"type":"string"},"deck":{"allOf":[{"$ref":"#/components/schemas/SwitchCustomerSellDeckRef"}],"nullable":true},"rates":{},"bypassesCustomerDefault":{"type":"boolean"},"warning":{"type":"string","nullable":true},"defaultRate":{"type":"number","nullable":true},"unlistedDestinations":{"type":"string"}},"required":["mode","deck","bypassesCustomerDefault","warning","defaultRate","unlistedDestinations"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"trunkId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"mode","in":"query","required":false,"description":"Default customer_default","schema":{"type":"string","enum":["customer_default","system_default","deck","none"]}},{"name":"deckId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"trunkId":"<trunkId>"},"query":{}}}},"/api/v1/switch/entity-counts":{"get":{"operationId":"getSwitchEntityCounts","tags":["Switch"],"summary":"Count customers, trunks, suppliers and other Switch records","description":"Headline counts for the Switch overview and navigation.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","additionalProperties":{}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/switch/customers/{id}/portal-invite":{"post":{"operationId":"postSwitchCustomersByIdPortalInvite","tags":["Switch: customers"],"summary":"Email a Switch customer a portal sign-in link","description":"Sends a magic sign-in link to the customer's portal email. With no portal email set it answers 400 VALIDATION_ERROR.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Rate limit:** 20 requests per hour per caller.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"sent":{"type":"boolean","enum":[true]},"to":{"type":"string"}},"required":["sent","to"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-rate-limit":{"max":20,"window":"hour"},"x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}},"x-px-billable":{"kind":"email","note":"Sends an email to a third party."}}},"/api/v1/switch/suppliers/{id}/test-sms":{"post":{"operationId":"postSwitchSuppliersByIdTestSms","tags":["Switch: suppliers"],"summary":"Test a supplier trunk SMS delivery","description":"SMPP performs a real bind with the stored credentials and sends nothing; HTTP can only be checked for a well-formed https URL.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Rate limit:** 20 requests per minute per caller.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchSmsEndpointTest"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-rate-limit":{"max":20,"window":"minute"},"x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}},"x-px-billable":{"kind":"traffic","note":"Places a real test call or sends a real test SMS over the trunk."}}},"/api/v1/switch/suppliers/test-sms":{"post":{"operationId":"postSwitchSuppliersTestSms","tags":["Switch: suppliers"],"summary":"Test unsaved SMS delivery details","description":"For the create form. SMPP performs a real bind and sends nothing; HTTP can only be checked for a well-formed https URL. The password is used for this one handshake and never stored.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Rate limit:** 20 requests per minute per caller.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchSmsEndpointTest"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-rate-limit":{"max":20,"window":"minute"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"smsDeliveryMethod":{"type":"string","enum":["http","smpp"],"nullable":true},"smsDeliveryUrl":{"type":"string","maxLength":500,"nullable":true},"smppHost":{"type":"string","maxLength":255,"nullable":true},"smppPort":{"type":"integer","minimum":1,"maximum":65535,"nullable":true},"smppSystemId":{"type":"string","maxLength":16,"nullable":true,"description":"Short account code the supplier issued (max 16 chars). An email address is rejected."},"smppPassword":{"type":"string","maxLength":64,"nullable":true},"smppBindType":{"type":"string","enum":["transceiver","transmitter"],"nullable":true},"smppSystemType":{"type":"string","maxLength":13,"nullable":true},"smppTps":{"type":"integer","minimum":1,"maximum":1000,"nullable":true}}}}}},"x-px-example":{"path":{},"query":{},"body":{"smsDeliveryMethod":"http","smsDeliveryUrl":"<smsDeliveryUrl>"}},"x-px-billable":{"kind":"traffic","note":"Places a real test call or sends a real test SMS over the trunk."}}},"/api/v1/switch/suppliers/{id}/portal-invite":{"post":{"operationId":"postSwitchSuppliersByIdPortalInvite","tags":["Switch: suppliers"],"summary":"Email a supplier portal sign-in link","description":"Sends a magic link to the trunk `portalEmail`. When no portal email is set it answers 400 VALIDATION_ERROR.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Rate limit:** 20 requests per hour per caller.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"sent":{"type":"boolean","enum":[true]},"to":{"type":"string"}},"required":["sent","to"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-rate-limit":{"max":20,"window":"hour"},"x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}},"x-px-billable":{"kind":"email","note":"Sends an email to a third party."}}},"/api/v1/switch/rate-lookup":{"get":{"operationId":"getSwitchRateLookup","tags":["Switch: rating"],"summary":"Look up the buy and sell price for a destination","description":"Read-only. The buy side needs a supplier `trunkId`; the sell side is resolved for the customer or customer trunk named (or your own sell rates). Each side is a rating outcome, so \"no matching rate\" is distinguishable from a price of 0. `margin` is present only when both sides are rated.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"destination":{"type":"string"},"origin":{"type":"string","nullable":true},"buy":{"allOf":[{"$ref":"#/components/schemas/SwitchRatingOutcome"}],"nullable":true,"description":"null when no trunkId was given"},"sell":{"$ref":"#/components/schemas/SwitchRatingOutcome"},"margin":{"type":"number","nullable":true,"description":"sell minus buy per minute, a JSON number; null unless both are rated"},"at":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["destination","origin","buy","sell","margin","at"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"destination","in":"query","required":true,"schema":{"type":"string","minLength":1,"maxLength":32}},{"name":"trunkId","in":"query","required":false,"description":"Supplier trunk for the buy side","schema":{"type":"string","format":"uuid"}},{"name":"customerId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"customerTrunkId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"origin","in":"query","required":false,"description":"Caller number, for origin-based rates","schema":{"type":"string","maxLength":32}}],"x-px-example":{"path":{},"query":{"destination":"+447700900123"}}}},"/api/v1/switch/sell-rates":{"get":{"operationId":"getSwitchSellRates","tags":["Switch: rating"],"summary":"List your operator sell rates","description":"The operator-wide A-Z sell rates, by prefix.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"rows":{"type":"array","items":{"$ref":"#/components/schemas/SwitchSellRate"}},"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"}},"required":["rows","total","limit","offset"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"search","in":"query","required":false,"description":"Prefix search (digits)","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Default 100, max 1000","schema":{"type":"integer","minimum":1,"maximum":1000}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0}}],"x-px-example":{"path":{},"query":{}}},"post":{"operationId":"postSwitchSellRates","tags":["Switch: rating"],"summary":"Add or update one operator sell rate","description":"Upserts by prefix and origin. Emits the sell_rate.changed webhook.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchSellRate"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"prefix":{"type":"string","minLength":1,"maxLength":24},"rate":{"type":"number","minimum":0,"description":"Price per minute, as a JSON number"},"origin":{"type":"string","maxLength":24},"billingIncrement":{"type":"string","maxLength":10,"description":"e.g. 60/60 or 1/1; omit to inherit the trunk default"}},"required":["prefix","rate"]}}}},"x-px-example":{"path":{},"query":{},"body":{"prefix":"44","rate":1}}}},"/api/v1/switch/sell-rates/bulk":{"post":{"operationId":"postSwitchSellRatesBulk","tags":["Switch: rating"],"summary":"Add or update operator sell rates in bulk","description":"Up to 50,000 rows in one transaction; the last row wins per prefix and origin. Emits one sell_rate.changed webhook.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"applied":{"type":"integer"}},"required":["applied"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"rows":{"type":"array","items":{"type":"object","properties":{"prefix":{"type":"string","maxLength":24},"rate":{"type":"number","minimum":0,"description":"Price per minute, as a JSON number"},"origin":{"type":"string","maxLength":24},"billingIncrement":{"type":"string","maxLength":10,"description":"e.g. 60/60 or 1/1; omit to inherit the trunk default"}},"required":["prefix","rate"]},"maxItems":50000}},"required":["rows"]}}}},"x-px-example":{"path":{},"query":{},"body":{"rows":[{"prefix":"44","rate":1}]}}}},"/api/v1/switch/sell-rates/{id}":{"delete":{"operationId":"deleteSwitchSellRatesById","tags":["Switch: rating"],"summary":"Delete an operator sell rate","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"deleted":{"type":"boolean","enum":[true]}},"required":["deleted"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/sell-rates/clear":{"post":{"operationId":"postSwitchSellRatesClear","tags":["Switch: rating"],"summary":"Clear operator sell rates","description":"Deletes the listed prefixes, or EVERY operator sell rate when `prefixes` is omitted.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"deleted":{"type":"integer"}},"required":["deleted"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"prefixes":{"type":"array","items":{"type":"string","maxLength":24}}}}}}},"x-px-example":{"path":{},"query":{},"body":{"prefixes":["<prefixe>"]}}}},"/api/v1/switch/customers/{id}/sell-rates":{"get":{"operationId":"getSwitchCustomersByIdSellRates","tags":["Switch: customers"],"summary":"List a Switch customer sell rates with buy cost and margin","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchCustomerSellRatePage"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"search","in":"query","required":false,"description":"Prefix or destination text","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer"}},{"name":"view","in":"query","required":false,"description":"Default current","schema":{"type":"string","enum":["current","scheduled","discontinued","expiring","all"]}},{"name":"origin","in":"query","required":false,"schema":{"type":"string","enum":["any","origin_only","destination_only"]}},{"name":"increment","in":"query","required":false,"schema":{"type":"string","enum":["any","custom","inherited"]}},{"name":"cost","in":"query","required":false,"schema":{"type":"string","enum":["any","missing"]}},{"name":"margin","in":"query","required":false,"schema":{"type":"string","enum":["any","thin","negative"]}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}},"post":{"operationId":"postSwitchCustomersByIdSellRates","tags":["Switch: customers"],"summary":"Add or replace one Switch customer sell rate","description":"Takes effect now on the customer's default trunk. Use the per-trunk rate endpoints to price a specific trunk.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchCustomerSellRate"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"prefix":{"type":"string","minLength":1,"maxLength":24},"rate":{"type":"number","minimum":0,"description":"USD per minute"},"origin":{"type":"string","maxLength":24},"billingIncrement":{"type":"string","maxLength":10}},"required":["prefix","rate"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"prefix":"44","rate":1}}}},"/api/v1/switch/customers/{id}/sell-rates/counts":{"get":{"operationId":"getSwitchCustomersByIdSellRatesCounts","tags":["Switch: customers"],"summary":"Count a Switch customer sell rates by view","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"current":{"type":"integer"},"scheduled":{"type":"integer"},"expiring":{"type":"integer"},"discontinued":{"type":"integer"},"all":{"type":"integer"}},"required":["current","scheduled","expiring","discontinued","all"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/customers/{id}/sell-rates/upcoming":{"get":{"operationId":"getSwitchCustomersByIdSellRatesUpcoming","tags":["Switch: customers"],"summary":"List upcoming sell-rate starts and ends for a Switch customer","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"subAccountId":{"type":"string","format":"uuid"},"customerTrunkId":{"type":"string","format":"uuid","nullable":true},"prefix":{"type":"string"},"originPrefix":{"type":"string","description":"\"\" = any origin"},"ratePerUnit":{"allOf":[{"$ref":"#/components/schemas/Money"}],"description":"Sell price per minute, 6-decimal USD string"},"billingIncrement":{"type":"string","nullable":true},"status":{"type":"string","description":"active, pending (scheduled) or discontinued"},"effectiveFrom":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"endDate":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"kind":{"type":"string","enum":["starts","ends"]},"at":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true}},"required":["id","subAccountId","customerTrunkId","prefix","originPrefix","ratePerUnit","billingIncrement","status","effectiveFrom","endDate","kind","at"],"additionalProperties":true}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/customers/{id}/sell-rates/notice":{"get":{"operationId":"getSwitchCustomersByIdSellRatesNotice","tags":["Switch: customers"],"summary":"Get a Switch customer rate-change notice period and what is queued","description":"The notice period you give this customer before a sell-rate increase takes effect, how many sell-rate changes are queued behind it, and who a notice email would go to by default (commercial contacts, then billing contacts, then the portal email; at most 5). Needs the rates.view permission. An unknown customer, or one that is not yours, answers 404.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchCustomerRateNotice"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}},"put":{"operationId":"putSwitchCustomersByIdSellRatesNotice","tags":["Switch: customers"],"summary":"Set a Switch customer rate-change notice period","description":"With a notice period, a rise on any of this customer's prices (hand edit, bulk paste, sheet import, markup, sell-deck publish or assignment) is queued and takes effect that many days out, at the next 00:00 UTC; decreases and new destinations still apply at once. 0 = every change applies immediately. The new period applies to rises written from now on; changes already queued keep their dates. Needs the rates.publish permission; the change is audited. Send `X-If-Unchanged-Since: <updatedAt you loaded>` to have the save refused with 409 STALE_WRITE if someone changed the record since.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"rateNoticeDays":{"type":"integer","minimum":0,"maximum":365}},"required":["rateNoticeDays"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"rateNoticeDays":{"type":"integer","minimum":0,"maximum":365,"description":"Whole days of notice before an increase takes effect; 0 = none"}},"required":["rateNoticeDays"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"rateNoticeDays":1}}}},"/api/v1/switch/customers/{id}/sell-rates/notice/changes":{"get":{"operationId":"getSwitchCustomersByIdSellRatesNoticeChanges","tags":["Switch: customers"],"summary":"List a Switch customer queued sell-rate changes","description":"Every sell-rate change queued for this customer and not yet in effect, with the rate in force today beside it. Soonest first, then by prefix; at most 50,000 rows. The same rows as the CSV the customer receives.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/SwitchCustomerRateChange"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"trunkId","in":"query","required":false,"description":"Only this trunk's changes","schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/customers/{id}/sell-rates/notice/changes.csv":{"get":{"operationId":"getSwitchCustomersByIdSellRatesNoticeChangesCsv","tags":["Switch: customers"],"summary":"Download a Switch customer queued sell-rate changes as CSV","description":"The list from GET /switch/customers/{id}/sell-rates/notice/changes as the CSV the customer receives, for you to check or forward.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"An attachment named rate-changes-<customer id>.csv. Columns: trunk, prefix, origin, current_rate, new_rate, change_pct, current_increment, new_increment, effective_from_utc. current_rate is empty for a new destination.","content":{"text/csv":{"schema":{"type":"string","format":"binary"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"trunkId","in":"query","required":false,"description":"Only this trunk's changes","schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/customers/{id}/sell-rates/notice/send":{"post":{"operationId":"postSwitchCustomersByIdSellRatesNoticeSend","tags":["Switch: customers"],"summary":"Email a Switch customer a rate-change notice","description":"Emails the customer every queued change with its effective date: a table of the first 100 in the message and the full list (up to 5,000 rows) as CSV in the text part. The email is white-label: it is sent under your brand, replies go to your own support address, and it does not mention PacketExchange. Recipients are `to` when given (up to 10), otherwise the default recipients from GET .../sell-rates/notice. Answers 400 VALIDATION_ERROR when there are no queued changes, when `trunkId` is not one of this customer's trunks, or when there is no one to send to. A recipient the mail service refused is listed in `failed`, not raised as an error. Needs the rates.publish permission; the send is audited. Send `X-If-Unchanged-Since: <updatedAt you loaded>` to have the save refused with 409 STALE_WRITE if someone changed the record since.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"sent":{"type":"array","items":{"type":"string"},"description":"Addresses the notice was accepted for"},"failed":{"type":"array","items":{"type":"string"},"description":"Addresses the mail service refused"},"rows":{"type":"integer","description":"Changes in the notice"},"increases":{"type":"integer"},"decreases":{"type":"integer"},"added":{"type":"integer","description":"New destinations (no rate today)"},"firstEffectiveFrom":{"type":"string","format":"date-time","description":"The earliest effective date in the notice"}},"required":["sent","failed","rows","increases","decreases","added","firstEffectiveFrom"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"trunkId":{"type":"string","format":"uuid","nullable":true,"description":"Only this trunk's changes; omit for every trunk of the customer"},"to":{"type":"array","items":{"type":"string","format":"email","maxLength":254},"maxItems":10,"description":"Recipients; omit to use the default recipients"},"message":{"type":"string","maxLength":2000,"description":"A note of your own, added under the introduction"}}}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"trunkId":"<trunkId>","to":["you@example.com"]}},"x-px-billable":{"kind":"email","note":"Sends an email to a third party."}}},"/api/v1/switch/customers/{id}/sell-rates/discontinue-all/preview":{"post":{"operationId":"postSwitchCustomersByIdSellRatesDiscontinueAllPreview","tags":["Switch: customers"],"summary":"Preview discontinuing a Switch customer whole sell deck","description":"Omit the effective fields to act now. Send either `effectiveFrom` (an instant with an offset) or `effectiveLocal` plus `timezone`; a bare date is refused because midnight differs by country.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"customerLabel":{"type":"string"},"activeRates":{"type":"integer"},"scheduledRates":{"type":"integer"},"alreadyDiscontinued":{"type":"integer"},"endDate":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"immediate":{"type":"boolean"},"timezone":{"type":"string","nullable":true},"effectOnNewCalls":{"type":"string"},"minutes30d":{"type":"number"},"calls30d":{"type":"integer"},"revenue30d":{"type":"number","description":"US dollars as a JSON number (computed figure)"},"impactTruncated":{"type":"boolean"},"sample":{"type":"array","items":{"type":"object","properties":{"prefix":{"type":"string"},"originPrefix":{"type":"string"},"ratePerUnit":{"$ref":"#/components/schemas/Money"},"billingIncrement":{"type":"string","nullable":true}},"required":["prefix","originPrefix","ratePerUnit","billingIncrement"]}}},"required":["customerLabel","activeRates","scheduledRates","alreadyDiscontinued","endDate","immediate","timezone","effectOnNewCalls","minutes30d","calls30d","revenue30d","impactTruncated","sample"],"additionalProperties":true}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"effectiveFrom":{"type":"string","minLength":4,"maxLength":40,"description":"An instant with offset, e.g. \"2026-10-01T00:00:00Z\". A bare date is refused."},"effectiveLocal":{"type":"string","minLength":10,"maxLength":30,"description":"A wall-clock time, e.g. \"2026-10-01T00:00\"; requires `timezone`"},"timezone":{"type":"string","maxLength":64,"nullable":true,"description":"IANA zone, e.g. Europe/London; always recorded"}}}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"effectiveFrom":"<effectiveFrom>","effectiveLocal":"<effectiveLocal>"}}}},"/api/v1/switch/customers/{id}/sell-rates/discontinue-all":{"post":{"operationId":"postSwitchCustomersByIdSellRatesDiscontinueAll","tags":["Switch: customers"],"summary":"Discontinue a Switch customer whole sell deck","description":"Closes every rate's period at the effective moment; nothing is deleted and priced calls keep their rate. New calls fall back to your operator deck, then markup over cost. Omit the effective fields to act now. Send either `effectiveFrom` (an instant with an offset) or `effectiveLocal` plus `timezone`; a bare date is refused because midnight differs by country.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"endDate":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"effective":{"description":"The moment described in words and in the recorded zone"},"revisionId":{"type":"string","format":"uuid","nullable":true},"discontinued":{"type":"integer"},"deleted":{"type":"integer","description":"Deprecated alias of `discontinued`; nothing is deleted"},"scheduledLeft":{"type":"integer"}},"required":["endDate","discontinued","deleted","scheduledLeft"],"additionalProperties":true}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"effectiveFrom":{"type":"string","minLength":4,"maxLength":40,"description":"An instant with offset, e.g. \"2026-10-01T00:00:00Z\". A bare date is refused."},"effectiveLocal":{"type":"string","minLength":10,"maxLength":30,"description":"A wall-clock time, e.g. \"2026-10-01T00:00\"; requires `timezone`"},"timezone":{"type":"string","maxLength":64,"nullable":true,"description":"IANA zone, e.g. Europe/London; always recorded"},"includeScheduled":{"type":"boolean"}}}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"effectiveFrom":"<effectiveFrom>","effectiveLocal":"<effectiveLocal>"}}}},"/api/v1/switch/customers/{id}/sell-rates/{rateId}/discontinue":{"post":{"operationId":"postSwitchCustomersByIdSellRatesByRateIdDiscontinue","tags":["Switch: customers"],"summary":"Discontinue one Switch customer sell rate","description":"Omit the effective fields to act now. Send either `effectiveFrom` (an instant with an offset) or `effectiveLocal` plus `timezone`; a bare date is refused because midnight differs by country.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"endDate":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"effective":{"description":"The moment described in words and in the recorded zone"},"revisionId":{"type":"string","format":"uuid","nullable":true},"discontinued":{"type":"boolean","enum":[true]},"deleted":{"type":"boolean","enum":[true],"description":"Deprecated alias; the rate is discontinued, not deleted"},"immediate":{"type":"boolean"}},"required":["endDate","discontinued","deleted","immediate"],"additionalProperties":true}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"rateId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"effectiveFrom":{"type":"string","minLength":4,"maxLength":40,"description":"An instant with offset, e.g. \"2026-10-01T00:00:00Z\". A bare date is refused."},"effectiveLocal":{"type":"string","minLength":10,"maxLength":30,"description":"A wall-clock time, e.g. \"2026-10-01T00:00\"; requires `timezone`"},"timezone":{"type":"string","maxLength":64,"nullable":true,"description":"IANA zone, e.g. Europe/London; always recorded"}}}}}},"x-px-example":{"path":{"id":"<id>","rateId":"<rateId>"},"query":{},"body":{"effectiveFrom":"<effectiveFrom>","effectiveLocal":"<effectiveLocal>"}}}},"/api/v1/switch/customers/{id}/sell-rates/discontinuations":{"get":{"operationId":"getSwitchCustomersByIdSellRatesDiscontinuations","tags":["Switch: customers"],"summary":"List sell-rate discontinuation events for a Switch customer","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"revisionId":{"type":"string","format":"uuid","nullable":true},"discontinuedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"rows":{"type":"integer"},"label":{"type":"string"},"effective":{"nullable":true},"timezone":{"type":"string","nullable":true},"changeMode":{"type":"string","nullable":true}},"required":["revisionId","discontinuedAt","rows","label","timezone","changeMode"]}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/customers/{id}/sell-rates/apply-markup":{"post":{"operationId":"postSwitchCustomersByIdSellRatesApplyMarkup","tags":["Switch: customers"],"summary":"Reprice a Switch customer deck as a markup over buy cost","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"updated":{"type":"integer"},"skipped":{"type":"integer"},"basis":{},"revisionId":{"type":"string","format":"uuid","nullable":true}},"required":["updated","skipped","revisionId"],"additionalProperties":true}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"markupPct":{"type":"number","minimum":-100},"prefixes":{"type":"array","items":{"type":"string","maxLength":24},"maxItems":50000,"description":"Only these prefixes; omit for the whole deck"}},"required":["markupPct"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"markupPct":1}}}},"/api/v1/switch/customers/{id}/sell-rates.csv":{"get":{"operationId":"getSwitchCustomersByIdSellRatesCsv","tags":["Switch: customers"],"summary":"Export a Switch customer sell rates as CSV","description":"Takes the same filters as the list, with buy cost and margin columns.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"The filtered sell deck as a CSV attachment.","content":{"text/csv":{"schema":{"type":"string","format":"binary"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"search","in":"query","required":false,"description":"Prefix or destination text","schema":{"type":"string"}},{"name":"view","in":"query","required":false,"description":"Default current","schema":{"type":"string","enum":["current","scheduled","discontinued","expiring","all"]}},{"name":"origin","in":"query","required":false,"schema":{"type":"string","enum":["any","origin_only","destination_only"]}},{"name":"increment","in":"query","required":false,"schema":{"type":"string","enum":["any","custom","inherited"]}},{"name":"cost","in":"query","required":false,"schema":{"type":"string","enum":["any","missing"]}},{"name":"margin","in":"query","required":false,"schema":{"type":"string","enum":["any","thin","negative"]}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/customers/{id}/sell-rates/bulk":{"post":{"operationId":"postSwitchCustomersByIdSellRatesBulk","tags":["Switch: customers"],"summary":"Add or replace many Switch customer sell rates","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"applied":{"type":"integer"},"revisionId":{"type":"string","format":"uuid","nullable":true}},"required":["applied","revisionId"],"additionalProperties":true}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"rows":{"type":"array","items":{"type":"object","properties":{"prefix":{"type":"string","maxLength":24},"rate":{"type":"number","minimum":0},"origin":{"type":"string","maxLength":24},"billingIncrement":{"type":"string","maxLength":10}},"required":["prefix","rate"]},"maxItems":50000}},"required":["rows"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"rows":[{"prefix":"44","rate":1}]}}}},"/api/v1/switch/customers/{id}/sell-rates/{rateId}":{"delete":{"operationId":"deleteSwitchCustomersByIdSellRatesByRateId","tags":["Switch: customers"],"summary":"Discontinue one Switch customer sell rate now","description":"Kept for existing clients: the rate is discontinued immediately, not deleted.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"endDate":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"effective":{"description":"The moment described in words and in the recorded zone"},"revisionId":{"type":"string","format":"uuid","nullable":true},"discontinued":{"type":"boolean","enum":[true]},"deleted":{"type":"boolean","enum":[true],"description":"Deprecated alias; the rate is discontinued, not deleted"},"immediate":{"type":"boolean"}},"required":["endDate","discontinued","deleted","immediate"],"additionalProperties":true}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"rateId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>","rateId":"<rateId>"},"query":{}}}},"/api/v1/switch/customer-trunks/{trunkId}/rates":{"get":{"operationId":"getSwitchCustomerTrunksByTrunkIdRates","tags":["Switch: customer trunks"],"summary":"List a trunk's sell rates with buy cost and margin","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchCustomerSellRatePage"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"trunkId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"search","in":"query","required":false,"description":"Prefix or destination text","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer"}},{"name":"view","in":"query","required":false,"description":"Default current","schema":{"type":"string","enum":["current","scheduled","discontinued","expiring","all"]}},{"name":"origin","in":"query","required":false,"schema":{"type":"string","enum":["any","origin_only","destination_only"]}},{"name":"increment","in":"query","required":false,"schema":{"type":"string","enum":["any","custom","inherited"]}},{"name":"cost","in":"query","required":false,"schema":{"type":"string","enum":["any","missing"]}},{"name":"margin","in":"query","required":false,"schema":{"type":"string","enum":["any","thin","negative"]}}],"x-px-example":{"path":{"trunkId":"<trunkId>"},"query":{}}},"post":{"operationId":"postSwitchCustomerTrunksByTrunkIdRates","tags":["Switch: customer trunks"],"summary":"Add or replace one sell rate on a trunk","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchCustomerSellRate"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"trunkId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"prefix":{"type":"string","minLength":1,"maxLength":24},"rate":{"type":"number","minimum":0,"description":"USD per minute"},"origin":{"type":"string","maxLength":24},"billingIncrement":{"type":"string","maxLength":10}},"required":["prefix","rate"]}}}},"x-px-example":{"path":{"trunkId":"<trunkId>"},"query":{},"body":{"prefix":"44","rate":1}}}},"/api/v1/switch/customer-trunks/{trunkId}/rates/counts":{"get":{"operationId":"getSwitchCustomerTrunksByTrunkIdRatesCounts","tags":["Switch: customer trunks"],"summary":"Count a trunk's sell rates by view","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"current":{"type":"integer"},"scheduled":{"type":"integer"},"expiring":{"type":"integer"},"discontinued":{"type":"integer"},"all":{"type":"integer"}},"required":["current","scheduled","expiring","discontinued","all"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"trunkId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"trunkId":"<trunkId>"},"query":{}}}},"/api/v1/switch/customer-trunks/{trunkId}/rates/upcoming":{"get":{"operationId":"getSwitchCustomerTrunksByTrunkIdRatesUpcoming","tags":["Switch: customer trunks"],"summary":"List upcoming sell-rate starts and ends on a trunk","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"subAccountId":{"type":"string","format":"uuid"},"customerTrunkId":{"type":"string","format":"uuid","nullable":true},"prefix":{"type":"string"},"originPrefix":{"type":"string","description":"\"\" = any origin"},"ratePerUnit":{"allOf":[{"$ref":"#/components/schemas/Money"}],"description":"Sell price per minute, 6-decimal USD string"},"billingIncrement":{"type":"string","nullable":true},"status":{"type":"string","description":"active, pending (scheduled) or discontinued"},"effectiveFrom":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"endDate":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"kind":{"type":"string","enum":["starts","ends"]},"at":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true}},"required":["id","subAccountId","customerTrunkId","prefix","originPrefix","ratePerUnit","billingIncrement","status","effectiveFrom","endDate","kind","at"],"additionalProperties":true}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"trunkId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"trunkId":"<trunkId>"},"query":{}}}},"/api/v1/switch/customer-trunks/{trunkId}/rates/discontinuations":{"get":{"operationId":"getSwitchCustomerTrunksByTrunkIdRatesDiscontinuations","tags":["Switch: customer trunks"],"summary":"List sell-rate discontinuation events on a trunk","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"revisionId":{"type":"string","format":"uuid","nullable":true},"discontinuedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"rows":{"type":"integer"},"label":{"type":"string"},"effective":{"nullable":true},"timezone":{"type":"string","nullable":true},"changeMode":{"type":"string","nullable":true}},"required":["revisionId","discontinuedAt","rows","label","timezone","changeMode"]}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"trunkId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"trunkId":"<trunkId>"},"query":{}}}},"/api/v1/switch/customer-trunks/{trunkId}/rates/discontinue-all/preview":{"post":{"operationId":"postSwitchCustomerTrunksByTrunkIdRatesDiscontinueAllPreview","tags":["Switch: customer trunks"],"summary":"Preview discontinuing a trunk's whole sell deck","description":"Omit the effective fields to act now. Send either `effectiveFrom` (an instant with an offset) or `effectiveLocal` plus `timezone`; a bare date is refused because midnight differs by country.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"customerLabel":{"type":"string"},"activeRates":{"type":"integer"},"scheduledRates":{"type":"integer"},"alreadyDiscontinued":{"type":"integer"},"endDate":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"immediate":{"type":"boolean"},"timezone":{"type":"string","nullable":true},"effectOnNewCalls":{"type":"string"},"minutes30d":{"type":"number"},"calls30d":{"type":"integer"},"revenue30d":{"type":"number","description":"US dollars as a JSON number (computed figure)"},"impactTruncated":{"type":"boolean"},"sample":{"type":"array","items":{"type":"object","properties":{"prefix":{"type":"string"},"originPrefix":{"type":"string"},"ratePerUnit":{"$ref":"#/components/schemas/Money"},"billingIncrement":{"type":"string","nullable":true}},"required":["prefix","originPrefix","ratePerUnit","billingIncrement"]}}},"required":["customerLabel","activeRates","scheduledRates","alreadyDiscontinued","endDate","immediate","timezone","effectOnNewCalls","minutes30d","calls30d","revenue30d","impactTruncated","sample"],"additionalProperties":true}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"trunkId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"effectiveFrom":{"type":"string","minLength":4,"maxLength":40,"description":"An instant with offset, e.g. \"2026-10-01T00:00:00Z\". A bare date is refused."},"effectiveLocal":{"type":"string","minLength":10,"maxLength":30,"description":"A wall-clock time, e.g. \"2026-10-01T00:00\"; requires `timezone`"},"timezone":{"type":"string","maxLength":64,"nullable":true,"description":"IANA zone, e.g. Europe/London; always recorded"}}}}}},"x-px-example":{"path":{"trunkId":"<trunkId>"},"query":{},"body":{"effectiveFrom":"<effectiveFrom>","effectiveLocal":"<effectiveLocal>"}}}},"/api/v1/switch/customer-trunks/{trunkId}/rates/discontinue-all":{"post":{"operationId":"postSwitchCustomerTrunksByTrunkIdRatesDiscontinueAll","tags":["Switch: customer trunks"],"summary":"Discontinue a trunk's whole sell deck","description":"Nothing is deleted; priced calls keep their rate. Omit the effective fields to act now. Send either `effectiveFrom` (an instant with an offset) or `effectiveLocal` plus `timezone`; a bare date is refused because midnight differs by country.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"endDate":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"effective":{"description":"The moment described in words and in the recorded zone"},"revisionId":{"type":"string","format":"uuid","nullable":true},"discontinued":{"type":"integer"},"deleted":{"type":"integer","description":"Deprecated alias of `discontinued`; nothing is deleted"},"scheduledLeft":{"type":"integer"}},"required":["endDate","discontinued","deleted","scheduledLeft"],"additionalProperties":true}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"trunkId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"effectiveFrom":{"type":"string","minLength":4,"maxLength":40,"description":"An instant with offset, e.g. \"2026-10-01T00:00:00Z\". A bare date is refused."},"effectiveLocal":{"type":"string","minLength":10,"maxLength":30,"description":"A wall-clock time, e.g. \"2026-10-01T00:00\"; requires `timezone`"},"timezone":{"type":"string","maxLength":64,"nullable":true,"description":"IANA zone, e.g. Europe/London; always recorded"},"includeScheduled":{"type":"boolean"}}}}}},"x-px-example":{"path":{"trunkId":"<trunkId>"},"query":{},"body":{"effectiveFrom":"<effectiveFrom>","effectiveLocal":"<effectiveLocal>"}}}},"/api/v1/switch/customer-trunks/{trunkId}/rates/{rateId}/discontinue":{"post":{"operationId":"postSwitchCustomerTrunksByTrunkIdRatesByRateIdDiscontinue","tags":["Switch: customer trunks"],"summary":"Discontinue one sell rate on a trunk","description":"Omit the effective fields to act now. Send either `effectiveFrom` (an instant with an offset) or `effectiveLocal` plus `timezone`; a bare date is refused because midnight differs by country.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"endDate":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"effective":{"description":"The moment described in words and in the recorded zone"},"revisionId":{"type":"string","format":"uuid","nullable":true},"discontinued":{"type":"boolean","enum":[true]},"deleted":{"type":"boolean","enum":[true],"description":"Deprecated alias; the rate is discontinued, not deleted"},"immediate":{"type":"boolean"}},"required":["endDate","discontinued","deleted","immediate"],"additionalProperties":true}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"trunkId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"rateId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"effectiveFrom":{"type":"string","minLength":4,"maxLength":40,"description":"An instant with offset, e.g. \"2026-10-01T00:00:00Z\". A bare date is refused."},"effectiveLocal":{"type":"string","minLength":10,"maxLength":30,"description":"A wall-clock time, e.g. \"2026-10-01T00:00\"; requires `timezone`"},"timezone":{"type":"string","maxLength":64,"nullable":true,"description":"IANA zone, e.g. Europe/London; always recorded"}}}}}},"x-px-example":{"path":{"trunkId":"<trunkId>","rateId":"<rateId>"},"query":{},"body":{"effectiveFrom":"<effectiveFrom>","effectiveLocal":"<effectiveLocal>"}}}},"/api/v1/switch/customer-trunks/{trunkId}/rates/bulk":{"post":{"operationId":"postSwitchCustomerTrunksByTrunkIdRatesBulk","tags":["Switch: customer trunks"],"summary":"Add or replace many sell rates on a trunk","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"applied":{"type":"integer"},"revisionId":{"type":"string","format":"uuid","nullable":true}},"required":["applied","revisionId"],"additionalProperties":true}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"trunkId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"rows":{"type":"array","items":{"type":"object","properties":{"prefix":{"type":"string","maxLength":24},"rate":{"type":"number","minimum":0},"origin":{"type":"string","maxLength":24},"billingIncrement":{"type":"string","maxLength":10}},"required":["prefix","rate"]},"maxItems":50000}},"required":["rows"]}}}},"x-px-example":{"path":{"trunkId":"<trunkId>"},"query":{},"body":{"rows":[{"prefix":"44","rate":1}]}}}},"/api/v1/switch/customer-trunks/{trunkId}/rates/{rateId}":{"delete":{"operationId":"deleteSwitchCustomerTrunksByTrunkIdRatesByRateId","tags":["Switch: customer trunks"],"summary":"Discontinue one sell rate on a trunk now","description":"Kept for existing clients: the rate is discontinued immediately, not deleted.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"endDate":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"effective":{"description":"The moment described in words and in the recorded zone"},"revisionId":{"type":"string","format":"uuid","nullable":true},"discontinued":{"type":"boolean","enum":[true]},"deleted":{"type":"boolean","enum":[true],"description":"Deprecated alias; the rate is discontinued, not deleted"},"immediate":{"type":"boolean"}},"required":["endDate","discontinued","deleted","immediate"],"additionalProperties":true}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"trunkId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"rateId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"trunkId":"<trunkId>","rateId":"<rateId>"},"query":{}}}},"/api/v1/switch/customer-trunks/{trunkId}/rates/clear":{"post":{"operationId":"postSwitchCustomerTrunksByTrunkIdRatesClear","tags":["Switch: customer trunks"],"summary":"Discontinue every sell rate on a trunk now","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"endDate":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"effective":{"description":"The moment described in words and in the recorded zone"},"revisionId":{"type":"string","format":"uuid","nullable":true},"discontinued":{"type":"integer"},"deleted":{"type":"integer","description":"Deprecated alias of `discontinued`; nothing is deleted"},"scheduledLeft":{"type":"integer"}},"required":["endDate","discontinued","deleted","scheduledLeft"],"additionalProperties":true}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"trunkId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"trunkId":"<trunkId>"},"query":{}}}},"/api/v1/switch/customer-trunks/{trunkId}/rates/scheduled":{"get":{"operationId":"getSwitchCustomerTrunksByTrunkIdRatesScheduled","tags":["Switch: customer trunks"],"summary":"List scheduled (future-dated) sell rates on a trunk","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/SwitchCustomerSellRate"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"trunkId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"trunkId":"<trunkId>"},"query":{}}}},"/api/v1/switch/customer-trunks/{trunkId}/rates/schedule":{"post":{"operationId":"postSwitchCustomerTrunksByTrunkIdRatesSchedule","tags":["Switch: customer trunks"],"summary":"Schedule a future sell-rate change on a trunk","description":"The rate becomes active at the effective moment. Omit the effective fields to act now. Send either `effectiveFrom` (an instant with an offset) or `effectiveLocal` plus `timezone`; a bare date is refused because midnight differs by country.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchCustomerSellRate"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"trunkId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"effectiveFrom":{"type":"string","minLength":4,"maxLength":40,"description":"An instant with offset, e.g. \"2026-10-01T00:00:00Z\". A bare date is refused."},"effectiveLocal":{"type":"string","minLength":10,"maxLength":30,"description":"A wall-clock time, e.g. \"2026-10-01T00:00\"; requires `timezone`"},"timezone":{"type":"string","maxLength":64,"nullable":true,"description":"IANA zone, e.g. Europe/London; always recorded"},"prefix":{"type":"string","minLength":1,"maxLength":24},"rate":{"type":"number","minimum":0,"description":"USD per minute"},"origin":{"type":"string","maxLength":24},"billingIncrement":{"type":"string","maxLength":10}},"required":["prefix","rate"]}}}},"x-px-example":{"path":{"trunkId":"<trunkId>"},"query":{},"body":{"prefix":"44","rate":1}}}},"/api/v1/switch/customer-trunks/{trunkId}/rates/scheduled/{rateId}":{"delete":{"operationId":"deleteSwitchCustomerTrunksByTrunkIdRatesScheduledByRateId","tags":["Switch: customer trunks"],"summary":"Cancel a scheduled sell rate on a trunk","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"cancelled":{"type":"boolean","enum":[true]}},"required":["cancelled"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"trunkId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"rateId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"trunkId":"<trunkId>","rateId":"<rateId>"},"query":{}}}},"/api/v1/switch/customer-trunks/{trunkId}/rates/apply-markup":{"post":{"operationId":"postSwitchCustomerTrunksByTrunkIdRatesApplyMarkup","tags":["Switch: customer trunks"],"summary":"Reprice as a markup over buy cost from a trunk","description":"Applies to the customer's deck; on a single-trunk customer that is this trunk's deck.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"updated":{"type":"integer"},"skipped":{"type":"integer"},"basis":{},"revisionId":{"type":"string","format":"uuid","nullable":true}},"required":["updated","skipped","revisionId"],"additionalProperties":true}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"trunkId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"markupPct":{"type":"number","minimum":-100},"prefixes":{"type":"array","items":{"type":"string","maxLength":24},"maxItems":50000,"description":"Only these prefixes; omit for the whole deck"}},"required":["markupPct"]}}}},"x-px-example":{"path":{"trunkId":"<trunkId>"},"query":{},"body":{"markupPct":1}}}},"/api/v1/switch/customer-trunks/{trunkId}/rates.csv":{"get":{"operationId":"getSwitchCustomerTrunksByTrunkIdRatesCsv","tags":["Switch: customer trunks"],"summary":"Export a trunk's sell rates as CSV","description":"Scoped to this trunk's deck; takes the same filters as the list.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"The trunk's filtered sell deck as a CSV attachment.","content":{"text/csv":{"schema":{"type":"string","format":"binary"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"trunkId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"search","in":"query","required":false,"description":"Prefix or destination text","schema":{"type":"string"}},{"name":"view","in":"query","required":false,"description":"Default current","schema":{"type":"string","enum":["current","scheduled","discontinued","expiring","all"]}},{"name":"origin","in":"query","required":false,"schema":{"type":"string","enum":["any","origin_only","destination_only"]}},{"name":"increment","in":"query","required":false,"schema":{"type":"string","enum":["any","custom","inherited"]}},{"name":"cost","in":"query","required":false,"schema":{"type":"string","enum":["any","missing"]}},{"name":"margin","in":"query","required":false,"schema":{"type":"string","enum":["any","thin","negative"]}}],"x-px-example":{"path":{"trunkId":"<trunkId>"},"query":{}}}},"/api/v1/switch/customers/{id}/sell-rates/clear":{"post":{"operationId":"postSwitchCustomersByIdSellRatesClear","tags":["Switch: customers"],"summary":"Discontinue every Switch customer sell rate now","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"endDate":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"effective":{"description":"The moment described in words and in the recorded zone"},"revisionId":{"type":"string","format":"uuid","nullable":true},"discontinued":{"type":"integer"},"deleted":{"type":"integer","description":"Deprecated alias of `discontinued`; nothing is deleted"},"scheduledLeft":{"type":"integer"}},"required":["endDate","discontinued","deleted","scheduledLeft"],"additionalProperties":true}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/customers/{id}/sell-rates/scheduled":{"get":{"operationId":"getSwitchCustomersByIdSellRatesScheduled","tags":["Switch: customers"],"summary":"List scheduled (future-dated) sell rates for a Switch customer","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/SwitchCustomerSellRate"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/customers/{id}/sell-rates/schedule":{"post":{"operationId":"postSwitchCustomersByIdSellRatesSchedule","tags":["Switch: customers"],"summary":"Schedule a future Switch customer sell-rate change","description":"The rate becomes active at the effective moment. Omit the effective fields to act now. Send either `effectiveFrom` (an instant with an offset) or `effectiveLocal` plus `timezone`; a bare date is refused because midnight differs by country.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchCustomerSellRate"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"effectiveFrom":{"type":"string","minLength":4,"maxLength":40,"description":"An instant with offset, e.g. \"2026-10-01T00:00:00Z\". A bare date is refused."},"effectiveLocal":{"type":"string","minLength":10,"maxLength":30,"description":"A wall-clock time, e.g. \"2026-10-01T00:00\"; requires `timezone`"},"timezone":{"type":"string","maxLength":64,"nullable":true,"description":"IANA zone, e.g. Europe/London; always recorded"},"prefix":{"type":"string","minLength":1,"maxLength":24},"rate":{"type":"number","minimum":0,"description":"USD per minute"},"origin":{"type":"string","maxLength":24},"billingIncrement":{"type":"string","maxLength":10}},"required":["prefix","rate"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"prefix":"44","rate":1}}}},"/api/v1/switch/customers/{id}/sell-rates/scheduled/{rateId}":{"delete":{"operationId":"deleteSwitchCustomersByIdSellRatesScheduledByRateId","tags":["Switch: customers"],"summary":"Cancel a scheduled Switch customer sell rate","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"cancelled":{"type":"boolean","enum":[true]}},"required":["cancelled"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"rateId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>","rateId":"<rateId>"},"query":{}}}},"/api/v1/switch/rate-decks/parse":{"post":{"operationId":"postSwitchRateDecksParse","tags":["Switch: rating"],"summary":"Read a rate sheet and propose a column mapping","description":"Step 1 of the guided import into any switch deck (your own sell deck, a supplier trunk or a customer trunk). Returns the detected columns, a sample and warnings. Writes nothing.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Rate limit:** 10 requests per minute per caller.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"targetLabel":{"type":"string"},"mapping":{"type":"object","properties":{},"additionalProperties":true,"description":"Detected column mapping; send it back (as JSON) on diff and apply"},"rawSample":{"type":"array","items":{"type":"array","items":{}},"description":"The first 8 raw rows"},"previewRows":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true},"description":"Up to 50 parsed rows"},"rowCount":{"type":"integer"},"warnings":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}},"currency":{"type":"string"},"summary":{"type":"object","properties":{},"additionalProperties":true},"overLimit":{"type":"boolean"},"maxRows":{"type":"integer"}},"required":["targetLabel","mapping","rawSample","previewRows","rowCount","warnings","currency","summary","overLimit","maxRows"],"additionalProperties":true}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-rate-limit":{"max":10,"window":"minute"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"targetKind":{"type":"string","enum":["operator","supplier","customer"]},"targetId":{"type":"string","format":"uuid"},"targetTrunkId":{"type":"string","format":"uuid"},"defaultIncrement":{"type":"string","pattern":"^\\d{1,3}\\/\\d{1,3}$"},"changeMode":{"type":"string","enum":["amendment","full_replacement"]},"effectiveFrom":{"type":"string","format":"date-time"},"timezone":{"type":"string","maxLength":64},"fxRate":{"type":"string","description":"Units of USD per 1 unit of the sheet currency; required to apply a non-USD sheet"},"replace":{"type":"string","enum":["true","false"],"description":"Legacy form of changeMode=full_replacement"},"mapping":{"type":"string","description":"The confirmed column mapping from the parse step, as JSON text"},"file":{"type":"string","description":"The rate sheet (CSV or XLSX), sent LAST"}},"required":["targetKind","file"],"description":"multipart/form-data. Send the text fields before the file part."}}}},"x-px-example":{"path":{},"query":{}}}},"/api/v1/switch/rate-decks/diff":{"post":{"operationId":"postSwitchRateDecksDiff","tags":["Switch: rating"],"summary":"Preview what a rate sheet would change","description":"Dry run: compares the sheet with the target deck's live rows and reports added, changed and removed prefixes. `changeMode` decides whether omitted prefixes stop pricing. Writes nothing.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchDeckSheetResult"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"targetKind":{"type":"string","enum":["operator","supplier","customer"]},"targetId":{"type":"string","format":"uuid"},"targetTrunkId":{"type":"string","format":"uuid"},"defaultIncrement":{"type":"string","pattern":"^\\d{1,3}\\/\\d{1,3}$"},"changeMode":{"type":"string","enum":["amendment","full_replacement"]},"effectiveFrom":{"type":"string","format":"date-time"},"timezone":{"type":"string","maxLength":64},"fxRate":{"type":"string","description":"Units of USD per 1 unit of the sheet currency; required to apply a non-USD sheet"},"replace":{"type":"string","enum":["true","false"],"description":"Legacy form of changeMode=full_replacement"},"mapping":{"type":"string","description":"The confirmed column mapping from the parse step, as JSON text"},"file":{"type":"string","description":"The rate sheet (CSV or XLSX), sent LAST"}},"required":["targetKind","file"],"description":"multipart/form-data. Send the text fields before the file part."}}}},"x-px-example":{"path":{},"query":{}}}},"/api/v1/switch/rate-decks/apply":{"post":{"operationId":"postSwitchRateDecksApply","tags":["Switch: rating"],"summary":"Apply a rate sheet to a switch deck","description":"Writes the sheet in one transaction and reports what landed. A non-USD sheet needs `fxRate`. For supplier decks a future `effectiveFrom` queues the change for that moment instead (the result then has `scheduled: true`).\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Rate limit:** 20 requests per minute per caller.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchDeckSheetResult"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-rate-limit":{"max":20,"window":"minute"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"targetKind":{"type":"string","enum":["operator","supplier","customer"]},"targetId":{"type":"string","format":"uuid"},"targetTrunkId":{"type":"string","format":"uuid"},"defaultIncrement":{"type":"string","pattern":"^\\d{1,3}\\/\\d{1,3}$"},"changeMode":{"type":"string","enum":["amendment","full_replacement"]},"effectiveFrom":{"type":"string","format":"date-time"},"timezone":{"type":"string","maxLength":64},"fxRate":{"type":"string","description":"Units of USD per 1 unit of the sheet currency; required to apply a non-USD sheet"},"replace":{"type":"string","enum":["true","false"],"description":"Legacy form of changeMode=full_replacement"},"mapping":{"type":"string","description":"The confirmed column mapping from the parse step, as JSON text"},"file":{"type":"string","description":"The rate sheet (CSV or XLSX), sent LAST"}},"required":["targetKind","file"],"description":"multipart/form-data. Send the text fields before the file part."}}}},"x-px-example":{"path":{},"query":{}}}},"/api/v1/switch/suppliers/{id}/rates":{"get":{"operationId":"getSwitchSuppliersByIdRates","tags":["Switch: suppliers"],"summary":"List the cost deck in force on a supplier trunk","description":"Active rows only; scheduled and archived rows have their own endpoints. Search matches a prefix start.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"rows":{"type":"array","items":{"$ref":"#/components/schemas/SwitchTrunkRate"}},"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"}},"required":["rows","total","limit","offset"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"search","in":"query","required":false,"description":"Digits; matches prefixes starting with them","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"1-1000, default 100","schema":{"type":"string"}},{"name":"offset","in":"query","required":false,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}},"post":{"operationId":"postSwitchSuppliersByIdRates","tags":["Switch: suppliers"],"summary":"Set the cost for one prefix on a supplier trunk","description":"Creates or replaces the active rate for the prefix (and origin), effective now.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchTrunkRate"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"prefix":{"type":"string","minLength":1,"maxLength":24},"rate":{"type":"number","minimum":0,"description":"Cost per minute, USD"},"origin":{"type":"string","maxLength":24},"billingIncrement":{"type":"string","maxLength":10}},"required":["prefix","rate"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"prefix":"44","rate":1}}}},"/api/v1/switch/suppliers/{id}/rates/bulk":{"post":{"operationId":"postSwitchSuppliersByIdRatesBulk","tags":["Switch: suppliers"],"summary":"Set costs for many prefixes on a supplier trunk","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"applied":{"type":"integer"}},"required":["applied"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"rows":{"type":"array","items":{"type":"object","properties":{"prefix":{"type":"string","maxLength":24},"rate":{"type":"number","minimum":0,"description":"Cost per minute, USD"},"origin":{"type":"string","maxLength":24},"billingIncrement":{"type":"string","maxLength":10}},"required":["prefix","rate"]},"maxItems":50000}},"required":["rows"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"rows":[{"prefix":"44","rate":1}]}}}},"/api/v1/switch/suppliers/{id}/rates/{rateId}":{"delete":{"operationId":"deleteSwitchSuppliersByIdRatesByRateId","tags":["Switch: suppliers"],"summary":"Delete one cost row from a supplier trunk","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"deleted":{"type":"boolean","enum":[true]}},"required":["deleted"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"rateId","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>","rateId":"<rateId>"},"query":{}}}},"/api/v1/switch/suppliers/{id}/rates/clear":{"post":{"operationId":"postSwitchSuppliersByIdRatesClear","tags":["Switch: suppliers"],"summary":"Clear the cost deck of a supplier trunk","description":"The deck is archived, not destroyed: restore it with POST /{id}/rates/restore.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"deleted":{"type":"integer"},"archived":{"type":"integer"},"recoverable":{"type":"boolean"},"revisionId":{"type":"string","format":"uuid","nullable":true}},"required":["deleted","archived","recoverable","revisionId"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/suppliers/{id}/rates/archived":{"get":{"operationId":"getSwitchSuppliersByIdRatesArchived","tags":["Switch: suppliers"],"summary":"List archived cost decks of a supplier trunk","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"revisionId":{"type":"string","format":"uuid","nullable":true},"archivedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"rows":{"type":"integer"},"label":{"type":"string"}},"required":["revisionId","archivedAt","rows","label"]}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/suppliers/{id}/rates/restore":{"post":{"operationId":"postSwitchSuppliersByIdRatesRestore","tags":["Switch: suppliers"],"summary":"Restore an archived cost deck","description":"Restores the newest archive unless `revisionId` names one. Each row returns to the status it was archived from.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"restored":{"type":"integer"},"skipped":{"type":"integer"},"revisionId":{"type":"string","format":"uuid","nullable":true}},"required":["restored","skipped","revisionId"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"revisionId":{"type":"string","format":"uuid"}}}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"revisionId":"<revisionId>"}}}},"/api/v1/switch/suppliers/{id}/rates/scheduled":{"get":{"operationId":"getSwitchSuppliersByIdRatesScheduled","tags":["Switch: suppliers"],"summary":"List scheduled cost changes on a supplier trunk","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/SwitchTrunkRate"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/suppliers/{id}/rates/schedule":{"post":{"operationId":"postSwitchSuppliersByIdRatesSchedule","tags":["Switch: suppliers"],"summary":"Schedule a future cost change for one prefix","description":"A date in the past or now applies the rate immediately instead.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchTrunkRate"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"prefix":{"type":"string","minLength":1,"maxLength":24},"rate":{"type":"number","minimum":0,"description":"Cost per minute, USD"},"origin":{"type":"string","maxLength":24},"billingIncrement":{"type":"string","maxLength":10},"effectiveFrom":{"type":"string","format":"date-time"}},"required":["prefix","rate","effectiveFrom"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"prefix":"44","rate":1,"effectiveFrom":"2026-10-01T09:00:00Z"}}}},"/api/v1/switch/suppliers/{id}/rates/scheduled/{rateId}":{"delete":{"operationId":"deleteSwitchSuppliersByIdRatesScheduledByRateId","tags":["Switch: suppliers"],"summary":"Cancel a scheduled cost change","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"cancelled":{"type":"boolean","enum":[true]}},"required":["cancelled"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"rateId","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>","rateId":"<rateId>"},"query":{}}}},"/api/v1/switch/suppliers/{id}/rates/pending-review":{"get":{"operationId":"getSwitchSuppliersByIdRatesPendingReview","tags":["Switch: suppliers"],"summary":"Review queued cost changes before they take effect","description":"Every queued change with the price billed today, the price that takes over and when, and the effect on the last 30 days of traffic. Rates are 6-decimal strings; `monthlyDelta` and `netMonthlyDelta` are JSON numbers. At most 500 rows.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"rows":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"kind":{"type":"string","enum":["deck","row","removed"]},"prefix":{"type":"string"},"destination":{"type":"string","nullable":true},"currentRate":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"US dollars as a decimal string with exactly 6 decimal places, e.g. \"0.012500\". Do money arithmetic with a decimal type, not floating point."},"newRate":{"type":"string","nullable":true},"deltaPct":{"type":"number","nullable":true},"effectiveFrom":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"minutes30d":{"type":"number"},"calls30d":{"type":"integer"},"monthlyDelta":{"type":"number","nullable":true}},"required":["id","kind","prefix","destination","currentRate","newRate","deltaPct","effectiveFrom","minutes30d","calls30d","monthlyDelta"],"additionalProperties":true}},"totalRows":{"type":"integer"},"decks":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}},"impactTruncated":{"type":"boolean"},"summary":{"type":"object","properties":{},"additionalProperties":true}},"required":["rows","totalRows","decks","impactTruncated","summary"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/invoices":{"get":{"operationId":"getSwitchInvoices","tags":["Switch: invoicing"],"summary":"List customer invoices","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"rows":{"type":"array","items":{"$ref":"#/components/schemas/SwitchInvoice"}},"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"}},"required":["rows","total","limit","offset"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"customerId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["draft","open","partial","paid","overdue","void"]}},{"name":"limit","in":"query","required":false,"description":"Page size (default 50, max 500)","schema":{"type":"integer","minimum":1,"maximum":500}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0}}],"x-px-example":{"path":{},"query":{}}},"post":{"operationId":"postSwitchInvoices","tags":["Switch: invoicing"],"summary":"Issue an invoice from a reviewed preview","description":"Irreversible: allocates the next invoice number and claims the usage. Requires the `reviewToken` from a preview that still matches live data. Does not send the invoice; use POST /switch/invoices/{id}/send.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customerId":{"type":"string","format":"uuid"},"invoiceNumber":{"type":"string","description":"Sequential per operator, gap-free"},"periodStart":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"periodEnd":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"issueDate":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"dueDate":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"currency":{"type":"string","minLength":3,"maxLength":3},"subtotal":{"$ref":"#/components/schemas/Money"},"tax":{"$ref":"#/components/schemas/Money"},"total":{"$ref":"#/components/schemas/Money"},"amountPaid":{"$ref":"#/components/schemas/Money"},"status":{"type":"string","enum":["draft","open","partial","paid","overdue","void"]},"overdue":{"type":"boolean"},"notes":{"type":"string","nullable":true},"replacesInvoiceId":{"type":"string","format":"uuid","nullable":true},"sentAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"sendCount":{"type":"integer"},"customerLabel":{"type":"string","nullable":true,"description":"On list rows"},"reviewDigest":{"type":"string","nullable":true},"preview":{"$ref":"#/components/schemas/SwitchInvoicePreview"}},"required":["id","customerId","invoiceNumber","periodStart","periodEnd","issueDate","dueDate","currency","subtotal","tax","total","amountPaid","status","overdue","notes","reviewDigest"],"additionalProperties":true}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["INVOICE_REVIEW_STALE","INVOICE_UNRATED_USAGE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"customerId":{"type":"string","format":"uuid"},"periodStart":{"type":"string","description":"ISO-8601 date or timestamp; start of the billing period"},"periodEnd":{"type":"string","description":"ISO-8601 date or timestamp; end of the billing period"},"notes":{"type":"string","maxLength":2000,"nullable":true},"includeBroughtForward":{"type":"boolean","description":"Also bill priced, still-unbilled usage from before the period"},"applyCredits":{"type":"boolean","description":"Consume the customer's open credit notes on this invoice"},"excludeUnrated":{"type":"object","properties":{"reason":{"type":"string","minLength":8,"maxLength":2000}},"required":["reason"],"nullable":true,"description":"Issue despite unpriced usage, leaving it unbilled for the stated reason (needs the billing adjustment permission)"},"reviewToken":{"type":"string","minLength":8,"maxLength":120}},"required":["customerId","periodStart","periodEnd","reviewToken"]}}}},"x-px-example":{"path":{},"query":{},"body":{"customerId":"<customerId>","periodStart":"<periodStart>","periodEnd":"<periodEnd>","reviewToken":"<reviewToken>"}},"x-px-billable":{"kind":"money","note":"Issues, voids or settles a billing document."}}},"/api/v1/switch/rerate/preview":{"post":{"operationId":"postSwitchReratePreview","tags":["Switch"],"summary":"POST /api/v1/switch/rerate/preview","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Rate limit:** 20 requests per minute per caller.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":" Response shape not documented yet: the standard `{ \"success\": true, \"data\": ... }` envelope."},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-rate-limit":{"max":20,"window":"minute"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/switch/rerate/apply":{"post":{"operationId":"postSwitchRerateApply","tags":["Switch"],"summary":"POST /api/v1/switch/rerate/apply","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Rate limit:** 10 requests per minute per caller.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":" Response shape not documented yet: the standard `{ \"success\": true, \"data\": ... }` envelope."},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-rate-limit":{"max":10,"window":"minute"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/switch/rerate/jobs":{"get":{"operationId":"getSwitchRerateJobs","tags":["Switch"],"summary":"GET /api/v1/switch/rerate/jobs","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":" Response shape not documented yet: the standard `{ \"success\": true, \"data\": ... }` envelope."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/switch/rerate/jobs/{jobId}":{"get":{"operationId":"getSwitchRerateJobsByJobId","tags":["Switch"],"summary":"GET /api/v1/switch/rerate/jobs/{jobId}","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":" Response shape not documented yet: the standard `{ \"success\": true, \"data\": ... }` envelope."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"jobId","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"jobId":"<jobId>"},"query":{}}}},"/api/v1/switch/rerate/{jobId}/undo":{"post":{"operationId":"postSwitchRerateByJobIdUndo","tags":["Switch"],"summary":"POST /api/v1/switch/rerate/{jobId}/undo","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":" Response shape not documented yet: the standard `{ \"success\": true, \"data\": ... }` envelope."},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"jobId","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"jobId":"<jobId>"},"query":{}}}},"/api/v1/switch/invoices/preview":{"post":{"operationId":"postSwitchInvoicesPreview","tags":["Switch: invoicing"],"summary":"Preview an invoice before issuing it","description":"A read: allocates no number and claims no usage. Returns every figure the invoice would carry, the usage it could not price, and a review token. Issue with that token; if live data changes in between, issuing fails with INVOICE_REVIEW_STALE.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchInvoicePreview"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"customerId":{"type":"string","format":"uuid"},"periodStart":{"type":"string","description":"ISO-8601 date or timestamp; start of the billing period"},"periodEnd":{"type":"string","description":"ISO-8601 date or timestamp; end of the billing period"},"notes":{"type":"string","maxLength":2000,"nullable":true},"includeBroughtForward":{"type":"boolean","description":"Also bill priced, still-unbilled usage from before the period"},"applyCredits":{"type":"boolean","description":"Consume the customer's open credit notes on this invoice"},"excludeUnrated":{"type":"object","properties":{"reason":{"type":"string","minLength":8,"maxLength":2000}},"required":["reason"],"nullable":true,"description":"Issue despite unpriced usage, leaving it unbilled for the stated reason (needs the billing adjustment permission)"},"releaseInvoiceId":{"type":"string","format":"uuid","nullable":true,"description":"Reissue only: review as if this invoice were already voided"}},"required":["customerId","periodStart","periodEnd"]}}}},"x-px-example":{"path":{},"query":{},"body":{"customerId":"<customerId>","periodStart":"<periodStart>","periodEnd":"<periodEnd>"}},"x-px-billable":{"kind":"money","note":"Issues, voids or settles a billing document."}}},"/api/v1/switch/invoices/{id}":{"get":{"operationId":"getSwitchInvoicesById","tags":["Switch: invoicing"],"summary":"Get an invoice with lines, payments and history","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchInvoiceDetail"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/invoices/{id}/payments":{"post":{"operationId":"postSwitchInvoicesByIdPayments","tags":["Switch: invoicing"],"summary":"Record a payment received against an invoice","description":"Updates `amountPaid` and the status (partial or paid). Overpayment is refused.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchInvoice"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"amount":{"type":"number","exclusiveMinimum":true,"minimum":0,"description":"Amount received, in the document currency"},"method":{"type":"string","maxLength":32,"nullable":true},"reference":{"type":"string","maxLength":160,"nullable":true}},"required":["amount"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"amount":1}},"x-px-billable":{"kind":"money","note":"Issues, voids or settles a billing document."}}},"/api/v1/switch/invoices/{id}/void":{"post":{"operationId":"postSwitchInvoicesByIdVoid","tags":["Switch: invoicing"],"summary":"Void an invoice","description":"A correction, never an erasure: needs a reason, refuses an invoice that has payments against it (issue a credit note instead), and releases the usage it claimed so it can be billed again. Applied credit notes are returned to the customer.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customerId":{"type":"string","format":"uuid"},"invoiceNumber":{"type":"string","description":"Sequential per operator, gap-free"},"periodStart":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"periodEnd":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"issueDate":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"dueDate":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"currency":{"type":"string","minLength":3,"maxLength":3},"subtotal":{"$ref":"#/components/schemas/Money"},"tax":{"$ref":"#/components/schemas/Money"},"total":{"$ref":"#/components/schemas/Money"},"amountPaid":{"$ref":"#/components/schemas/Money"},"status":{"type":"string","enum":["draft","open","partial","paid","overdue","void"]},"overdue":{"type":"boolean"},"notes":{"type":"string","nullable":true},"replacesInvoiceId":{"type":"string","format":"uuid","nullable":true},"sentAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"sendCount":{"type":"integer"},"customerLabel":{"type":"string","nullable":true,"description":"On list rows"},"releasedCalls":{"type":"integer"},"returnedCreditNotes":{"type":"integer"}},"required":["id","customerId","invoiceNumber","periodStart","periodEnd","issueDate","dueDate","currency","subtotal","tax","total","amountPaid","status","overdue","notes","releasedCalls","returnedCreditNotes"],"additionalProperties":true}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","minLength":8,"maxLength":2000}},"required":["reason"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"reason":"Example"}},"x-px-billable":{"kind":"money","note":"Issues, voids or settles a billing document."}}},"/api/v1/switch/invoices/{id}/reissue":{"post":{"operationId":"postSwitchInvoicesByIdReissue","tags":["Switch: invoicing"],"summary":"Void an invoice and issue its replacement","description":"Voids this invoice and issues a replacement over the same period in one step. Preview the replacement first (with `releaseInvoiceId`) and pass its review token. If the void succeeds but the issue fails, the original stays void and its usage is unbilled; the error says so.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customerId":{"type":"string","format":"uuid"},"invoiceNumber":{"type":"string","description":"Sequential per operator, gap-free"},"periodStart":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"periodEnd":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"issueDate":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"dueDate":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"currency":{"type":"string","minLength":3,"maxLength":3},"subtotal":{"$ref":"#/components/schemas/Money"},"tax":{"$ref":"#/components/schemas/Money"},"total":{"$ref":"#/components/schemas/Money"},"amountPaid":{"$ref":"#/components/schemas/Money"},"status":{"type":"string","enum":["draft","open","partial","paid","overdue","void"]},"overdue":{"type":"boolean"},"notes":{"type":"string","nullable":true},"replacesInvoiceId":{"type":"string","format":"uuid","nullable":true},"sentAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"sendCount":{"type":"integer"},"customerLabel":{"type":"string","nullable":true,"description":"On list rows"},"replacesInvoiceNumber":{"type":"string"}},"required":["id","customerId","invoiceNumber","periodStart","periodEnd","issueDate","dueDate","currency","subtotal","tax","total","amountPaid","status","overdue","notes","replacesInvoiceNumber"],"additionalProperties":true}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["INVOICE_REVIEW_STALE","INVOICE_UNRATED_USAGE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","minLength":8,"maxLength":2000},"reviewToken":{"type":"string","minLength":8,"maxLength":120},"notes":{"type":"string","maxLength":2000,"nullable":true},"includeBroughtForward":{"type":"boolean"},"applyCredits":{"type":"boolean"},"excludeUnrated":{"type":"object","properties":{"reason":{"type":"string","minLength":8,"maxLength":2000}},"required":["reason"],"nullable":true}},"required":["reason","reviewToken"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"reason":"Example","reviewToken":"<reviewToken>"}},"x-px-billable":{"kind":"money","note":"Issues, voids or settles a billing document."}}},"/api/v1/switch/invoices/{id}/send":{"post":{"operationId":"postSwitchInvoicesByIdSend","tags":["Switch: invoicing"],"summary":"Email an invoice to its recipients","description":"Safe to repeat. Sends to the billing contacts, or to up to 20 addresses in `to`. Only accepted sends count as delivered.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Rate limit:** 60 requests per 10 minutes per caller.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"sent":{"type":"boolean"},"to":{"type":"array","items":{"type":"string"},"description":"Addresses the mail transport accepted"},"failed":{"type":"array","items":{},"description":"Addresses that could not be sent to"},"sendCount":{"type":"integer"},"sentAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true}},"required":["sent","to","failed","sendCount","sentAt"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-rate-limit":{"max":60,"window":"10 minutes"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"to":{"type":"array","items":{"type":"string","format":"email"},"maxItems":20}}}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"to":["you@example.com"]}},"x-px-billable":{"kind":"email","note":"Emails the invoice to its recipients."}}},"/api/v1/switch/invoices/{id}/print":{"get":{"operationId":"getSwitchInvoicesByIdPrint","tags":["Switch: invoicing"],"summary":"Render an invoice as printable HTML","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"The invoice as a standalone HTML document.","content":{"text/html":{"schema":{"type":"string","format":"binary"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/invoices/{id}/xml":{"get":{"operationId":"getSwitchInvoicesByIdXml","tags":["Switch: invoicing"],"summary":"Download an invoice as XML","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"The invoice as a structured XML document.","content":{"application/xml":{"schema":{"type":"string","format":"binary"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/invoices/{id}/pdf":{"get":{"operationId":"getSwitchInvoicesByIdPdf","tags":["Switch: invoicing"],"summary":"Download an invoice as PDF","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"The invoice PDF, as an attachment.","content":{"application/pdf":{"schema":{"type":"string","format":"binary"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/credit-notes":{"get":{"operationId":"getSwitchCreditNotes","tags":["Switch: invoicing"],"summary":"List credit notes","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/SwitchCreditNote"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"customerId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","required":false,"description":"Page size (default 50, max 500)","schema":{"type":"integer","minimum":1,"maximum":500}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0}}],"x-px-example":{"path":{},"query":{}}},"post":{"operationId":"postSwitchCreditNotes","tags":["Switch: invoicing"],"summary":"Issue a credit note to a customer","description":"Open credit reduces net receivables and can be applied to a later invoice with `applyCredits`. `invoiceId`, when given, must belong to the same customer.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchCreditNote"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"customerId":{"type":"string","format":"uuid"},"amount":{"type":"number","exclusiveMinimum":true,"minimum":0},"reason":{"type":"string","maxLength":2000,"nullable":true},"invoiceId":{"type":"string","format":"uuid","nullable":true}},"required":["customerId","amount"]}}}},"x-px-example":{"path":{},"query":{},"body":{"customerId":"<customerId>","amount":1}},"x-px-billable":{"kind":"money","note":"Issues, voids or settles a billing document."}}},"/api/v1/switch/ar-aging":{"get":{"operationId":"getSwitchArAging","tags":["Switch: invoicing"],"summary":"Get accounts-receivable ageing","description":"Outstanding customer invoice balances by days past due. `totalOutstanding` is net of open credit notes; the buckets are gross.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"totalOutstanding":{"type":"number","description":"US dollars as a JSON number rounded to 6 decimals (a computed figure, not a ledger string)"},"grossOutstanding":{"type":"number","description":"US dollars as a JSON number rounded to 6 decimals (a computed figure, not a ledger string)"},"creditNotesOpen":{"type":"number","description":"US dollars as a JSON number rounded to 6 decimals (a computed figure, not a ledger string)"},"openCount":{"type":"integer"},"buckets":{"type":"object","properties":{"current":{"type":"number","description":"US dollars as a JSON number rounded to 6 decimals (a computed figure, not a ledger string)"},"d1_30":{"type":"number","description":"US dollars as a JSON number rounded to 6 decimals (a computed figure, not a ledger string)"},"d31_60":{"type":"number","description":"US dollars as a JSON number rounded to 6 decimals (a computed figure, not a ledger string)"},"d61_90":{"type":"number","description":"US dollars as a JSON number rounded to 6 decimals (a computed figure, not a ledger string)"},"d90plus":{"type":"number","description":"US dollars as a JSON number rounded to 6 decimals (a computed figure, not a ledger string)"}},"required":["current","d1_30","d31_60","d61_90","d90plus"]}},"required":["totalOutstanding","grossOutstanding","creditNotesOpen","openCount","buckets"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/switch/customers/{id}/billing-settings":{"post":{"operationId":"postSwitchCustomersByIdBillingSettings","tags":["Switch: customers"],"summary":"Set a Switch customer billing cycle and payment terms","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"customerId":{"type":"string","format":"uuid"},"billingCycle":{"type":"string","nullable":true},"paymentTermsDays":{"type":"integer","nullable":true},"nextInvoiceAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true}},"required":["customerId","billingCycle","paymentTermsDays","nextInvoiceAt"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["STALE_WRITE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"billingCycle":{"type":"string","enum":["weekly","biweekly","monthly","manual"],"nullable":true},"paymentTermsDays":{"type":"integer","minimum":0,"maximum":365,"nullable":true}}}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"billingCycle":"weekly","paymentTermsDays":1}}}},"/api/v1/switch/payables":{"get":{"operationId":"getSwitchPayables","tags":["Switch: invoicing"],"summary":"List supplier payables","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"rows":{"type":"array","items":{"$ref":"#/components/schemas/SwitchPayable"}},"total":{"type":"integer"},"limit":{"type":"integer"}},"required":["rows","total","limit"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"vendorTrunkId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["draft","open","partial","paid","overdue","void"]}},{"name":"limit","in":"query","required":false,"description":"Page size (default 50, max 500)","schema":{"type":"integer","minimum":1,"maximum":500}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0}}],"x-px-example":{"path":{},"query":{}}},"post":{"operationId":"postSwitchPayables","tags":["Switch: invoicing"],"summary":"Raise a payable for a supplier trunk over a period","description":"Totals the supplier cost of the usage on that trunk in the period and claims it, so it cannot be paid twice.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchPayable"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"vendorTrunkId":{"type":"string","format":"uuid"},"periodStart":{"type":"string","description":"ISO-8601 date or timestamp; start of the billing period"},"periodEnd":{"type":"string","description":"ISO-8601 date or timestamp; end of the billing period"},"notes":{"type":"string","maxLength":2000,"nullable":true}},"required":["vendorTrunkId","periodStart","periodEnd"]}}}},"x-px-example":{"path":{},"query":{},"body":{"vendorTrunkId":"<vendorTrunkId>","periodStart":"<periodStart>","periodEnd":"<periodEnd>"}},"x-px-billable":{"kind":"money","note":"Issues, voids or settles a billing document."}}},"/api/v1/switch/payables/{id}":{"get":{"operationId":"getSwitchPayablesById","tags":["Switch: invoicing"],"summary":"Get a payable with lines and payments","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"vendorTrunkId":{"type":"string","format":"uuid"},"payableNumber":{"type":"string"},"periodStart":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"periodEnd":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"issueDate":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"dueDate":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"currency":{"type":"string","minLength":3,"maxLength":3},"subtotal":{"$ref":"#/components/schemas/Money"},"total":{"$ref":"#/components/schemas/Money"},"amountPaid":{"$ref":"#/components/schemas/Money"},"status":{"type":"string","enum":["draft","open","partial","paid","overdue","void"]},"notes":{"type":"string","nullable":true},"overdue":{"type":"boolean"},"trunkLabel":{"type":"string","nullable":true,"description":"On list rows"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"lines":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}},"payments":{"type":"array","items":{"$ref":"#/components/schemas/SwitchPayment"}},"trunk":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"label":{"type":"string"},"settlementMode":{"type":"string","nullable":true}},"required":["id","label","settlementMode"],"nullable":true}},"required":["id","vendorTrunkId","payableNumber","periodStart","periodEnd","issueDate","dueDate","currency","subtotal","total","amountPaid","status","notes","createdAt","updatedAt","lines","payments","trunk"],"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/payables/{id}/payments":{"post":{"operationId":"postSwitchPayablesByIdPayments","tags":["Switch: invoicing"],"summary":"Record a payment made to a supplier","description":"Payments larger than the outstanding balance, or against a void payable, are refused.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchPayable"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"amount":{"type":"number","exclusiveMinimum":true,"minimum":0,"description":"Amount received, in the document currency"},"method":{"type":"string","maxLength":32,"nullable":true},"reference":{"type":"string","maxLength":160,"nullable":true}},"required":["amount"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"amount":1}},"x-px-billable":{"kind":"money","note":"Issues, voids or settles a billing document."}}},"/api/v1/switch/payables/{id}/void":{"post":{"operationId":"postSwitchPayablesByIdVoid","tags":["Switch: invoicing"],"summary":"Void a payable","description":"Releases the usage it claimed so a corrected payable can pick it up. Voiding an already void payable is a no-op.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"vendorTrunkId":{"type":"string","format":"uuid"},"payableNumber":{"type":"string"},"periodStart":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"periodEnd":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"issueDate":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"dueDate":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"currency":{"type":"string","minLength":3,"maxLength":3},"subtotal":{"$ref":"#/components/schemas/Money"},"total":{"$ref":"#/components/schemas/Money"},"amountPaid":{"$ref":"#/components/schemas/Money"},"status":{"type":"string","enum":["draft","open","partial","paid","overdue","void"]},"notes":{"type":"string","nullable":true},"overdue":{"type":"boolean"},"trunkLabel":{"type":"string","nullable":true,"description":"On list rows"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"releasedCalls":{"type":"integer"}},"required":["id","vendorTrunkId","payableNumber","periodStart","periodEnd","issueDate","dueDate","currency","subtotal","total","amountPaid","status","notes","createdAt","updatedAt","releasedCalls"],"additionalProperties":true}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}},"x-px-billable":{"kind":"money","note":"Issues, voids or settles a billing document."}}},"/api/v1/switch/ap-aging":{"get":{"operationId":"getSwitchApAging","tags":["Switch: invoicing"],"summary":"Get accounts-payable ageing","description":"What you owe suppliers on open payables, by days past due.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"totalOwed":{"type":"number","description":"US dollars as a JSON number rounded to 6 decimals (a computed figure, not a ledger string)"},"openCount":{"type":"integer"},"buckets":{"type":"object","properties":{"current":{"type":"number","description":"US dollars as a JSON number rounded to 6 decimals (a computed figure, not a ledger string)"},"d1_30":{"type":"number","description":"US dollars as a JSON number rounded to 6 decimals (a computed figure, not a ledger string)"},"d31_60":{"type":"number","description":"US dollars as a JSON number rounded to 6 decimals (a computed figure, not a ledger string)"},"d61_90":{"type":"number","description":"US dollars as a JSON number rounded to 6 decimals (a computed figure, not a ledger string)"},"d90plus":{"type":"number","description":"US dollars as a JSON number rounded to 6 decimals (a computed figure, not a ledger string)"}},"required":["current","d1_30","d31_60","d61_90","d90plus"]}},"required":["totalOwed","openCount","buckets"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/switch/counterparties":{"get":{"operationId":"getSwitchCounterparties","tags":["Switch: invoicing"],"summary":"List bilateral counterparties","description":"A counterparty pairs a customer you sell to with a supplier trunk you buy from, so the two balances can be netted.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/SwitchCounterparty"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}},"post":{"operationId":"postSwitchCounterparties","tags":["Switch: invoicing"],"summary":"Create a bilateral counterparty","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchCounterparty"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":160},"customerId":{"type":"string","format":"uuid","nullable":true},"vendorTrunkId":{"type":"string","format":"uuid","nullable":true},"currency":{"type":"string","minLength":3,"maxLength":3,"nullable":true},"nettingEnabled":{"type":"boolean"},"notes":{"type":"string","maxLength":2000,"nullable":true}},"required":["name"]}}}},"x-px-example":{"path":{},"query":{},"body":{"name":"Acme"}}}},"/api/v1/switch/counterparties/{id}":{"patch":{"operationId":"patchSwitchCounterpartiesById","tags":["Switch: invoicing"],"summary":"Update a bilateral counterparty","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchCounterparty"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":160},"customerId":{"type":"string","format":"uuid","nullable":true},"vendorTrunkId":{"type":"string","format":"uuid","nullable":true},"currency":{"type":"string","minLength":3,"maxLength":3,"nullable":true},"nettingEnabled":{"type":"boolean"},"notes":{"type":"string","maxLength":2000,"nullable":true}}}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"name":"Acme","customerId":"<customerId>"}}},"delete":{"operationId":"deleteSwitchCounterpartiesById","tags":["Switch: invoicing"],"summary":"Delete a bilateral counterparty","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"deleted":{"type":"boolean","enum":[true]}},"required":["deleted"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/counterparties/{id}/netting":{"post":{"operationId":"postSwitchCounterpartiesByIdNetting","tags":["Switch: invoicing"],"summary":"Run netting for a counterparty over a period","description":"Open receivables (less issued credit notes) minus open payables in the period give one net figure and direction. The run is recorded as final and fires the `netting.run` webhook; the money itself moves off-platform.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"counterpartyId":{"type":"string","format":"uuid"},"counterpartyName":{"type":"string"},"periodStart":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"periodEnd":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"arTotal":{"$ref":"#/components/schemas/Money"},"apTotal":{"$ref":"#/components/schemas/Money"},"netAmount":{"allOf":[{"$ref":"#/components/schemas/Money"}],"description":"Absolute net amount; see direction"},"direction":{"type":"string","enum":["receivable","payable","settled"]},"status":{"type":"string"},"notes":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","counterpartyId","counterpartyName","periodStart","periodEnd","arTotal","apTotal","netAmount","direction","status","notes","createdAt"],"additionalProperties":true}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"periodStart":{"type":"string","description":"ISO date or datetime"},"periodEnd":{"type":"string","description":"ISO date or datetime (exclusive)"},"notes":{"type":"string","maxLength":2000,"nullable":true}},"required":["periodStart","periodEnd"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"periodStart":"<periodStart>","periodEnd":"<periodEnd>"}}}},"/api/v1/switch/netting-runs":{"get":{"operationId":"getSwitchNettingRuns","tags":["Switch: invoicing"],"summary":"List netting runs","description":"Settlements that offset what a bilateral counterparty owes you against what you owe them (latest 200).\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"counterpartyId":{"type":"string","format":"uuid"},"counterpartyName":{"type":"string","nullable":true},"periodStart":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"periodEnd":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"arTotal":{"$ref":"#/components/schemas/Money"},"apTotal":{"$ref":"#/components/schemas/Money"},"netAmount":{"$ref":"#/components/schemas/Money"},"direction":{"type":"string"},"status":{"type":"string"},"notes":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","counterpartyId","counterpartyName","periodStart","periodEnd","arTotal","apTotal","netAmount","direction","status","notes","createdAt"],"additionalProperties":true}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"counterpartyId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/switch/analytics/overview":{"get":{"operationId":"getSwitchAnalyticsOverview","tags":["Switch: CDRs and analytics"],"summary":"Get margin and quality totals for all traffic","description":"Revenue, cost, margin, ASR and minutes across every customer and supplier over the window, plus how much billed traffic carries no supplier cost yet.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"revenue":{"type":"number","description":"US dollars as a JSON number rounded to 6 decimals (a computed figure, not a ledger string)"},"cost":{"type":"number","description":"US dollars as a JSON number rounded to 6 decimals (a computed figure, not a ledger string)"},"margin":{"type":"number","description":"US dollars as a JSON number rounded to 6 decimals (a computed figure, not a ledger string)"},"marginPct":{"type":"number","nullable":true,"description":"null when there was no revenue"},"calls":{"type":"integer"},"answered":{"type":"integer"},"minutes":{"type":"number"},"asr":{"type":"number","nullable":true,"description":"Answer rate in percent; null when there were no calls"},"window":{"type":"object","properties":{"from":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"to":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"label":{"type":"string"}},"required":["from","to","label"]},"freshness":{"type":"object","properties":{},"additionalProperties":true},"rating":{"type":"object","properties":{"unratedBilled":{"type":"integer"},"billedCalls":{"type":"integer"},"unratedPct":{"type":"number"},"unratedRevenue":{"type":"number","description":"US dollars as a JSON number rounded to 6 decimals (a computed figure, not a ledger string)"},"unratedMinutes":{"type":"number"}},"required":["unratedBilled","billedCalls","unratedPct","unratedRevenue","unratedMinutes"]}},"required":["revenue","cost","margin","marginPct","calls","answered","minutes","asr","window","freshness","rating"],"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"from","in":"query","required":false,"description":"ISO-8601 start (default: 30 days before to)","schema":{"type":"string"}},{"name":"to","in":"query","required":false,"description":"ISO-8601 end (default: now)","schema":{"type":"string"}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/switch/analytics/timeseries":{"get":{"operationId":"getSwitchAnalyticsTimeseries","tags":["Switch: CDRs and analytics"],"summary":"Get daily margin and quality figures","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"revenue":{"type":"number","description":"US dollars as a JSON number rounded to 6 decimals (a computed figure, not a ledger string)"},"cost":{"type":"number","description":"US dollars as a JSON number rounded to 6 decimals (a computed figure, not a ledger string)"},"margin":{"type":"number","description":"US dollars as a JSON number rounded to 6 decimals (a computed figure, not a ledger string)"},"marginPct":{"type":"number","nullable":true,"description":"null when there was no revenue"},"calls":{"type":"integer"},"answered":{"type":"integer"},"minutes":{"type":"number"},"asr":{"type":"number","nullable":true,"description":"Answer rate in percent; null when there were no calls"},"day":{"type":"string"}},"required":["revenue","cost","margin","marginPct","calls","answered","minutes","asr","day"],"additionalProperties":true}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"from","in":"query","required":false,"description":"ISO-8601 start (default: 30 days before to)","schema":{"type":"string"}},{"name":"to","in":"query","required":false,"description":"ISO-8601 end (default: now)","schema":{"type":"string"}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/switch/analytics/breakdown":{"get":{"operationId":"getSwitchAnalyticsBreakdown","tags":["Switch: CDRs and analytics"],"summary":"Break down margin and quality by customer, supplier or destination","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"revenue":{"type":"number","description":"US dollars as a JSON number rounded to 6 decimals (a computed figure, not a ledger string)"},"cost":{"type":"number","description":"US dollars as a JSON number rounded to 6 decimals (a computed figure, not a ledger string)"},"margin":{"type":"number","description":"US dollars as a JSON number rounded to 6 decimals (a computed figure, not a ledger string)"},"marginPct":{"type":"number","nullable":true,"description":"null when there was no revenue"},"calls":{"type":"integer"},"answered":{"type":"integer"},"minutes":{"type":"number"},"asr":{"type":"number","nullable":true,"description":"Answer rate in percent; null when there were no calls"},"key":{"type":"string"},"label":{"type":"string"},"external":{"type":"boolean"}},"required":["revenue","cost","margin","marginPct","calls","answered","minutes","asr","key","label"],"additionalProperties":true}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"from","in":"query","required":false,"description":"ISO-8601 start (default: 30 days before to)","schema":{"type":"string"}},{"name":"to","in":"query","required":false,"description":"ISO-8601 end (default: now)","schema":{"type":"string"}},{"name":"by","in":"query","required":false,"description":"Default customer","schema":{"type":"string","enum":["customer","supplier","destination"]}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/switch/analytics/drilldown":{"get":{"operationId":"getSwitchAnalyticsDrilldown","tags":["Switch: CDRs and analytics"],"summary":"Drill into one customer, supplier or destination","description":"One Breakdown row (or a pair of them) over the same window: totals, daily figures, and the split by every dimension not already chosen (customer, supplier, destination, and the customer's trunks once a customer is chosen). Filters take the `key` values the Breakdown rows return. Totals equal the Breakdown row they came from, and each split adds up to the totals; a split lists at most 50 rows and folds the rest into one row keyed `__other__`. The supplier split includes calls that reached no supplier (key `none`).\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"window":{"type":"object","properties":{"from":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"to":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"label":{"type":"string"}},"required":["from","to","label"]},"path":{"type":"object","properties":{},"additionalProperties":true},"totals":{"type":"object","properties":{"revenue":{"type":"number","description":"US dollars as a JSON number rounded to 6 decimals (a computed figure, not a ledger string)"},"cost":{"type":"number","description":"US dollars as a JSON number rounded to 6 decimals (a computed figure, not a ledger string)"},"margin":{"type":"number","description":"US dollars as a JSON number rounded to 6 decimals (a computed figure, not a ledger string)"},"marginPct":{"type":"number","nullable":true,"description":"null when there was no revenue"},"calls":{"type":"integer"},"answered":{"type":"integer"},"minutes":{"type":"number"},"asr":{"type":"number","nullable":true,"description":"Answer rate in percent; null when there were no calls"}},"required":["revenue","cost","margin","marginPct","calls","answered","minutes","asr"],"additionalProperties":true},"daily":{"type":"array","items":{"type":"object","properties":{"revenue":{"type":"number","description":"US dollars as a JSON number rounded to 6 decimals (a computed figure, not a ledger string)"},"cost":{"type":"number","description":"US dollars as a JSON number rounded to 6 decimals (a computed figure, not a ledger string)"},"margin":{"type":"number","description":"US dollars as a JSON number rounded to 6 decimals (a computed figure, not a ledger string)"},"marginPct":{"type":"number","nullable":true,"description":"null when there was no revenue"},"calls":{"type":"integer"},"answered":{"type":"integer"},"minutes":{"type":"number"},"asr":{"type":"number","nullable":true,"description":"Answer rate in percent; null when there were no calls"},"day":{"type":"string"}},"required":["revenue","cost","margin","marginPct","calls","answered","minutes","asr","day"],"additionalProperties":true}},"splits":{"type":"object","additionalProperties":{"type":"array","items":{"type":"object","properties":{"revenue":{"type":"number","description":"US dollars as a JSON number rounded to 6 decimals (a computed figure, not a ledger string)"},"cost":{"type":"number","description":"US dollars as a JSON number rounded to 6 decimals (a computed figure, not a ledger string)"},"margin":{"type":"number","description":"US dollars as a JSON number rounded to 6 decimals (a computed figure, not a ledger string)"},"marginPct":{"type":"number","nullable":true,"description":"null when there was no revenue"},"calls":{"type":"integer"},"answered":{"type":"integer"},"minutes":{"type":"number"},"asr":{"type":"number","nullable":true,"description":"Answer rate in percent; null when there were no calls"},"key":{"type":"string"},"label":{"type":"string"},"drillable":{"type":"boolean"},"external":{"type":"boolean"},"otherCount":{"type":"integer"}},"required":["revenue","cost","margin","marginPct","calls","answered","minutes","asr","key","label","drillable"],"additionalProperties":true}}}},"required":["window","path","totals","daily","splits"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"from","in":"query","required":false,"description":"ISO-8601 start (default: 30 days before to)","schema":{"type":"string"}},{"name":"to","in":"query","required":false,"description":"ISO-8601 end (default: now)","schema":{"type":"string"}},{"name":"customerId","in":"query","required":false,"description":"A customer row key","schema":{"type":"string","format":"uuid"}},{"name":"supplier","in":"query","required":false,"description":"A supplier row key: trunk:<id>, route:<id> or none","schema":{"type":"string"}},{"name":"destination","in":"query","required":false,"description":"A destination row key, such as 44|United Kingdom|Mobile O2","schema":{"type":"string"}},{"name":"customerTrunkId","in":"query","required":false,"description":"A trunk split row key (customer trunk id or none); needs customerId","schema":{"type":"string"}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/switch/fraud/cli-watch":{"get":{"operationId":"getSwitchFraudCliWatch","tags":["Switch: operations"],"summary":"See which caller IDs are presented, and by whom","description":"Observe only: nothing here blocks traffic. `wouldBlock` states how much real traffic a \"same caller ID N times\" rule would refuse before anyone enables one.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"hours":{"type":"number"},"minCalls":{"type":"integer"},"watch":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}},"spoofingSuspects":{"type":"integer"},"wouldBlock":{"type":"object","properties":{"clis":{"type":"integer"},"calls":{"type":"integer"},"totalCalls":{"type":"integer"},"percent":{"type":"number"}},"required":["clis","calls","totalCalls","percent"]}},"required":["hours","minCalls","watch","spoofingSuspects","wouldBlock"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"hours","in":"query","required":false,"schema":{"type":"number"}},{"name":"minCalls","in":"query","required":false,"schema":{"type":"integer"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer"}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/switch/fraud/ani-watch":{"get":{"operationId":"getSwitchFraudAniWatch","tags":["Switch: operations"],"summary":"See which senders rotate through many caller IDs","description":"Observe only. Per sender, how many distinct caller IDs were presented in the window.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{},"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"hours","in":"query","required":false,"schema":{"type":"number"}},{"name":"minCalls","in":"query","required":false,"schema":{"type":"integer"}},{"name":"maxDistinct","in":"query","required":false,"schema":{"type":"integer"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer"}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/switch/fraud/settings":{"get":{"operationId":"getSwitchFraudSettings","tags":["Switch: operations"],"summary":"Get fraud screening settings","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchFraudSettings"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}},"post":{"operationId":"postSwitchFraudSettings","tags":["Switch: operations"],"summary":"Update fraud screening settings","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchFraudSettings"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"fraudEnabled":{"type":"boolean"},"fraudBlockScore":{"type":"integer","minimum":1,"maximum":100,"description":"Risk score at or above which a call is refused"},"fraudAlertScore":{"type":"integer","minimum":1,"maximum":100,"description":"Risk score at or above which a call is flagged"},"highRiskPrefixes":{"type":"array","items":{"type":"string","maxLength":24},"maxItems":500}}}}}},"x-px-example":{"path":{},"query":{},"body":{"fraudEnabled":true,"fraudBlockScore":1}}}},"/api/v1/switch/fraud/events":{"get":{"operationId":"getSwitchFraudEvents","tags":["Switch: operations"],"summary":"List fraud screening events","description":"Calls that were flagged or blocked by fraud screening, newest first.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"customerLabel":{"type":"string","nullable":true}},"required":["id","createdAt","customerLabel"],"additionalProperties":true}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/switch/operations-queue":{"get":{"operationId":"getSwitchOperationsQueue","tags":["Switch: operations"],"summary":"List what needs attention first on the switch","description":"Derived on every request from live trunk state, 24-hour margin and post-dial delay, rating and deck provenance. Each item carries the same issue reference used everywhere else.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"priority":{"type":"string"},"kind":{"type":"string","enum":["trunk","margin","quality","fraud","rating","deck","credit","setup"]},"title":{"type":"string"},"subject":{"type":"string"},"detail":{"type":"string"},"since":{"type":"string"},"href":{"type":"string","description":"Dashboard path where it can be acted on"},"ref":{"type":"string","description":"Issue reference, e.g. OPS-3F9A1C22"},"severity":{"type":"string","enum":["critical","warning","review"]}},"required":["priority","kind","title","subject","detail","since","href","ref","severity"],"additionalProperties":true}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/switch/issues":{"get":{"operationId":"getSwitchIssues","tags":["Switch: operations"],"summary":"List operational issues","description":"Every warning the product shows comes from this list. Team members see only issues within their customer and trunk scope. Nothing here changes routing, admission or rating: issue actions only change what people see and who owns it.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/SwitchIssue"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"customerId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"customerTrunkId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"trunkId","in":"query","required":false,"description":"Supplier trunk","schema":{"type":"string","format":"uuid"}},{"name":"supplierId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"destination","in":"query","required":false,"schema":{"type":"string"}},{"name":"includeReview","in":"query","required":false,"description":"Include review-severity issues (default true)","schema":{"type":"string","enum":["true","false"]}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/switch/issues/{ref}":{"get":{"operationId":"getSwitchIssuesByRef","tags":["Switch: operations"],"summary":"Get an operational issue by reference","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchIssue"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"ref","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"ref":"<ref>"},"query":{}}}},"/api/v1/switch/issues/{ref}/timeline":{"get":{"operationId":"getSwitchIssuesByRefTimeline","tags":["Switch: operations"],"summary":"Get the history of an operational issue","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"action":{"type":"string"},"fromStatus":{"type":"string","nullable":true},"toStatus":{"type":"string","nullable":true},"note":{"type":"string","nullable":true},"at":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"by":{"type":"string","description":"Who acted, or \"the platform\" for automatic changes"}},"required":["action","fromStatus","toStatus","note","at","by"]}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"ref","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"ref":"<ref>"},"query":{}}}},"/api/v1/switch/issues/{ref}/acknowledge":{"post":{"operationId":"postSwitchIssuesByRefAcknowledge","tags":["Switch: operations"],"summary":"Acknowledge an operational issue","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"ref":{"type":"string"},"status":{"type":"string","enum":["open_unacknowledged","open_acknowledged","resolved"]}},"required":["ref","status"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"ref","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"note":{"type":"string","maxLength":1000}}}}}},"x-px-example":{"path":{"ref":"<ref>"},"query":{},"body":{"note":"Example"}}}},"/api/v1/switch/issues/{ref}/assign":{"post":{"operationId":"postSwitchIssuesByRefAssign","tags":["Switch: operations"],"summary":"Assign an operational issue to a team member","description":"Pass `userId: null` to unassign.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"ref":{"type":"string"},"ownerUserId":{"type":"string","format":"uuid","nullable":true}},"required":["ref","ownerUserId"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"ref","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","format":"uuid","nullable":true}},"required":["userId"]}}}},"x-px-example":{"path":{"ref":"<ref>"},"query":{},"body":{"userId":"<userId>"}}}},"/api/v1/switch/issues/{ref}/resolve":{"post":{"operationId":"postSwitchIssuesByRefResolve","tags":["Switch: operations"],"summary":"Resolve an operational issue","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"ref":{"type":"string"},"status":{"type":"string","enum":["open_unacknowledged","open_acknowledged","resolved"]}},"required":["ref","status"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"ref","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"resolution":{"type":"string","maxLength":2000}}}}}},"x-px-example":{"path":{"ref":"<ref>"},"query":{},"body":{"resolution":"<resolution>"}}}},"/api/v1/switch/issues/{ref}/dismiss":{"post":{"operationId":"postSwitchIssuesByRefDismiss","tags":["Switch: operations"],"summary":"Dismiss an operational issue","description":"Closes it as dismissed. It reopens automatically if the condition in `reopensWhen` occurs.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"ref":{"type":"string"},"status":{"type":"string","enum":["open_unacknowledged","open_acknowledged","resolved"]},"resolvedVia":{"type":"string","enum":["dismissed"]},"reason":{"type":"string","nullable":true},"reopensWhen":{"type":"string","nullable":true}},"required":["ref","status","resolvedVia","reason","reopensWhen"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"ref","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","maxLength":500}}}}}},"x-px-example":{"path":{"ref":"<ref>"},"query":{},"body":{"reason":"Example"}}}},"/api/v1/switch/issues/{ref}/reopen":{"post":{"operationId":"postSwitchIssuesByRefReopen","tags":["Switch: operations"],"summary":"Reopen a resolved or dismissed operational issue","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"ref":{"type":"string"},"status":{"type":"string","enum":["open_unacknowledged","open_acknowledged","resolved"]}},"required":["ref","status"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"ref","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"note":{"type":"string","maxLength":1000}}}}}},"x-px-example":{"path":{"ref":"<ref>"},"query":{},"body":{"note":"Example"}}}},"/api/v1/switch/issues/{ref}/snooze":{"post":{"operationId":"postSwitchIssuesByRefSnooze","tags":["Switch: operations"],"summary":"Snooze notifications for an operational issue","description":"Mutes notifications only; the issue stays open and visible. Up to 14 days.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"ref":{"type":"string"},"snoozedUntil":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"issueStatus":{"type":"string","enum":["open_unacknowledged","open_acknowledged","resolved"]}},"required":["ref","snoozedUntil","issueStatus"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"ref","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"minutes":{"type":"integer","minimum":1,"maximum":20160}},"required":["minutes"]}}}},"x-px-example":{"path":{"ref":"<ref>"},"query":{},"body":{"minutes":1}}}},"/api/v1/switch/cdr-exports":{"post":{"operationId":"postSwitchCdrExports","tags":["Switch: CDRs and analytics"],"summary":"Start a background call-record export","description":"Queues an export of the filtered records (body takes the same filters as GET /switch/cdrs). At most 3 exports may run at once. Numbers: a scoped API key without the `cdr:numbers` scope receives masked calling and dialled numbers (`numbersMasked` says so). Full-access keys and dashboard sessions see them in full.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"202":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchCdrExport"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["TOO_MANY_EXPORTS"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"from":{"type":"string","description":"ISO-8601 start of the window"},"to":{"type":"string","description":"ISO-8601 end of the window"},"kind":{"type":"string","enum":["voice","sms"]},"direction":{"type":"string","enum":["inbound","outbound"]},"status":{"type":"string"},"subAccountId":{"type":"string","format":"uuid","description":"Customer"},"customerTrunkId":{"type":"string","format":"uuid"},"vendorTrunkId":{"type":"string","format":"uuid","description":"Supplier trunk"},"supplierTrunkMatch":{"type":"string","enum":["selected","attempted","either"],"description":"How vendorTrunkId matches failover attempts (default selected)"},"routeGroupId":{"type":"string","format":"uuid"},"countryPrefix":{"type":"string"},"destination":{"type":"string"},"destinationName":{"type":"string"},"answeredOnly":{"type":"string","enum":["true","false"]},"answeredState":{"type":"string","enum":["answered","unanswered"]},"mediaMode":{"type":"string","enum":["direct","proxy"]},"sipCode":{"type":"integer"},"sipCodes":{"type":"string","description":"Comma-separated SIP codes (max 20)"},"q850Cause":{"type":"integer"},"q850Causes":{"type":"string","description":"Comma-separated Q.850 causes (max 20)"},"hangupCause":{"type":"string"},"durationMin":{"type":"number"},"durationMax":{"type":"number"},"pddMinMs":{"type":"number"},"pddMaxMs":{"type":"number"},"codec":{"type":"string"},"releaseParty":{"type":"string"},"ip":{"type":"string"},"ratingState":{"type":"string","enum":["rated","unrated"]},"negativeMarginOnly":{"type":"string","enum":["true","false"]},"riskMin":{"type":"number"},"attestation":{"type":"string","enum":["A","B","C"]},"search":{"type":"string","description":"Up to 20 values separated by comma, semicolon or newline"},"searchField":{"type":"string"},"searchMatch":{"type":"string","enum":["any","all"]},"sortBy":{"type":"string"},"sortDir":{"type":"string","enum":["asc","desc"]},"includeProbes":{"type":"string","enum":["true","false"],"description":"Include the platform's synthetic reachability probes (hidden by default)"},"limit":{"type":"integer","minimum":1,"maximum":500},"offset":{"type":"integer","minimum":0}}}}}},"x-px-example":{"path":{},"query":{},"body":{"from":"+447700900123","to":"+447700900123"}}},"get":{"operationId":"getSwitchCdrExports","tags":["Switch: CDRs and analytics"],"summary":"List your recent call-record exports","description":"The latest 25 Switch exports.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/SwitchCdrExport"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/switch/cdr-exports/{id}":{"get":{"operationId":"getSwitchCdrExportsById","tags":["Switch: CDRs and analytics"],"summary":"Get the status of a call-record export","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchCdrExport"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/usage":{"get":{"operationId":"getSwitchUsage","tags":["Switch: CDRs and analytics"],"summary":"Get traffic usage for one customer","description":"Totals, per-day figures, live concurrent calls and (optionally) per-destination usage for a customer (sub-account) over a window of up to 92 days (default: the last 24 hours). A longer window is clamped and says so in `window.clamped`. `live.concurrentCalls` is null when the live monitor cannot be reached.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"window":{"type":"object","properties":{"subAccountId":{"type":"string","format":"uuid"},"since":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"until":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"nextSince":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"clamped":{"type":"boolean"},"maxWindowDays":{"type":"integer"}},"required":["subAccountId","since","until","nextSince","clamped","maxWindowDays"]},"totals":{"type":"object","properties":{},"additionalProperties":true,"description":"Calls, answered, minutes, revenue, cost and rejectedAtCapacity over the window"},"daily":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true,"description":"One row per UTC day, same figures as totals plus `day`"}},"live":{"type":"object","properties":{"concurrentCalls":{"type":"integer","nullable":true}},"required":["concurrentCalls"]},"byDestination":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}}},"required":["window","totals","daily","live"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"subAccountId","in":"query","required":true,"description":"The customer to report on (required)","schema":{"type":"string","format":"uuid"}},{"name":"since","in":"query","required":false,"description":"ISO-8601 start (default: 24 hours before until)","schema":{"type":"string"}},{"name":"until","in":"query","required":false,"description":"ISO-8601 end (default: now)","schema":{"type":"string"}},{"name":"destinations","in":"query","required":false,"description":"Include the per-destination breakdown","schema":{"type":"string","enum":["true","false","1","0"]}}],"x-px-example":{"path":{},"query":{"subAccountId":"<subAccountId>"}}}},"/api/v1/switch/cdrs/{id}/audit-copy":{"post":{"operationId":"postSwitchCdrsByIdAuditCopy","tags":["Switch: CDRs and analytics"],"summary":"Record that call-record details were copied","description":"Writes an access entry to your account activity (for example when diagnostics are copied to the clipboard). Answers 202 with `{ success: true }` and no data.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"202":{"description":"Recorded. The body is `{ \"success\": true }` with no `data`.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"anyOf":[{"not":{}},{"enum":["null"],"nullable":true}],"description":"Not sent by this endpoint"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"what":{"type":"string","maxLength":64,"description":"What was copied (default \"diagnostics\")"}}}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"what":"<what>"}}}},"/api/v1/switch/cdr-filter-options":{"get":{"operationId":"getSwitchCdrFilterOptions","tags":["Switch: CDRs and analytics"],"summary":"Get the values available to filter call records by","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"ingressTrunks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"label":{"type":"string"},"owner":{"type":"string","nullable":true},"techPrefix":{"type":"string","nullable":true}},"required":["id","label","owner","techPrefix"]}},"egressTrunks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"label":{"type":"string"},"owner":{"type":"string","nullable":true},"techPrefix":{"type":"string","nullable":true}},"required":["id","label","owner","techPrefix"]}},"routeGroups":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"label":{"type":"string"},"country":{"type":"string","nullable":true}},"required":["id","label","country"]}},"hasRiskScores":{"type":"boolean"},"hasAttestation":{"type":"boolean"}},"required":["ingressTrunks","egressTrunks","routeGroups","hasRiskScores","hasAttestation"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/switch/cdr-workspace":{"get":{"operationId":"getSwitchCdrWorkspace","tags":["Switch: CDRs and analytics"],"summary":"Get your saved call-records layout","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"order":{"type":"array","items":{"type":"string"},"maxItems":60},"cols":{"type":"array","items":{"type":"string"},"maxItems":60},"compact":{"type":"boolean"},"pageSize":{"anyOf":[{"type":"number","enum":[50]},{"type":"number","enum":[100]},{"type":"number","enum":[200]}]},"widths":{"type":"object","additionalProperties":{"type":"number","minimum":48,"maximum":600}}},"nullable":true,"description":"null until a layout has been saved"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}},"put":{"operationId":"putSwitchCdrWorkspace","tags":["Switch: CDRs and analytics"],"summary":"Save your call-records layout","description":"Column order, visible columns, density, page size (50, 100 or 200) and column widths (48-600 px). Invalid values are dropped, not rejected.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"order":{"type":"array","items":{"type":"string"},"maxItems":60},"cols":{"type":"array","items":{"type":"string"},"maxItems":60},"compact":{"type":"boolean"},"pageSize":{"anyOf":[{"type":"number","enum":[50]},{"type":"number","enum":[100]},{"type":"number","enum":[200]}]},"widths":{"type":"object","additionalProperties":{"type":"number","minimum":48,"maximum":600}}}}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"order":{"type":"array","items":{"type":"string"},"maxItems":60},"cols":{"type":"array","items":{"type":"string"},"maxItems":60},"compact":{"type":"boolean"},"pageSize":{"anyOf":[{"type":"number","enum":[50]},{"type":"number","enum":[100]},{"type":"number","enum":[200]}]},"widths":{"type":"object","additionalProperties":{"type":"number","minimum":48,"maximum":600}}}}}}},"x-px-example":{"path":{},"query":{},"body":{"order":["<order>"],"cols":["<col>"]}}}},"/api/v1/switch/fraud/summary":{"get":{"operationId":"getSwitchFraudSummary","tags":["Switch: operations"],"summary":"Count fraud screening events","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"total":{"type":"integer"},"blocked":{"type":"integer"},"flagged":{"type":"integer"}},"required":["total","blocked","flagged"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/switch/fraud/baseline":{"get":{"operationId":"getSwitchFraudBaseline","tags":["Switch: operations"],"summary":"Get the learned traffic baseline used for risk scoring","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{},"additionalProperties":true,"nullable":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/switch/fraud/retrain":{"post":{"operationId":"postSwitchFraudRetrain","tags":["Switch: operations"],"summary":"Retrain the traffic baseline from recent calls","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"sampleCalls":{"type":"integer"},"baseline":{"type":"object","properties":{},"additionalProperties":true,"nullable":true}},"required":["sampleCalls","baseline"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/switch/fraud/score":{"post":{"operationId":"postSwitchFraudScore","tags":["Switch: operations"],"summary":"Score the risk of a call without placing it","description":"Dry run of the risk assessment for a customer calling a destination. An unknown customer answers 404 NOT_FOUND.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{},"additionalProperties":true,"description":"Risk score, the factors behind it and the action screening would take"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"subAccountId":{"type":"string","format":"uuid"},"destination":{"type":"string","minLength":1,"maxLength":32}},"required":["subAccountId","destination"]}}}},"x-px-example":{"path":{},"query":{},"body":{"subAccountId":"<subAccountId>","destination":"+447700900123"}}}},"/api/v1/switch/cdrs":{"get":{"operationId":"getSwitchCdrs","tags":["Switch: CDRs and analytics"],"summary":"Search call records","description":"Paged call records (one row per attempt) with a summary over the whole filtered window: calls, ASR and ACD (per call, failover collapsed), PDD median and p95, revenue, cost and margin. Long windows are clamped (see `window`). Numbers: a scoped API key without the `cdr:numbers` scope receives masked calling and dialled numbers (`numbersMasked` says so). Full-access keys and dashboard sessions see them in full.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"rows":{"type":"array","items":{"$ref":"#/components/schemas/SwitchCdr"}},"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"},"summary":{"type":"object","properties":{},"additionalProperties":true,"description":"Window totals: calls, answeredCalls, asrPercent, acdSeconds, talkSeconds, billableSeconds, pddMedianMs, pddP95Ms, revenue, cost, margin, ingestionLagSeconds..."},"numbersMasked":{"type":"boolean"},"addressesMasked":{"type":"boolean"},"fieldVisibility":{"type":"object","properties":{},"additionalProperties":true},"generatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"window":{"type":"object","properties":{"from":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"to":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"clamped":{"type":"boolean"},"maxWindowDays":{"type":"integer"}},"required":["from","to","clamped","maxWindowDays"]},"queryId":{"type":"string","description":"Stable id of the question asked, shared with exports of the same filters"}},"required":["rows","total","limit","offset","summary","numbersMasked","addressesMasked","fieldVisibility","generatedAt","window","queryId"],"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"from","in":"query","required":false,"description":"ISO-8601 start of the window","schema":{"type":"string"}},{"name":"to","in":"query","required":false,"description":"ISO-8601 end of the window","schema":{"type":"string"}},{"name":"kind","in":"query","required":false,"schema":{"type":"string","enum":["voice","sms"]}},{"name":"direction","in":"query","required":false,"schema":{"type":"string","enum":["inbound","outbound"]}},{"name":"status","in":"query","required":false,"schema":{"type":"string"}},{"name":"subAccountId","in":"query","required":false,"description":"Customer","schema":{"type":"string","format":"uuid"}},{"name":"customerTrunkId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"vendorTrunkId","in":"query","required":false,"description":"Supplier trunk","schema":{"type":"string","format":"uuid"}},{"name":"supplierTrunkMatch","in":"query","required":false,"description":"How vendorTrunkId matches failover attempts (default selected)","schema":{"type":"string","enum":["selected","attempted","either"]}},{"name":"routeGroupId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"countryPrefix","in":"query","required":false,"schema":{"type":"string"}},{"name":"destination","in":"query","required":false,"schema":{"type":"string"}},{"name":"destinationName","in":"query","required":false,"schema":{"type":"string"}},{"name":"answeredOnly","in":"query","required":false,"schema":{"type":"string","enum":["true","false"]}},{"name":"answeredState","in":"query","required":false,"schema":{"type":"string","enum":["answered","unanswered"]}},{"name":"mediaMode","in":"query","required":false,"schema":{"type":"string","enum":["direct","proxy"]}},{"name":"sipCode","in":"query","required":false,"schema":{"type":"integer"}},{"name":"sipCodes","in":"query","required":false,"description":"Comma-separated SIP codes (max 20)","schema":{"type":"string"}},{"name":"q850Cause","in":"query","required":false,"schema":{"type":"integer"}},{"name":"q850Causes","in":"query","required":false,"description":"Comma-separated Q.850 causes (max 20)","schema":{"type":"string"}},{"name":"hangupCause","in":"query","required":false,"schema":{"type":"string"}},{"name":"durationMin","in":"query","required":false,"schema":{"type":"number"}},{"name":"durationMax","in":"query","required":false,"schema":{"type":"number"}},{"name":"pddMinMs","in":"query","required":false,"schema":{"type":"number"}},{"name":"pddMaxMs","in":"query","required":false,"schema":{"type":"number"}},{"name":"codec","in":"query","required":false,"schema":{"type":"string"}},{"name":"releaseParty","in":"query","required":false,"schema":{"type":"string"}},{"name":"ip","in":"query","required":false,"schema":{"type":"string"}},{"name":"ratingState","in":"query","required":false,"schema":{"type":"string","enum":["rated","unrated"]}},{"name":"negativeMarginOnly","in":"query","required":false,"schema":{"type":"string","enum":["true","false"]}},{"name":"riskMin","in":"query","required":false,"schema":{"type":"number"}},{"name":"attestation","in":"query","required":false,"schema":{"type":"string","enum":["A","B","C"]}},{"name":"search","in":"query","required":false,"description":"Up to 20 values separated by comma, semicolon or newline","schema":{"type":"string"}},{"name":"searchField","in":"query","required":false,"schema":{"type":"string"}},{"name":"searchMatch","in":"query","required":false,"schema":{"type":"string","enum":["any","all"]}},{"name":"sortBy","in":"query","required":false,"schema":{"type":"string"}},{"name":"sortDir","in":"query","required":false,"schema":{"type":"string","enum":["asc","desc"]}},{"name":"includeProbes","in":"query","required":false,"description":"Include the platform's synthetic reachability probes (hidden by default)","schema":{"type":"string","enum":["true","false"]}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/switch/cdrs/facets":{"get":{"operationId":"getSwitchCdrsFacets","tags":["Switch: CDRs and analytics"],"summary":"Count call records by filter value","description":"For the filtered window, how many records carry each status, SIP code, customer, supplier and so on.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"queryId":{"type":"string","description":"Stable id of the question asked, shared with exports of the same filters"}},"required":["queryId"],"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"from","in":"query","required":false,"description":"ISO-8601 start of the window","schema":{"type":"string"}},{"name":"to","in":"query","required":false,"description":"ISO-8601 end of the window","schema":{"type":"string"}},{"name":"kind","in":"query","required":false,"schema":{"type":"string","enum":["voice","sms"]}},{"name":"direction","in":"query","required":false,"schema":{"type":"string","enum":["inbound","outbound"]}},{"name":"status","in":"query","required":false,"schema":{"type":"string"}},{"name":"subAccountId","in":"query","required":false,"description":"Customer","schema":{"type":"string","format":"uuid"}},{"name":"customerTrunkId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"vendorTrunkId","in":"query","required":false,"description":"Supplier trunk","schema":{"type":"string","format":"uuid"}},{"name":"supplierTrunkMatch","in":"query","required":false,"description":"How vendorTrunkId matches failover attempts (default selected)","schema":{"type":"string","enum":["selected","attempted","either"]}},{"name":"routeGroupId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"countryPrefix","in":"query","required":false,"schema":{"type":"string"}},{"name":"destination","in":"query","required":false,"schema":{"type":"string"}},{"name":"destinationName","in":"query","required":false,"schema":{"type":"string"}},{"name":"answeredOnly","in":"query","required":false,"schema":{"type":"string","enum":["true","false"]}},{"name":"answeredState","in":"query","required":false,"schema":{"type":"string","enum":["answered","unanswered"]}},{"name":"mediaMode","in":"query","required":false,"schema":{"type":"string","enum":["direct","proxy"]}},{"name":"sipCode","in":"query","required":false,"schema":{"type":"integer"}},{"name":"sipCodes","in":"query","required":false,"description":"Comma-separated SIP codes (max 20)","schema":{"type":"string"}},{"name":"q850Cause","in":"query","required":false,"schema":{"type":"integer"}},{"name":"q850Causes","in":"query","required":false,"description":"Comma-separated Q.850 causes (max 20)","schema":{"type":"string"}},{"name":"hangupCause","in":"query","required":false,"schema":{"type":"string"}},{"name":"durationMin","in":"query","required":false,"schema":{"type":"number"}},{"name":"durationMax","in":"query","required":false,"schema":{"type":"number"}},{"name":"pddMinMs","in":"query","required":false,"schema":{"type":"number"}},{"name":"pddMaxMs","in":"query","required":false,"schema":{"type":"number"}},{"name":"codec","in":"query","required":false,"schema":{"type":"string"}},{"name":"releaseParty","in":"query","required":false,"schema":{"type":"string"}},{"name":"ip","in":"query","required":false,"schema":{"type":"string"}},{"name":"ratingState","in":"query","required":false,"schema":{"type":"string","enum":["rated","unrated"]}},{"name":"negativeMarginOnly","in":"query","required":false,"schema":{"type":"string","enum":["true","false"]}},{"name":"riskMin","in":"query","required":false,"schema":{"type":"number"}},{"name":"attestation","in":"query","required":false,"schema":{"type":"string","enum":["A","B","C"]}},{"name":"search","in":"query","required":false,"description":"Up to 20 values separated by comma, semicolon or newline","schema":{"type":"string"}},{"name":"searchField","in":"query","required":false,"schema":{"type":"string"}},{"name":"searchMatch","in":"query","required":false,"schema":{"type":"string","enum":["any","all"]}},{"name":"sortBy","in":"query","required":false,"schema":{"type":"string"}},{"name":"sortDir","in":"query","required":false,"schema":{"type":"string","enum":["asc","desc"]}},{"name":"includeProbes","in":"query","required":false,"description":"Include the platform's synthetic reachability probes (hidden by default)","schema":{"type":"string","enum":["true","false"]}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/switch/cdrs/analytics":{"get":{"operationId":"getSwitchCdrsAnalytics","tags":["Switch: CDRs and analytics"],"summary":"Get charts for the filtered call records","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"queryId":{"type":"string","description":"Stable id of the question asked, shared with exports of the same filters"}},"required":["queryId"],"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"from","in":"query","required":false,"description":"ISO-8601 start of the window","schema":{"type":"string"}},{"name":"to","in":"query","required":false,"description":"ISO-8601 end of the window","schema":{"type":"string"}},{"name":"kind","in":"query","required":false,"schema":{"type":"string","enum":["voice","sms"]}},{"name":"direction","in":"query","required":false,"schema":{"type":"string","enum":["inbound","outbound"]}},{"name":"status","in":"query","required":false,"schema":{"type":"string"}},{"name":"subAccountId","in":"query","required":false,"description":"Customer","schema":{"type":"string","format":"uuid"}},{"name":"customerTrunkId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"vendorTrunkId","in":"query","required":false,"description":"Supplier trunk","schema":{"type":"string","format":"uuid"}},{"name":"supplierTrunkMatch","in":"query","required":false,"description":"How vendorTrunkId matches failover attempts (default selected)","schema":{"type":"string","enum":["selected","attempted","either"]}},{"name":"routeGroupId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"countryPrefix","in":"query","required":false,"schema":{"type":"string"}},{"name":"destination","in":"query","required":false,"schema":{"type":"string"}},{"name":"destinationName","in":"query","required":false,"schema":{"type":"string"}},{"name":"answeredOnly","in":"query","required":false,"schema":{"type":"string","enum":["true","false"]}},{"name":"answeredState","in":"query","required":false,"schema":{"type":"string","enum":["answered","unanswered"]}},{"name":"mediaMode","in":"query","required":false,"schema":{"type":"string","enum":["direct","proxy"]}},{"name":"sipCode","in":"query","required":false,"schema":{"type":"integer"}},{"name":"sipCodes","in":"query","required":false,"description":"Comma-separated SIP codes (max 20)","schema":{"type":"string"}},{"name":"q850Cause","in":"query","required":false,"schema":{"type":"integer"}},{"name":"q850Causes","in":"query","required":false,"description":"Comma-separated Q.850 causes (max 20)","schema":{"type":"string"}},{"name":"hangupCause","in":"query","required":false,"schema":{"type":"string"}},{"name":"durationMin","in":"query","required":false,"schema":{"type":"number"}},{"name":"durationMax","in":"query","required":false,"schema":{"type":"number"}},{"name":"pddMinMs","in":"query","required":false,"schema":{"type":"number"}},{"name":"pddMaxMs","in":"query","required":false,"schema":{"type":"number"}},{"name":"codec","in":"query","required":false,"schema":{"type":"string"}},{"name":"releaseParty","in":"query","required":false,"schema":{"type":"string"}},{"name":"ip","in":"query","required":false,"schema":{"type":"string"}},{"name":"ratingState","in":"query","required":false,"schema":{"type":"string","enum":["rated","unrated"]}},{"name":"negativeMarginOnly","in":"query","required":false,"schema":{"type":"string","enum":["true","false"]}},{"name":"riskMin","in":"query","required":false,"schema":{"type":"number"}},{"name":"attestation","in":"query","required":false,"schema":{"type":"string","enum":["A","B","C"]}},{"name":"search","in":"query","required":false,"description":"Up to 20 values separated by comma, semicolon or newline","schema":{"type":"string"}},{"name":"searchField","in":"query","required":false,"schema":{"type":"string"}},{"name":"searchMatch","in":"query","required":false,"schema":{"type":"string","enum":["any","all"]}},{"name":"sortBy","in":"query","required":false,"schema":{"type":"string"}},{"name":"sortDir","in":"query","required":false,"schema":{"type":"string","enum":["asc","desc"]}},{"name":"includeProbes","in":"query","required":false,"description":"Include the platform's synthetic reachability probes (hidden by default)","schema":{"type":"string","enum":["true","false"]}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/switch/cdrs/failure-summary":{"get":{"operationId":"getSwitchCdrsFailureSummary","tags":["Switch: CDRs and analytics"],"summary":"Break down failed calls by stage and reason","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"queryId":{"type":"string","description":"Stable id of the question asked, shared with exports of the same filters"}},"required":["queryId"],"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"from","in":"query","required":false,"description":"ISO-8601 start of the window","schema":{"type":"string"}},{"name":"to","in":"query","required":false,"description":"ISO-8601 end of the window","schema":{"type":"string"}},{"name":"kind","in":"query","required":false,"schema":{"type":"string","enum":["voice","sms"]}},{"name":"direction","in":"query","required":false,"schema":{"type":"string","enum":["inbound","outbound"]}},{"name":"status","in":"query","required":false,"schema":{"type":"string"}},{"name":"subAccountId","in":"query","required":false,"description":"Customer","schema":{"type":"string","format":"uuid"}},{"name":"customerTrunkId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"vendorTrunkId","in":"query","required":false,"description":"Supplier trunk","schema":{"type":"string","format":"uuid"}},{"name":"supplierTrunkMatch","in":"query","required":false,"description":"How vendorTrunkId matches failover attempts (default selected)","schema":{"type":"string","enum":["selected","attempted","either"]}},{"name":"routeGroupId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"countryPrefix","in":"query","required":false,"schema":{"type":"string"}},{"name":"destination","in":"query","required":false,"schema":{"type":"string"}},{"name":"destinationName","in":"query","required":false,"schema":{"type":"string"}},{"name":"answeredOnly","in":"query","required":false,"schema":{"type":"string","enum":["true","false"]}},{"name":"answeredState","in":"query","required":false,"schema":{"type":"string","enum":["answered","unanswered"]}},{"name":"mediaMode","in":"query","required":false,"schema":{"type":"string","enum":["direct","proxy"]}},{"name":"sipCode","in":"query","required":false,"schema":{"type":"integer"}},{"name":"sipCodes","in":"query","required":false,"description":"Comma-separated SIP codes (max 20)","schema":{"type":"string"}},{"name":"q850Cause","in":"query","required":false,"schema":{"type":"integer"}},{"name":"q850Causes","in":"query","required":false,"description":"Comma-separated Q.850 causes (max 20)","schema":{"type":"string"}},{"name":"hangupCause","in":"query","required":false,"schema":{"type":"string"}},{"name":"durationMin","in":"query","required":false,"schema":{"type":"number"}},{"name":"durationMax","in":"query","required":false,"schema":{"type":"number"}},{"name":"pddMinMs","in":"query","required":false,"schema":{"type":"number"}},{"name":"pddMaxMs","in":"query","required":false,"schema":{"type":"number"}},{"name":"codec","in":"query","required":false,"schema":{"type":"string"}},{"name":"releaseParty","in":"query","required":false,"schema":{"type":"string"}},{"name":"ip","in":"query","required":false,"schema":{"type":"string"}},{"name":"ratingState","in":"query","required":false,"schema":{"type":"string","enum":["rated","unrated"]}},{"name":"negativeMarginOnly","in":"query","required":false,"schema":{"type":"string","enum":["true","false"]}},{"name":"riskMin","in":"query","required":false,"schema":{"type":"number"}},{"name":"attestation","in":"query","required":false,"schema":{"type":"string","enum":["A","B","C"]}},{"name":"search","in":"query","required":false,"description":"Up to 20 values separated by comma, semicolon or newline","schema":{"type":"string"}},{"name":"searchField","in":"query","required":false,"schema":{"type":"string"}},{"name":"searchMatch","in":"query","required":false,"schema":{"type":"string","enum":["any","all"]}},{"name":"sortBy","in":"query","required":false,"schema":{"type":"string"}},{"name":"sortDir","in":"query","required":false,"schema":{"type":"string","enum":["asc","desc"]}},{"name":"includeProbes","in":"query","required":false,"description":"Include the platform's synthetic reachability probes (hidden by default)","schema":{"type":"string","enum":["true","false"]}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/switch/cdrs/failure-groups":{"get":{"operationId":"getSwitchCdrsFailureGroups","tags":["Switch: CDRs and analytics"],"summary":"Group failed calls by the dimensions they share","description":"Clusters failures (for example one supplier, one destination, one SIP code) so a pattern reads as one problem.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"queryId":{"type":"string","description":"Stable id of the question asked, shared with exports of the same filters"}},"required":["queryId"],"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"from","in":"query","required":false,"description":"ISO-8601 start of the window","schema":{"type":"string"}},{"name":"to","in":"query","required":false,"description":"ISO-8601 end of the window","schema":{"type":"string"}},{"name":"kind","in":"query","required":false,"schema":{"type":"string","enum":["voice","sms"]}},{"name":"direction","in":"query","required":false,"schema":{"type":"string","enum":["inbound","outbound"]}},{"name":"status","in":"query","required":false,"schema":{"type":"string"}},{"name":"subAccountId","in":"query","required":false,"description":"Customer","schema":{"type":"string","format":"uuid"}},{"name":"customerTrunkId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"vendorTrunkId","in":"query","required":false,"description":"Supplier trunk","schema":{"type":"string","format":"uuid"}},{"name":"supplierTrunkMatch","in":"query","required":false,"description":"How vendorTrunkId matches failover attempts (default selected)","schema":{"type":"string","enum":["selected","attempted","either"]}},{"name":"routeGroupId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"countryPrefix","in":"query","required":false,"schema":{"type":"string"}},{"name":"destination","in":"query","required":false,"schema":{"type":"string"}},{"name":"destinationName","in":"query","required":false,"schema":{"type":"string"}},{"name":"answeredOnly","in":"query","required":false,"schema":{"type":"string","enum":["true","false"]}},{"name":"answeredState","in":"query","required":false,"schema":{"type":"string","enum":["answered","unanswered"]}},{"name":"mediaMode","in":"query","required":false,"schema":{"type":"string","enum":["direct","proxy"]}},{"name":"sipCode","in":"query","required":false,"schema":{"type":"integer"}},{"name":"sipCodes","in":"query","required":false,"description":"Comma-separated SIP codes (max 20)","schema":{"type":"string"}},{"name":"q850Cause","in":"query","required":false,"schema":{"type":"integer"}},{"name":"q850Causes","in":"query","required":false,"description":"Comma-separated Q.850 causes (max 20)","schema":{"type":"string"}},{"name":"hangupCause","in":"query","required":false,"schema":{"type":"string"}},{"name":"durationMin","in":"query","required":false,"schema":{"type":"number"}},{"name":"durationMax","in":"query","required":false,"schema":{"type":"number"}},{"name":"pddMinMs","in":"query","required":false,"schema":{"type":"number"}},{"name":"pddMaxMs","in":"query","required":false,"schema":{"type":"number"}},{"name":"codec","in":"query","required":false,"schema":{"type":"string"}},{"name":"releaseParty","in":"query","required":false,"schema":{"type":"string"}},{"name":"ip","in":"query","required":false,"schema":{"type":"string"}},{"name":"ratingState","in":"query","required":false,"schema":{"type":"string","enum":["rated","unrated"]}},{"name":"negativeMarginOnly","in":"query","required":false,"schema":{"type":"string","enum":["true","false"]}},{"name":"riskMin","in":"query","required":false,"schema":{"type":"number"}},{"name":"attestation","in":"query","required":false,"schema":{"type":"string","enum":["A","B","C"]}},{"name":"search","in":"query","required":false,"description":"Up to 20 values separated by comma, semicolon or newline","schema":{"type":"string"}},{"name":"searchField","in":"query","required":false,"schema":{"type":"string"}},{"name":"searchMatch","in":"query","required":false,"schema":{"type":"string","enum":["any","all"]}},{"name":"sortBy","in":"query","required":false,"schema":{"type":"string"}},{"name":"sortDir","in":"query","required":false,"schema":{"type":"string","enum":["asc","desc"]}},{"name":"includeProbes","in":"query","required":false,"description":"Include the platform's synthetic reachability probes (hidden by default)","schema":{"type":"string","enum":["true","false"]}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0}},{"name":"dims","in":"query","required":false,"description":"Comma-separated grouping dimensions","schema":{"type":"string"}},{"name":"destinationDigits","in":"query","required":false,"schema":{"type":"integer"}},{"name":"bucket","in":"query","required":false,"schema":{"type":"string","enum":["day","hour"]}},{"name":"minSessions","in":"query","required":false,"schema":{"type":"integer"}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/switch/call-filters":{"get":{"operationId":"getSwitchCallFilters","tags":["Switch: CDRs and analytics"],"summary":"Get the call-filter vocabulary","description":"The shared filter names and closed value sets used by call records, quality and live calls.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","additionalProperties":{}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/switch/list-filters":{"get":{"operationId":"getSwitchListFilters","tags":["Switch: CDRs and analytics"],"summary":"Get the list-filter vocabulary","description":"Filter names and value sets for the customer, supplier and trunk lists.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","additionalProperties":{}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/switch/cdrs/{id}":{"get":{"operationId":"getSwitchCdrsById","tags":["Switch: CDRs and analytics"],"summary":"Get one call record with attempts, SIP trace and timeline","description":"Numbers: a scoped API key without the `cdr:numbers` scope receives masked calling and dialled numbers (`numbersMasked` says so). Full-access keys and dashboard sessions see them in full. A record that is not yours answers 404 NOT_FOUND.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"kind":{"type":"string","enum":["voice","sms"]},"direction":{"type":"string"},"from":{"type":"string","nullable":true},"to":{"type":"string","nullable":true},"cli":{"type":"string","nullable":true},"status":{"type":"string"},"sipCode":{"type":"integer","nullable":true},"hangupCause":{"type":"string","nullable":true},"durationSeconds":{"type":"integer","nullable":true},"billedSeconds":{"type":"integer","nullable":true},"segments":{"type":"integer","nullable":true},"pddMs":{"type":"integer","nullable":true},"callGroupId":{"type":"string","nullable":true,"description":"Shared by every failover attempt of one call"},"customer":{"type":"string","nullable":true},"supplier":{"type":"string","nullable":true},"revenue":{"type":"number","description":"US dollars as a JSON number rounded to 6 decimals (a computed figure, not a ledger string)"},"cost":{"type":"number","description":"US dollars as a JSON number rounded to 6 decimals (a computed figure, not a ledger string)"},"margin":{"type":"number","description":"US dollars as a JSON number rounded to 6 decimals (a computed figure, not a ledger string)"},"sellRatePerUnit":{"type":"number","nullable":true,"description":"null when the call could not be rated (distinct from a real 0)"},"buyRatePerUnit":{"type":"number","nullable":true,"description":"US dollars as a JSON number rounded to 6 decimals (a computed figure, not a ledger string)"},"ratingState":{"type":"string","nullable":true},"mos":{"type":"number","nullable":true},"jitterMs":{"type":"number","nullable":true},"packetLossPct":{"type":"number","nullable":true},"mediaMode":{"type":"string","nullable":true},"codec":{"type":"string","nullable":true},"q850Cause":{"type":"integer","nullable":true},"destinationName":{"type":"string","nullable":true},"riskScore":{"type":"number","nullable":true},"attestation":{"type":"string","nullable":true},"customerTrunkId":{"type":"string","format":"uuid","nullable":true},"attemptCount":{"type":"integer"},"invoiceId":{"type":"string","format":"uuid","nullable":true},"attempts":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true},"description":"Every supplier attempt of this call, including skipped candidates"},"trace":{"type":"object","properties":{},"additionalProperties":true,"nullable":true,"description":"The captured SIP messages, when available"},"timeline":{"type":"object","properties":{"startedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"startedFrom":{"type":"string","enum":["first_sip_message","first_supplier_attempt"],"nullable":true},"answeredAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"endedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"recordedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true}},"required":["startedAt","startedFrom","answeredAt","endedAt","recordedAt"]}},"required":["id","createdAt","kind","direction","from","to","cli","status","sipCode","hangupCause","durationSeconds","billedSeconds","segments","pddMs","callGroupId","customer","supplier","revenue","cost","margin","sellRatePerUnit","buyRatePerUnit","ratingState","mos","jitterMs","packetLossPct","mediaMode","codec","q850Cause","destinationName","attempts","trace","timeline"],"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/cdrs/{id}/attempts":{"get":{"operationId":"getSwitchCdrsByIdAttempts","tags":["Switch: CDRs and analytics"],"summary":"List the supplier attempts of a call","description":"A record that is not yours answers 404 NOT_FOUND.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/cdr-views":{"get":{"operationId":"getSwitchCdrViews","tags":["Switch: CDRs and analytics"],"summary":"List saved call-record views","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/SwitchCdrView"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}},"post":{"operationId":"postSwitchCdrViews","tags":["Switch: CDRs and analytics"],"summary":"Save a call-record view","description":"Creates the view, or replaces the one with the same name.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchCdrView"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"service":{"type":"string","enum":["voice","sms"]},"filters":{"type":"object","additionalProperties":{}},"columns":{"type":"array","items":{"type":"string","maxLength":64},"maxItems":60},"sort":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string","maxLength":64},"direction":{"type":"string","enum":["asc","desc"]}},"required":["field","direction"]},"maxItems":4},"isDefault":{"type":"boolean"}},"required":["name"]}}}},"x-px-example":{"path":{},"query":{},"body":{"name":"Acme"}}}},"/api/v1/switch/cdr-views/{viewId}":{"delete":{"operationId":"deleteSwitchCdrViewsByViewId","tags":["Switch: CDRs and analytics"],"summary":"Delete a saved call-record view","description":"Answers `{ success: true }` with no data, whether or not the view existed.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Deleted. The body is `{ \"success\": true }` with no `data`.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"anyOf":[{"not":{}},{"enum":["null"],"nullable":true}],"description":"Not sent by this endpoint"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"viewId","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"viewId":"<viewId>"},"query":{}}}},"/api/v1/switch/cdrs/{id}/trace":{"get":{"operationId":"getSwitchCdrsByIdTrace","tags":["Switch: CDRs and analytics"],"summary":"Get the SIP trace of a call","description":"The signalling ladder for the call. Access is recorded in your account activity. A record that is not yours answers 404 NOT_FOUND.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{},"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/cdrs/{id}/retest":{"post":{"operationId":"postSwitchCdrsByIdRetest","tags":["Switch: CDRs and analytics"],"summary":"Re-run routing for a call record","description":"Resolves the route this call would take now, without placing a call, so a fix can be checked against the original failure.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Rate limit:** 10 requests per minute per caller.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{},"additionalProperties":true}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-rate-limit":{"max":10,"window":"minute"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/cdrs.csv":{"get":{"operationId":"getSwitchCdrsCsv","tags":["Switch: CDRs and analytics"],"summary":"Download filtered call records as CSV","description":"Synchronous export, capped at a row ceiling; `X-PKX-Row-Count`, `X-PKX-Truncated` and `X-PKX-Query-Id` headers describe the file. For large windows use POST /switch/cdr-exports. Numbers: a scoped API key without the `cdr:numbers` scope receives masked calling and dialled numbers (`numbersMasked` says so). Full-access keys and dashboard sessions see them in full.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"CSV of the filtered call records, as an attachment.","content":{"text/csv":{"schema":{"type":"string","format":"binary"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"from","in":"query","required":false,"description":"ISO-8601 start of the window","schema":{"type":"string"}},{"name":"to","in":"query","required":false,"description":"ISO-8601 end of the window","schema":{"type":"string"}},{"name":"kind","in":"query","required":false,"schema":{"type":"string","enum":["voice","sms"]}},{"name":"direction","in":"query","required":false,"schema":{"type":"string","enum":["inbound","outbound"]}},{"name":"status","in":"query","required":false,"schema":{"type":"string"}},{"name":"subAccountId","in":"query","required":false,"description":"Customer","schema":{"type":"string","format":"uuid"}},{"name":"customerTrunkId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"vendorTrunkId","in":"query","required":false,"description":"Supplier trunk","schema":{"type":"string","format":"uuid"}},{"name":"supplierTrunkMatch","in":"query","required":false,"description":"How vendorTrunkId matches failover attempts (default selected)","schema":{"type":"string","enum":["selected","attempted","either"]}},{"name":"routeGroupId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"countryPrefix","in":"query","required":false,"schema":{"type":"string"}},{"name":"destination","in":"query","required":false,"schema":{"type":"string"}},{"name":"destinationName","in":"query","required":false,"schema":{"type":"string"}},{"name":"answeredOnly","in":"query","required":false,"schema":{"type":"string","enum":["true","false"]}},{"name":"answeredState","in":"query","required":false,"schema":{"type":"string","enum":["answered","unanswered"]}},{"name":"mediaMode","in":"query","required":false,"schema":{"type":"string","enum":["direct","proxy"]}},{"name":"sipCode","in":"query","required":false,"schema":{"type":"integer"}},{"name":"sipCodes","in":"query","required":false,"description":"Comma-separated SIP codes (max 20)","schema":{"type":"string"}},{"name":"q850Cause","in":"query","required":false,"schema":{"type":"integer"}},{"name":"q850Causes","in":"query","required":false,"description":"Comma-separated Q.850 causes (max 20)","schema":{"type":"string"}},{"name":"hangupCause","in":"query","required":false,"schema":{"type":"string"}},{"name":"durationMin","in":"query","required":false,"schema":{"type":"number"}},{"name":"durationMax","in":"query","required":false,"schema":{"type":"number"}},{"name":"pddMinMs","in":"query","required":false,"schema":{"type":"number"}},{"name":"pddMaxMs","in":"query","required":false,"schema":{"type":"number"}},{"name":"codec","in":"query","required":false,"schema":{"type":"string"}},{"name":"releaseParty","in":"query","required":false,"schema":{"type":"string"}},{"name":"ip","in":"query","required":false,"schema":{"type":"string"}},{"name":"ratingState","in":"query","required":false,"schema":{"type":"string","enum":["rated","unrated"]}},{"name":"negativeMarginOnly","in":"query","required":false,"schema":{"type":"string","enum":["true","false"]}},{"name":"riskMin","in":"query","required":false,"schema":{"type":"number"}},{"name":"attestation","in":"query","required":false,"schema":{"type":"string","enum":["A","B","C"]}},{"name":"search","in":"query","required":false,"description":"Up to 20 values separated by comma, semicolon or newline","schema":{"type":"string"}},{"name":"searchField","in":"query","required":false,"schema":{"type":"string"}},{"name":"searchMatch","in":"query","required":false,"schema":{"type":"string","enum":["any","all"]}},{"name":"sortBy","in":"query","required":false,"schema":{"type":"string"}},{"name":"sortDir","in":"query","required":false,"schema":{"type":"string","enum":["asc","desc"]}},{"name":"includeProbes","in":"query","required":false,"description":"Include the platform's synthetic reachability probes (hidden by default)","schema":{"type":"string","enum":["true","false"]}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/switch/live":{"get":{"operationId":"getSwitchLive","tags":["Switch: operations"],"summary":"List calls in progress","description":"Calls up now, from the live monitor. Filters narrow the list; `unsupported` names any requested filter this surface cannot apply.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"population":{},"supports":{"type":"array","items":{"type":"string"}},"unsupported":{"type":"array","items":{"type":"string"}}},"required":["supports","unsupported"],"additionalProperties":true,"description":"Live calls plus the filter vocabulary this surface supports"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"subAccountId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"countryPrefix","in":"query","required":false,"schema":{"type":"string","maxLength":64}},{"name":"destination","in":"query","required":false,"schema":{"type":"string","maxLength":64}},{"name":"kind","in":"query","required":false,"schema":{"type":"string","enum":["voice","sms"]}},{"name":"answeredState","in":"query","required":false,"schema":{"type":"string","enum":["answered","unanswered"]}},{"name":"supplierName","in":"query","required":false,"schema":{"type":"string","maxLength":64}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/switch/live/geo":{"get":{"operationId":"getSwitchLiveGeo","tags":["Switch: operations"],"summary":"Calls in progress by country pair","description":"The live calls reduced to ISO alpha-2 origin and destination countries for a traffic map: `routes` [{ from (null when the caller ID is not international), to, channels, calls, answered }], busiest first, `unplaced` (destination not placeable), `total`, `fresh`. No numbers are returned. Optional `subAccountId`.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{},"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"subAccountId","in":"query","required":false,"schema":{"type":"string","maxLength":64}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/switch/noc/ask":{"post":{"operationId":"postSwitchNocAsk","tags":["Switch: operations"],"summary":"Ask AI Control a question about your switch","description":"Natural-language questions and requests about your traffic, answered from your own switch data within your team permissions. Returns a reply and any actions it proposes or took. Nothing changes unless your role allows it.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"reply":{"type":"string","nullable":true},"actions":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}}},"required":["reply"],"additionalProperties":true}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-error-codes":["AI_UNAVAILABLE"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","minLength":1,"maxLength":4000},"history":{"type":"array","items":{},"maxItems":60,"description":"Earlier turns of the conversation"}},"required":["message"]}}}},"x-px-example":{"path":{},"query":{},"body":{"message":"Hello from Acme"}}}},"/api/v1/switch/me":{"get":{"operationId":"getSwitchMe","tags":["Switch: team and audit"],"summary":"Get your role and permissions on the switch","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"operatorId":{"type":"string","format":"uuid"},"isAccountHolder":{"type":"boolean"},"role":{"type":"string","nullable":true},"roleLabel":{"type":"string","nullable":true},"permissions":{"type":"array","items":{"type":"string"}},"sensitivePermissions":{"type":"array","items":{"type":"string"}},"scope":{"type":"object","properties":{"customerIds":{"type":"array","items":{"type":"string","format":"uuid"},"nullable":true,"description":"null = all customers"},"trunkIds":{"type":"array","items":{"type":"string","format":"uuid"},"nullable":true,"description":"null = all trunks"}},"required":["customerIds","trunkIds"]}},"required":["operatorId","isAccountHolder","role","roleLabel","permissions","sensitivePermissions","scope"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/switch/team":{"get":{"operationId":"getSwitchTeam","tags":["Switch: team and audit"],"summary":"List team members and the available roles","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"members":{"type":"array","items":{"$ref":"#/components/schemas/SwitchTeamMember"}},"roles":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}}},"required":["members","roles"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}},"post":{"operationId":"postSwitchTeam","tags":["Switch: team and audit"],"summary":"Add a team member","description":"Gives an email address a role on your switch, optionally limited to some customers and trunks (null = all).\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchTeamMember"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","format":"email","maxLength":255},"role":{"type":"string","enum":["viewer","noc","routing","billing","account_manager","administrator"]},"customerIds":{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":500,"nullable":true},"trunkIds":{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":500,"nullable":true},"note":{"type":"string","maxLength":500,"nullable":true}},"required":["email","role"]}}}},"x-px-example":{"path":{},"query":{},"body":{"email":"you@example.com","role":"viewer"}}}},"/api/v1/switch/team/{memberId}":{"patch":{"operationId":"patchSwitchTeamByMemberId","tags":["Switch: team and audit"],"summary":"Change a team member's role, scope or status","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchTeamMember"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"memberId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"role":{"type":"string","enum":["viewer","noc","routing","billing","account_manager","administrator"]},"status":{"type":"string","enum":["active","suspended"]},"customerIds":{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":500,"nullable":true},"trunkIds":{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":500,"nullable":true},"note":{"type":"string","maxLength":500,"nullable":true}}}}}},"x-px-example":{"path":{"memberId":"<memberId>"},"query":{},"body":{"role":"viewer","status":"active"}}},"delete":{"operationId":"deleteSwitchTeamByMemberId","tags":["Switch: team and audit"],"summary":"Suspend a team member","description":"Suspends rather than deletes, so their history stays attributed.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchTeamMember"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"memberId","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"memberId":"<memberId>"},"query":{}}}},"/api/v1/switch/audit":{"get":{"operationId":"getSwitchAudit","tags":["Switch: team and audit"],"summary":"Search the switch audit history","description":"Who changed what, when, and under which permission. Cursor-paginated with `nextCursor`.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"entries":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}},"nextCursor":{"type":"string","nullable":true}},"required":["entries","nextCursor"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"customerId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"trunkId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"actorUserId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"action","in":"query","required":false,"schema":{"type":"string","maxLength":80}},{"name":"permission","in":"query","required":false,"schema":{"type":"string","maxLength":64}},{"name":"sensitiveOnly","in":"query","required":false,"schema":{"type":"boolean"}},{"name":"outcome","in":"query","required":false,"schema":{"type":"string","enum":["success","failure","denied"]}},{"name":"from","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"search","in":"query","required":false,"schema":{"type":"string","maxLength":120}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/switch/audit/filter-options":{"get":{"operationId":"getSwitchAuditFilterOptions","tags":["Switch: team and audit"],"summary":"Get the values available to filter the audit history by","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"actors":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}},"permissions":{"type":"array","items":{"type":"string"}},"sensitivePermissions":{"type":"array","items":{"type":"string"}}},"required":["actors","permissions","sensitivePermissions"],"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/switch/approvals":{"get":{"operationId":"getSwitchApprovals","tags":["Switch: team and audit"],"summary":"List approval requests","description":"Actions waiting for (or decided by) a second person. Defaults to pending and approved.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/SwitchApproval"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"status","in":"query","required":false,"description":"Comma-separated statuses","schema":{"type":"string","maxLength":120}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/switch/approvals/{id}/decide":{"post":{"operationId":"postSwitchApprovalsByIdDecide","tags":["Switch: team and audit"],"summary":"Approve or reject an approval request","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchApproval"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"decision":{"type":"string","enum":["approve","reject"]},"note":{"type":"string","maxLength":2000,"nullable":true}},"required":["decision"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"decision":"approve"}}}},"/api/v1/switch/approval-policies":{"get":{"operationId":"getSwitchApprovalPolicies","tags":["Switch: team and audit"],"summary":"List approval policies","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"policies":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}},"eligible":{"type":"array","items":{"type":"string"},"description":"Permissions that can be put behind an approval"},"pending":{"type":"integer"}},"required":["policies","eligible","pending"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}},"put":{"operationId":"putSwitchApprovalPolicies","tags":["Switch: team and audit"],"summary":"Set the approval policy for a permission","description":"Require a second person to approve actions under this permission, optionally only above an amount.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{},"additionalProperties":true}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"permission":{"type":"string","enum":["customers.view","trunks.view","routing.view","rates.view","billing.view","noc.view","audit.view","team.view","customers.edit","trunks.edit","rates.edit","billing.edit","noc.act","credentials.reveal","credentials.rotate","routing.edit","rates.publish","billing.payment","billing.adjustment","billing.credit_limit","customers.close","trunks.delete","team.manage","approvals.decide"]},"enabled":{"type":"boolean"},"minAmountUsd":{"type":"number","minimum":0,"nullable":true},"requireDifferentPerson":{"type":"boolean"},"expiresAfterHours":{"type":"integer","minimum":1,"maximum":2160},"requireReason":{"type":"boolean"}},"required":["permission","enabled"]}}}},"x-px-example":{"path":{},"query":{},"body":{"permission":"customers.view","enabled":true}}}},"/api/v1/switch/dnc/summary":{"get":{"operationId":"getSwitchDncSummary","tags":["Switch: operations"],"summary":"Get Do Not Call list sizes and recent hits","description":"Do Not Call on the Switch uses ONE list: the same entries as the Dialer's suppression list (/dnc), plus the platform-wide list. A call from a customer or trunk with \"Honor Do Not Call\" on is checked against both. This returns the list sizes, your entries by source, the Switch calls that matched in the last 7 and 30 days, how many customers and trunks honour the list, and the platform mode.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"ownCount":{"type":"integer","description":"Entries on your own list"},"globalCount":{"type":"integer","description":"Entries on the platform-wide list"},"bySource":{"type":"object","additionalProperties":{"type":"integer"},"description":"Your entries per source (manual, upload, sms_stop, callguard_optout)"},"hits":{"type":"object","properties":{"refused7":{"type":"integer"},"warned7":{"type":"integer"},"refused30":{"type":"integer"},"warned30":{"type":"integer"}},"required":["refused7","warned7","refused30","warned30"],"description":"Switch calls that matched, refused or only warned, over 7 and 30 days"},"customersHonoring":{"type":"integer"},"trunksHonoring":{"type":"integer","description":"Trunks with the setting explicitly on"},"mode":{"type":"string","enum":["off","warn","enforce"],"description":"The platform setting for Switch calls: off = not checked; warn = matches are recorded but the call proceeds; enforce = matches are refused"},"timeoutMs":{"type":"integer","description":"The lookup time budget per call; a slower lookup lets the call through"}},"required":["ownCount","globalCount","bySource","hits","customersHonoring","trunksHonoring","mode","timeoutMs"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/switch/dnc/entries":{"get":{"operationId":"getSwitchDncEntries","tags":["Switch: operations"],"summary":"List Do Not Call entries","description":"Your own list and the platform-wide list. Reasons are shown only for your own entries.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"rows":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"phoneNumber":{"type":"string"},"source":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"scope":{"type":"string","enum":["own","global"],"description":"own = your list; global = the platform-wide list"},"reason":{"type":"string","nullable":true}},"required":["id","phoneNumber","source","createdAt","scope","reason"]}},"hasMore":{"type":"boolean"}},"required":["rows","hasMore"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"q","in":"query","required":false,"description":"Number prefix to search for","schema":{"type":"string"}},{"name":"scope","in":"query","required":false,"schema":{"type":"string","enum":["all","own","global"]}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/switch/dnc/hits":{"get":{"operationId":"getSwitchDncHits","tags":["Switch: operations"],"summary":"List calls refused or warned by Do Not Call","description":"Your customers' Switch calls whose number matched a Do Not Call list, newest first (default 50, max 200).\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"phoneNumber":{"type":"string"},"listScope":{"type":"string","enum":["own","global"],"description":"Which list matched"},"outcome":{"type":"string","enum":["refused","warned"],"description":"refused = the call was blocked (enforce mode); warned = recorded only"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"subAccountId":{"type":"string","format":"uuid","nullable":true},"customerTrunkId":{"type":"string","format":"uuid","nullable":true},"customer":{"type":"string","nullable":true},"trunk":{"type":"string","nullable":true}},"required":["id","phoneNumber","listScope","outcome","createdAt","subAccountId","customerTrunkId","customer","trunk"]}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/switch/dnc/check":{"get":{"operationId":"getSwitchDncCheck","tags":["Switch: operations"],"summary":"Check whether a number is on a Do Not Call list","description":"Checks one number against your list and the platform list. When it is on both, your own entry is returned. The platform list never shows its reason.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"input":{"type":"string","description":"What you sent"},"number":{"type":"string","nullable":true,"description":"The number as stored on the list (digits); null when nothing could be read"},"valid":{"type":"boolean","description":"Whether it reads as a dialable number"},"listed":{"type":"boolean"},"scope":{"type":"string","enum":["own","global"],"description":"own = your list; global = the platform-wide list","nullable":true},"entry":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"source":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"reason":{"type":"string","nullable":true}},"required":["id","source","createdAt","reason"],"nullable":true}},"required":["input","number","valid","listed","scope","entry"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"number","in":"query","required":true,"schema":{"type":"string","minLength":1,"maxLength":40}}],"x-px-example":{"path":{},"query":{"number":"+447700900123"}}}},"/api/v1/switch/dnc/customers":{"get":{"operationId":"getSwitchDncCustomers","tags":["Switch: operations"],"summary":"List which customers and trunks honour Do Not Call","description":"Every customer's setting with each trunk's own value (null = inherits from the customer) and the effective result.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"label":{"type":"string"},"status":{"type":"string"},"honorDnc":{"type":"boolean"},"trunks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"label":{"type":"string"},"status":{"type":"string"},"honorDnc":{"type":"boolean","nullable":true},"effective":{"type":"boolean"}},"required":["id","label","status","honorDnc","effective"]}}},"required":["id","label","status","honorDnc","trunks"]}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/switch/dnc/honor":{"get":{"operationId":"getSwitchDncHonor","tags":["Switch: operations"],"summary":"Get the Do Not Call setting of a customer or trunk","description":"Name `subAccountId` or `customerTrunkId`. A customer or trunk that is not yours answers 404.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchDncHonorSetting"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"subAccountId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"customerTrunkId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{},"query":{}}},"patch":{"operationId":"patchSwitchDncHonor","tags":["Switch: operations"],"summary":"Turn Do Not Call on or off for a customer or trunk","description":"Name exactly one of `subAccountId` or `customerTrunkId`. A trunk can pass `honor: null` to inherit from its customer; a customer is either on or off. Takes effect on the next call and is audited with the before and after values.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SwitchDncHonorSetting"}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"subAccountId":{"type":"string","format":"uuid"},"customerTrunkId":{"type":"string","format":"uuid"},"honor":{"type":"boolean","nullable":true}},"required":["honor"]}}}},"x-px-example":{"path":{},"query":{},"body":{"honor":true}}}},"/api/v1/switch/dnc/scrub":{"post":{"operationId":"postSwitchDncScrub","tags":["Switch: operations"],"summary":"Remove Do Not Call numbers from an uploaded list","description":"Upload a CSV or text file (multipart, field `file`, up to 500,000 rows and 16 MB). Rows whose number is on your list or the platform list are removed; every other row, including a header, comes back unchanged. With `?format=csv` the cleaned file is returned directly (counts in the `X-Dnc-Rows`, `X-Dnc-Clean`, `X-Dnc-Removed-Own`, `X-Dnc-Removed-Global` and `X-Dnc-Invalid` headers); otherwise the counts are returned and the file can be fetched from GET /switch/dnc/scrub/{id} for one hour. Rows that cannot be read as a number are kept and counted as invalid.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Rate limit:** 10 requests per minute per caller.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid","nullable":true,"description":"Download id, valid for one hour; null when the copy could not be stored (the counts are still correct: run again with ?format=csv)"},"filename":{"type":"string"},"counts":{"type":"object","properties":{"rows":{"type":"integer"},"clean":{"type":"integer"},"removedOwn":{"type":"integer"},"removedGlobal":{"type":"integer"},"invalid":{"type":"integer"},"hadHeader":{"type":"boolean"}},"required":["rows","clean","removedOwn","removedGlobal","invalid","hadHeader"]},"invalidSamples":{"type":"array","items":{"type":"string"},"description":"Up to 10 unreadable rows (first 80 characters each)"},"ms":{"type":"integer","description":"Processing time in milliseconds"}},"required":["id","filename","counts","invalidSamples","ms"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-rate-limit":{"max":10,"window":"minute"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"format","in":"query","required":false,"schema":{"type":"string","enum":["csv","json"]}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","description":"CSV or text file of numbers (max 16 MB)"}},"required":["file"]}}}},"x-px-example":{"path":{},"query":{}}}},"/api/v1/switch/dnc/scrub/{id}":{"get":{"operationId":"getSwitchDncScrubById","tags":["Switch: operations"],"summary":"Download a scrubbed file","description":"Scrub results are kept for one hour; after that (or for an id that is not yours) the answer is 404 and the scrub must be run again.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"The cleaned CSV, as an attachment.","content":{"text/csv":{"schema":{"type":"string","format":"binary"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/switch/dnc/import":{"post":{"operationId":"postSwitchDncImport","tags":["Switch: operations"],"summary":"Add numbers to your Do Not Call list from a file","description":"Multipart upload: field `file` (CSV or text of numbers, up to 500,000 rows and 16 MB) and an optional `reason`, which must come BEFORE the file part. The number column is found from the first line (a phone-like header, else the first column). Numbers already listed are skipped. Audited.\n\n**Auth:** API key or JWT. Scoped keys need `switch:manage`.\n\n**Rate limit:** 10 requests per minute per caller.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. The Switch has no test mode, so a change always applies to your live configuration. Test keys can still read Switch data.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"rows":{"type":"integer","description":"Number rows read (a header row is not counted)"},"added":{"type":"integer"},"skipped":{"type":"integer","description":"Valid numbers already listed, or repeated within the file"},"invalid":{"type":"integer","description":"Rows that could not be read as a number"}},"required":["rows","added","skipped","invalid"]}}}}}},"202":{"$ref":"#/components/responses/ApprovalRequired"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","x-rate-limit":{"max":10,"window":"minute"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","description":"CSV or text file of numbers (max 16 MB)"},"reason":{"type":"string","maxLength":500}},"required":["file"]}}}},"x-px-example":{"path":{},"query":{}}}},"/api/v1/switch/dnc/export":{"get":{"operationId":"getSwitchDncExport","tags":["Switch: operations"],"summary":"Download your Do Not Call list as CSV","description":"**Auth:** API key or JWT. Scoped keys need `switch:manage`.","responses":{"200":{"description":"Your own Do Not Call list, as an attachment named do-not-call-<date>.csv. Columns: phone_number, source, reason, added_at.","content":{"text/csv":{"schema":{"type":"string","format":"binary"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"`SWITCH_SUBSCRIPTION_REQUIRED`: the account has no active Switch plan or trial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"switch:manage","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/us-compliance/profile":{"get":{"operationId":"getUsComplianceProfile","tags":["Compliance"],"summary":"Get your US calling compliance profile","description":"Your STIR/SHAKEN and FCC registrations, reused for every US voice purchase. `data` is null until you submit one.\n\n**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"allOf":[{"$ref":"#/components/schemas/UsComplianceProfile"}],"nullable":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}},"put":{"operationId":"putUsComplianceProfile","tags":["Compliance"],"summary":"Submit or update your US calling compliance profile","description":"Required before a US voice route purchase can be reviewed. Accepting the terms stamps `termsAcceptedAt`.\n\n**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/UsComplianceProfile"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"legalBusinessName":{"type":"string","minLength":1,"maxLength":255},"contactName":{"type":"string","minLength":1,"maxLength":255},"contactEmail":{"type":"string","format":"email","maxLength":255},"contactPhone":{"type":"string","maxLength":40,"nullable":true},"frn":{"type":"string","minLength":1,"maxLength":40},"filer499Id":{"type":"string","minLength":1,"maxLength":40},"ocn":{"type":"string","minLength":1,"maxLength":20},"rmdRegistered":{"type":"boolean"},"rmdReference":{"type":"string","maxLength":2000,"nullable":true},"signsOwnTraffic":{"type":"boolean"},"stirShakenCert":{"type":"string","maxLength":4000,"nullable":true},"attestationLevel":{"type":"string","enum":["A","B","C"],"nullable":true},"termsAccepted":{"type":"boolean"}},"required":["legalBusinessName","contactName","contactEmail","frn","filer499Id","ocn","rmdRegistered","signsOwnTraffic","termsAccepted"]}}}},"x-px-example":{"path":{},"query":{},"body":{"legalBusinessName":"<legalBusinessName>","contactName":"<contactName>","contactEmail":"you@example.com","frn":"<frn>","filer499Id":"<filer499Id>","ocn":"<ocn>","rmdRegistered":true,"signsOwnTraffic":true,"termsAccepted":true}}}},"/api/v1/us-compliance/route/{routeId}/requirement":{"get":{"operationId":"getUsComplianceRouteByRouteIdRequirement","tags":["Compliance"],"summary":"Check whether a route needs a US compliance profile","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"required":{"type":"boolean"},"hasProfile":{"type":"boolean"},"profileComplete":{"type":"boolean"}},"required":["required","hasProfile","profileComplete"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"routeId","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"routeId":"<routeId>"},"query":{}}}},"/api/v1/us-compliance/status":{"get":{"operationId":"getUsComplianceStatus","tags":["Compliance"],"summary":"Get your US compliance review status","description":"`actionNeeded` is true when a US purchase is waiting on review and your profile is not complete enough for it to proceed.\n\n**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"hasProfile":{"type":"boolean"},"profileComplete":{"type":"boolean"},"pendingReviewCount":{"type":"integer"},"actionNeeded":{"type":"boolean"}},"required":["hasProfile","profileComplete","pendingReviewCount","actionNeeded"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/offers":{"post":{"operationId":"postOffers","tags":["Offers"],"summary":"Make an offer on a route","description":"Opens a negotiation at `proposedPrice` (6-decimal USD string). The seller can accept, reject or counter.\n\n**Auth:** API key or JWT. Scoped keys need `offers:write`.\n\n**Idempotency:** send an `X-Idempotency-Key` header to make retries safe; a replay within 24 hours returns the original response.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/Offer"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"offers:write","x-idempotent":true,"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"X-Idempotency-Key","in":"header","required":false,"description":"Any unique string (a UUID is ideal). Replays within 24 hours return the first response instead of acting twice.","schema":{"type":"string","maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"routeId":{"type":"string","format":"uuid"},"proposedPrice":{"type":"string","pattern":"^\\d+(\\.\\d{1,6})?$"},"message":{"type":"string","maxLength":500}},"required":["routeId","proposedPrice"]}}}},"x-px-example":{"path":{},"query":{},"body":{"routeId":"<routeId>","proposedPrice":"<proposedPrice>"}},"x-px-billable":{"kind":"money","note":"Makes or answers a binding offer on a route."}},"get":{"operationId":"getOffers","tags":["Offers"],"summary":"List offers you made and received","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/Offer"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"role","in":"query","required":false,"description":"Default all","schema":{"type":"string","enum":["buyer","seller","all"]}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["pending","countered","accepted","rejected","withdrawn","expired"]}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/offers/bulk":{"post":{"operationId":"postOffersBulk","tags":["Offers"],"summary":"Make offers on several routes at once","description":"One offer per item, grouped. Routes that cannot take an offer (your own, inactive, already negotiating) are skipped and reported back.\n\n**Auth:** API key or JWT. Scoped keys need `offers:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"group":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"message":{"type":"string","nullable":true},"status":{"type":"string"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","message","status","createdAt"]},"offers":{"type":"array","items":{"$ref":"#/components/schemas/Offer"}},"skipped":{"type":"array","items":{"type":"object","properties":{"routeId":{"type":"string","format":"uuid"},"reason":{"type":"string"}},"required":["routeId","reason"]}}},"required":["group","offers","skipped"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"offers:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"routeId":{"type":"string","format":"uuid"},"proposedPrice":{"type":"string","pattern":"^\\d+(\\.\\d{1,6})?$"}},"required":["routeId","proposedPrice"]},"minItems":1,"maxItems":100},"message":{"type":"string","maxLength":500}},"required":["items"]}}}},"x-px-example":{"path":{},"query":{},"body":{"items":[{"routeId":"<routeId>","proposedPrice":"<proposedPrice>"}]}}}},"/api/v1/offers/groups":{"get":{"operationId":"getOffersGroups","tags":["Offers"],"summary":"List your bulk offers","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"message":{"type":"string","nullable":true},"status":{"type":"string"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"offers":{"type":"array","items":{"$ref":"#/components/schemas/Offer"}},"total":{"type":"integer"},"counts":{"type":"object","additionalProperties":{"type":"integer"},"description":"Child offers per status"}},"required":["id","message","status","createdAt","offers","total","counts"],"additionalProperties":true}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/offers/groups/{id}/respond":{"post":{"operationId":"postOffersGroupsByIdRespond","tags":["Offers"],"summary":"Accept or reject every open offer in a bulk offer","description":"**Auth:** API key or JWT. Scoped keys need `offers:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"groupId":{"type":"string","format":"uuid"},"applied":{"type":"integer"},"results":{"type":"array","items":{"type":"object","properties":{"ok":{"type":"boolean"}},"required":["ok"],"additionalProperties":true}}},"required":["groupId","applied","results"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"offers:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","enum":["accept","reject"]},"message":{"type":"string","maxLength":500}},"required":["action"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"action":"accept"}}}},"/api/v1/offers/{id}":{"get":{"operationId":"getOffersById","tags":["Offers"],"summary":"Get an offer with its negotiation history","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"routeId":{"type":"string","format":"uuid"},"groupId":{"type":"string","format":"uuid","nullable":true,"description":"Set when the offer is part of a bulk (multi-route) offer"},"listPrice":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"The route list price when the offer was made"},"proposedPrice":{"allOf":[{"$ref":"#/components/schemas/Money"}],"description":"The latest price on the table"},"agreedPrice":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"Set once accepted"},"status":{"type":"string","enum":["pending","countered","accepted","rejected","withdrawn","expired"]},"lastActor":{"type":"string","enum":["buyer","seller"]},"message":{"type":"string","nullable":true,"description":"Cleaned of contact details"},"expiresAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"role":{"type":"string","enum":["buyer","seller"],"description":"Your side of this offer"},"yourTurn":{"type":"boolean"},"counterparty":{"type":"string","description":"Pseudonym for the other side, stable per route"},"route":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"destinationName":{"type":"string","description":"The seller reads the name they gave the route; the buyer reads the platform-generated name (see MarketplaceRoute.destinationName)"},"listingRef":{"type":"string","description":"Anonymous short reference of the listing (4 characters, e.g. \"7K2Q\"): stable for the life of the listing, unique enough to tell two same-named listings apart, and derived from the listing alone (it says nothing about the seller). Absent on your own listings."},"country":{"type":"string"},"countryCode":{"type":"string"},"type":{"type":"string","enum":["voice","sms"]},"routeType":{"type":"string"},"pricePerUnit":{"$ref":"#/components/schemas/Money"}},"required":["id","destinationName","country","countryCode","type","routeType","pricePerUnit"],"nullable":true},"events":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"offerId":{"type":"string","format":"uuid"},"actor":{"type":"string"},"action":{"type":"string"},"price":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"US dollars as a decimal string with exactly 6 decimal places, e.g. \"0.012500\". Do money arithmetic with a decimal type, not floating point."},"message":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","offerId","actor","action","price","message","createdAt"],"additionalProperties":true},"description":"The negotiation timeline, oldest first"}},"required":["id","routeId","groupId","listPrice","proposedPrice","agreedPrice","status","lastActor","message","expiresAt","createdAt","updatedAt","role","yourTurn","counterparty","route","events"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}},"patch":{"operationId":"patchOffersById","tags":["Offers"],"summary":"Accept, reject, counter or withdraw an offer","description":"`price` is required for `counter`. Accepting creates or reprices the purchase at the agreed price.\n\n**Auth:** API key or JWT. Scoped keys need `offers:write`.\n\n**Idempotency:** send an `X-Idempotency-Key` header to make retries safe; a replay within 24 hours returns the original response.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/Offer"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"offers:write","x-idempotent":true,"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"X-Idempotency-Key","in":"header","required":false,"description":"Any unique string (a UUID is ideal). Replays within 24 hours return the first response instead of acting twice.","schema":{"type":"string","maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","enum":["counter","accept","reject","withdraw"]},"price":{"type":"string","pattern":"^\\d+(\\.\\d{1,6})?$"},"message":{"type":"string","maxLength":500}},"required":["action"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"action":"counter"}},"x-px-billable":{"kind":"money","note":"Makes or answers a binding offer on a route."}}},"/api/v1/notifications":{"get":{"operationId":"getNotifications","tags":["Notifications"],"summary":"List your notifications","description":"Unread critical notifications first, then newest activity first, with the unread and unread-critical counts. Feed mode (`feed=1`, `cursor` or `kind`): the whole history newest first, keyset-paged with `nextCursor`, optionally one `kind`, each row carrying its `kind`.\n\n**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"notifications":{"type":"array","items":{"$ref":"#/components/schemas/Notification"}},"unreadCount":{"type":"integer"},"criticalUnreadCount":{"type":"integer","description":"Unread notifications that need action"},"nextCursor":{"type":"string","nullable":true,"description":"Feed mode only; null on the last page"}},"required":["notifications","unreadCount","criticalUnreadCount"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"unread","in":"query","required":false,"description":"Only unread notifications","schema":{"type":"string","enum":["1","true"]}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100}},{"name":"feed","in":"query","required":false,"description":"Feed mode without a kind filter","schema":{"type":"string","enum":["1","true"]}},{"name":"cursor","in":"query","required":false,"description":"Feed mode: `nextCursor` from the previous page","schema":{"type":"string","maxLength":200}},{"name":"kind","in":"query","required":false,"description":"Feed mode: one kind only","schema":{"type":"string","enum":["money","routes","offers","security","other"]}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/notifications/{id}/read":{"post":{"operationId":"postNotificationsByIdRead","tags":["Notifications"],"summary":"Mark a notification as read","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success. The body is `{ \"success\": true }` with no `data`.","content":{"application/json":{"schema":{"type":"object","required":["success"],"properties":{"success":{"type":"boolean","enum":[true]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/notifications/preferences":{"get":{"operationId":"getNotificationsPreferences","tags":["Notifications"],"summary":"Get your notification email preference","description":"Whether unread critical notifications are emailed to you as a digest (on by default).\n\n**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/NotificationEmailPrefs"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}},"put":{"operationId":"putNotificationsPreferences","tags":["Notifications"],"summary":"Set your notification email preference","description":"Turn the \"needs attention\" digest email on or off. The digest lists unread critical notifications, at most once every 4 hours. Security and account emails are not affected.\n\n**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/NotificationEmailPrefs"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"actionEmail":{"type":"boolean"}},"required":["actionEmail"]}}}},"x-px-example":{"path":{},"query":{},"body":{"actionEmail":true}}}},"/api/v1/notifications/read-all":{"post":{"operationId":"postNotificationsReadAll","tags":["Notifications"],"summary":"Mark all notifications as read","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success. The body is `{ \"success\": true }` with no `data`.","content":{"application/json":{"schema":{"type":"object","required":["success"],"properties":{"success":{"type":"boolean","enum":[true]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/comms/calls":{"post":{"operationId":"postCommsCalls","tags":["Voice and SMS"],"summary":"Place a single outbound call","description":"Dials `to` over a route you purchased (or one Smart Routing selects). By default the request BLOCKS until the call ends (answer and hangup, no answer, or `maxDuration`), then returns the outcome and what it cost (200); set a client timeout above `maxDuration`. With `async: true` it returns at once with **202** and `status: ringing`; follow the call on GET /comms/calls/{id} or with the call.ringing, call.answered, call.gathered and call.completed webhooks. Validation, routing and balance errors are still returned straight away in both modes. `actions` make the answered call speak (`say`, in en, es, fr, de, pt or hi), play an MP3 (`play`), collect keypad digits (`gather`), wait (`pause`) or end (`hangup`), in order; audio is prepared before dialling, so a bad URL costs nothing. Billed per the route increment at the route price plus the platform fee, after the call completes; there is no charge for spoken text. A test key simulates the call against test credit and runs no actions.\n\n**Auth:** API key or JWT. Scoped keys need `voice:send`.\n\n**Rate limit:** 10 requests per second per caller.\n\n**Idempotency:** send an `X-Idempotency-Key` header to make retries safe; a replay within 24 hours returns the original response.","responses":{"200":{"description":"The call outcome (200), or with async:true the accepted call (202)","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"anyOf":[{"$ref":"#/components/schemas/CommsCall"},{"$ref":"#/components/schemas/CommsCallAccepted"}]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"voice:send","x-rate-limit":{"max":10,"window":"second"},"x-idempotent":true,"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"X-Idempotency-Key","in":"header","required":false,"description":"Any unique string (a UUID is ideal). Replays within 24 hours return the first response instead of acting twice.","schema":{"type":"string","maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"to":{"type":"string","pattern":"^\\+?[1-9][0-9]{6,14}$","description":"Destination number (E.164)"},"from":{"type":"string","pattern":"^\\+?[1-9][0-9]{6,14}$","description":"Caller ID to present (E.164)"},"routeId":{"type":"string","format":"uuid","description":"A route you purchased. Omit to let Smart Routing pick one"},"strategy":{"type":"string","enum":["cheapest","best_quality","balanced"],"description":"Smart Routing strategy used when routeId is omitted"},"maxDuration":{"type":"integer","minimum":10,"maximum":3600,"default":300,"description":"Hang up after this many seconds"},"async":{"type":"boolean","description":"Return at once (202, status ringing) instead of waiting for the call to end. Follow the call on GET /comms/calls/{id} or with the call.* webhooks"},"actions":{"type":"array","items":{"$ref":"#/components/schemas/CallAction"},"minItems":1,"maxItems":10,"description":"What the call does once answered, in order: say, play, gather, pause, hangup. At most 10 actions, 1,500 characters of spoken text, 3 play URLs and 5 gathers. The call ends when the actions finish"},"language":{"type":"string","enum":["en","es","fr","de","pt","hi"],"description":"Default language for say actions (default en)"}},"required":["to","from"]}}}},"x-px-example":{"path":{},"query":{},"body":{"to":"+447700900123","from":"+447700900123"}},"x-px-billable":{"kind":"traffic","note":"Places a real call or sends a real message, billed to your balance. A test key simulates it against test credit."}},"get":{"operationId":"getCommsCalls","tags":["Voice and SMS"],"summary":"List your API call history","description":"Ledger entries for calls placed through POST /comms/calls, newest first.\n\n**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":"One page of results, newest first.","content":{"application/json":{"schema":{"type":"object","required":["success","data","nextCursor","hasMore"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/CommsHistoryEntry"}},"nextCursor":{"type":"string","nullable":true,"description":"Pass as `cursor` to fetch the next page; null on the last page."},"hasMore":{"type":"boolean","description":"True when another page exists."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"type","in":"query","required":false,"description":"Accepted but not applied: each endpoint already fixes its own type","schema":{"type":"string","enum":["api_call","api_sms","smpp_sms","dialer_campaign"]}},{"name":"from","in":"query","required":false,"description":"Only rows created at or after this instant","schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","required":false,"description":"Only rows created before this instant","schema":{"type":"string","format":"date-time"}},{"name":"cursor","in":"query","required":false,"description":"The `nextCursor` from the previous page","schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/comms/calls/{id}":{"get":{"operationId":"getCommsCallsById","tags":["Voice and SMS"],"summary":"Get one call: live status, cost and gathered digits","description":"Works for any call placed through POST /comms/calls, while it runs and after it ends: status, timestamps, duration, cost, the hangup cause in plain words, and the digits collected by gather actions. A reseller sub-account key sees only its own calls. Unknown ids answer 404.\n\n**Auth:** API key or JWT. Scoped keys need `voice:send`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/CommsCallStatus"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"voice:send","x-error-codes":["NOT_FOUND"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The callId returned by POST /comms/calls"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/comms/sms":{"post":{"operationId":"postCommsSms","tags":["Voice and SMS"],"summary":"Send a single SMS","description":"Forwards the message to the route seller and returns straight away with a message id. `status` is the send-time outcome (accepted, sent or failed). The final outcome comes later from the carrier's delivery receipt, when the route returns one: read it with `GET /comms/sms/{messageId}` or subscribe to the `sms.delivered` and `sms.failed` webhooks. A message that fails on its receipt is refunded. Billed per segment at the route price plus the platform fee. A test key simulates the send against test credit.\n\n**Auth:** API key or JWT. Scoped keys need `sms:send`.\n\n**Rate limit:** 10 requests per second per caller.\n\n**Idempotency:** send an `X-Idempotency-Key` header to make retries safe; a replay within 24 hours returns the original response.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/CommsSms"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"sms:send","x-rate-limit":{"max":10,"window":"second"},"x-idempotent":true,"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"X-Idempotency-Key","in":"header","required":false,"description":"Any unique string (a UUID is ideal). Replays within 24 hours return the first response instead of acting twice.","schema":{"type":"string","maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"to":{"type":"string","pattern":"^\\+?[1-9][0-9]{6,14}$","description":"Destination number (E.164)"},"from":{"type":"string","minLength":1,"maxLength":30,"pattern":"^[A-Za-z0-9 .+_-]+$","description":"Sender ID: a number or an alphanumeric sender (letters, digits, spaces and . + _ -)"},"routeId":{"type":"string","format":"uuid","description":"A route you purchased. Omit to let Smart Routing pick one"},"strategy":{"type":"string","enum":["cheapest","best_quality","balanced"],"description":"Smart Routing strategy used when routeId is omitted"},"message":{"type":"string","minLength":1,"maxLength":1600,"description":"Message body. Long messages are sent as concatenated segments"}},"required":["to","from","message"]}}}},"x-px-example":{"path":{},"query":{},"body":{"to":"+447700900123","from":"+447700900123","message":"Hello from Acme"}},"x-px-billable":{"kind":"traffic","note":"Places a real call or sends a real message, billed to your balance. A test key simulates it against test credit."}},"get":{"operationId":"getCommsSms","tags":["Voice and SMS"],"summary":"List your SMS history","description":"Ledger entries for messages sent over the API and SMPP, newest first.\n\n**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":"One page of results, newest first.","content":{"application/json":{"schema":{"type":"object","required":["success","data","nextCursor","hasMore"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/CommsHistoryEntry"}},"nextCursor":{"type":"string","nullable":true,"description":"Pass as `cursor` to fetch the next page; null on the last page."},"hasMore":{"type":"boolean","description":"True when another page exists."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"type","in":"query","required":false,"description":"Accepted but not applied: each endpoint already fixes its own type","schema":{"type":"string","enum":["api_call","api_sms","smpp_sms","dialer_campaign"]}},{"name":"from","in":"query","required":false,"description":"Only rows created at or after this instant","schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","required":false,"description":"Only rows created before this instant","schema":{"type":"string","format":"date-time"}},{"name":"cursor","in":"query","required":false,"description":"The `nextCursor` from the previous page","schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/comms/sms/{messageId}":{"get":{"operationId":"getCommsSmsByMessageId","tags":["Voice and SMS"],"summary":"Get the delivery status and timeline of a sent SMS","description":"Returns the message's current status and its timeline: `queued` (charged), `sent` (the route accepted the hand-off), then `delivered` or `failed`, each with a timestamp, and an `errorCode` on failure.\n\n**Where delivered comes from.** Only from a carrier delivery receipt. Receipts come back on SMPP routes whose supplier returns them, and on HTTP routes whose seller posts them back to us. A route that returns none leaves its messages at `sent` with `awaitingReceipt: true`; `routeReturnsReceipts` tells you whether the route has returned any in the last 30 days, so you know whether to wait. A receipt that reports the message undelivered, expired or rejected marks it `failed` and refunds it.\n\nCovers messages sent with `POST /comms/sms` and `POST /comms/sms/bulk`. An unknown id answers 200 with status `not_found` rather than 404.\n\n**Auth:** API key or JWT. Scoped keys need `sms:send`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/CommsSmsStatus"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"sms:send","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"messageId","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"messageId":"<messageId>"},"query":{}}}},"/api/v1/comms/sms/bulk":{"post":{"operationId":"postCommsSmsBulk","tags":["Voice and SMS"],"summary":"Send up to 1,000 SMS in one request","description":"Sends each message in order over one route and returns a result per recipient. Each message is billed exactly as `POST /comms/sms` bills it: a reseller sub-account API key pays the sub-account's retail rate, a test key simulates. Stops at the first insufficient-balance refusal (account or sub-account) and marks the rest `skipped`. Not idempotent: retrying resends every message.\n\n**Auth:** API key or JWT. Scoped keys need `sms:send`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/CommsBulkSmsResult"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"sms:send","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"routeId":{"type":"string","format":"uuid","description":"The purchased SMS route every message is sent over"},"from":{"type":"string","minLength":1,"maxLength":30,"description":"Sender ID for every message"},"messages":{"type":"array","items":{"type":"object","properties":{"to":{"type":"string","minLength":5,"maxLength":30},"message":{"type":"string","minLength":1,"maxLength":1600}},"required":["to","message"]},"minItems":1,"maxItems":1000}},"required":["routeId","from","messages"]}}}},"x-px-example":{"path":{},"query":{},"body":{"routeId":"<routeId>","from":"+447700900123","messages":[{"to":"+447700900123","message":"Hello from Acme"}]}},"x-px-billable":{"kind":"traffic","note":"Places a real call or sends a real message, billed to your balance. A test key simulates it against test credit."}}},"/api/v1/comms/voice-otp":{"post":{"operationId":"postCommsVoiceOtp","tags":["Verify"],"summary":"Read a one-time passcode to a phone by voice call","description":"Calls `to` and, when answered, reads the code one digit at a time: \"Your {brand} verification code is 4, 8, 2, 9, 1, 3. Again, 4, 8, 2, 9, 1, 3.\" Repeated `repeat` times (default 2, max 3), then the call hangs up. Pass your own `code` (4-10 digits) or let us generate one of `length` digits (default 6); a generated code is returned only when you set `returnCode: true`. You check the code yourself; use POST /verify/start instead to have us check it. Languages: en, es, fr, de, pt, hi. `brand` defaults to your company name and is cleaned to letters, digits and spaces (max 30). Returns as soon as the call is ringing; the outcome and cost arrive with the call.completed webhook and on GET /comms/voice-otp/{id}. Billed exactly like POST /comms/calls: the route rate per billing increment plus the platform fee. No text-to-speech surcharge. A test key simulates the call against test credit. Omit `strategy` and the code goes out over Smart Routing's `best_quality` route for the destination (plain calls and SMS default to `balanced`). Limits, shared by voice passcodes and the Verify API: 5 codes per number per hour, 30 seconds between codes to the same number, a per-account daily cap, and a cap on codes into one number range per hour. A limit answers 429 with `details.retryAfterSeconds`. Embargoed destinations, premium-rate / satellite / high-risk ranges and numbers on your Do-Not-Contact list are refused with 400.\n\n**Auth:** API key or JWT. Scoped keys need `voice:send`.\n\n**Rate limit:** 10 requests per second per caller.\n\n**Idempotency:** send an `X-Idempotency-Key` header to make retries safe; a replay within 24 hours returns the original response.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/VoiceOtpResult"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"voice:send","x-rate-limit":{"max":10,"window":"second"},"x-idempotent":true,"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"X-Idempotency-Key","in":"header","required":false,"description":"Any unique string (a UUID is ideal). Replays within 24 hours return the first response instead of acting twice.","schema":{"type":"string","maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"to":{"type":"string","pattern":"^\\+?[1-9][0-9]{6,14}$"},"code":{"type":"string","pattern":"^[0-9]{4,10}$"},"length":{"type":"integer","minimum":4,"maximum":10},"language":{"type":"string","pattern":"^[a-z]{2}$"},"repeat":{"type":"integer","minimum":1,"maximum":3},"from":{"type":"string","pattern":"^\\+?[1-9][0-9]{6,14}$"},"strategy":{"type":"string","enum":["cheapest","best_quality","balanced"]},"route":{"type":"string","enum":["smart","direct"]},"brand":{"type":"string","maxLength":120,"description":"Brand read out / sent. Cleaned to letters, digits and spaces, max 30 characters"},"returnCode":{"type":"boolean"}},"required":["to"]}}}},"x-px-example":{"path":{},"query":{},"body":{"to":"+447700900123"}},"x-px-billable":{"kind":"traffic","note":"Places a real call or sends a real message, billed to your balance. A test key simulates it against test credit."}}},"/api/v1/comms/voice-otp/{id}":{"get":{"operationId":"getCommsVoiceOtpById","tags":["Verify"],"summary":"Get the outcome of a voice passcode call","description":"Whether the call was answered, how long it ran and what it cost. Never returns the code.\n\n**Auth:** API key or JWT. Scoped keys need `voice:send`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/VoiceOtpStatus"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"voice:send","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/billing/transactions":{"get":{"operationId":"getBillingTransactions","tags":["Billing"],"summary":"List ledger transactions","description":"Your account ledger, newest first, cursor-paginated. Filter by type and an ISO date range (inclusive `from`, exclusive `to`). With `format=csv` the response is a CSV file of every matching row (up to 10,000) instead of JSON.\n\n**Auth:** API key or JWT. Scoped keys need `account:read`.","responses":{"200":{"description":"One page of results, newest first.","content":{"application/json":{"schema":{"type":"object","required":["success","data","nextCursor","hasMore"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/LedgerTransaction"}},"nextCursor":{"type":"string","nullable":true,"description":"Pass as `cursor` to fetch the next page; null on the last page."},"hasMore":{"type":"boolean","description":"True when another page exists."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"type","in":"query","required":false,"schema":{"type":"string","enum":["topup","charge","credit","payout","platform_fee","test_credit"]}},{"name":"from","in":"query","required":false,"description":"Inclusive start (ISO-8601)","schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","required":false,"description":"Exclusive end (ISO-8601)","schema":{"type":"string","format":"date-time"}},{"name":"cursor","in":"query","required":false,"description":"The `nextCursor` from the previous page","schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":25}},{"name":"format","in":"query","required":false,"description":"csv streams every matching row (up to 10,000) as a spreadsheet file","schema":{"type":"string","enum":["json","csv"]}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/billing/summary":{"get":{"operationId":"getBillingSummary","tags":["Billing"],"summary":"Get your spending and earnings summary","description":"Dashboard totals: spending (all time and today, UTC), seller earnings (all time, 30 days, today), active purchases and campaigns, and the withdrawable versus held part of your balance.\n\n**Auth:** API key or JWT. Scoped keys need `account:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"totalSpending":{"$ref":"#/components/schemas/Money"},"totalTransactions":{"type":"integer"},"spendingToday":{"$ref":"#/components/schemas/Money"},"transactionsToday":{"type":"integer"},"activePurchases":{"type":"integer"},"runningCampaigns":{"type":"integer"},"totalCampaigns":{"type":"integer"},"totalEarnings":{"$ref":"#/components/schemas/Money"},"earnings30d":{"$ref":"#/components/schemas/Money"},"earningsToday":{"$ref":"#/components/schemas/Money"},"availableBalance":{"allOf":[{"$ref":"#/components/schemas/Money"}],"description":"Withdrawable now"},"heldBalance":{"allOf":[{"$ref":"#/components/schemas/Money"}],"description":"Card top-ups still inside the chargeback hold window"}},"required":["totalSpending","totalTransactions","spendingToday","transactionsToday","activePurchases","runningCampaigns","totalCampaigns","totalEarnings","earnings30d","earningsToday","availableBalance","heldBalance"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/billing/earnings-by-route":{"get":{"operationId":"getBillingEarningsByRoute","tags":["Billing"],"summary":"Get seller earnings broken down by route","description":"Top 50 routes by earnings over the last `days`. Attribution comes from call records, so it is partial: records without a route land in an \"Unattributed\" row, and the total can differ slightly from the credit ledger (`attribution: \"partial\"`).\n\n**Auth:** API key or JWT. Scoped keys need `account:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"routeId":{"type":"string","format":"uuid","nullable":true},"destinationName":{"type":"string"},"credits":{"$ref":"#/components/schemas/Money"},"count":{"type":"integer"}},"required":["routeId","destinationName","credits","count"]}},"days":{"type":"integer"},"attribution":{"type":"string","enum":["partial"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":365,"default":30}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/billing/usage-by-destination":{"get":{"operationId":"getBillingUsageByDestination","tags":["Billing"],"summary":"Get your outbound usage grouped by destination country","description":"Records, voice sessions, answered sessions, minutes, SMS segments, ASR, ACD and cost per destination country. ASR is voice-only and counted over customer sessions (a failed-over call counts once). With no dates the window is all time; `basis.window` states the window used. `format=csv` returns a CSV file.\n\n**Auth:** API key or JWT. Scoped keys need `account:read`.\n\n**Rate limit:** 30 requests per minute per caller.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"country":{"type":"string"},"countryCode":{"type":"string","nullable":true},"attempts":{"type":"integer","description":"Deprecated: same as `records` (a row count, not a call count)"},"records":{"type":"integer"},"voiceSessions":{"type":"integer"},"answered":{"type":"integer"},"minutes":{"type":"number"},"segments":{"type":"integer"},"asr":{"type":"number","nullable":true,"description":"Percent, voice only; null with no voice sessions"},"asrBasis":{"type":"object","properties":{},"additionalProperties":true,"description":"Which population and window the ASR counts"},"acd":{"type":"number","nullable":true,"description":"Average answered duration in seconds"},"cost":{"$ref":"#/components/schemas/Money"}},"required":["country","countryCode","attempts","records","voiceSessions","answered","minutes","segments","asr","asrBasis","acd","cost"]}},"basis":{"type":"object","properties":{"population":{"type":"string","enum":["customer_sessions"]},"window":{"type":"string"}},"required":["population","window"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:read","x-rate-limit":{"max":30,"window":"minute"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"from","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"format","in":"query","required":false,"schema":{"type":"string","enum":["json","csv"]}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/billing/balance-history":{"get":{"operationId":"getBillingBalanceHistory","tags":["Billing"],"summary":"Get your end-of-day balance history","description":"One point per UTC day that had ledger activity. Balances here are plain JSON numbers for charting, not ledger strings.\n\n**Auth:** API key or JWT. Scoped keys need `account:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"points":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string","description":"YYYY-MM-DD (UTC)"},"balance":{"type":"number"}},"required":["date","balance"]}},"currentBalance":{"type":"number"},"hasData":{"type":"boolean"}},"required":["points","currentBalance","hasData"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":90,"default":30}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/billing/traffic-timeseries":{"get":{"operationId":"getBillingTrafficTimeseries","tags":["Billing"],"summary":"Get daily voice and SMS spend","description":"Charges per UTC day split into voice and SMS. Amounts are plain JSON numbers for charting.\n\n**Auth:** API key or JWT. Scoped keys need `account:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"points":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string","description":"YYYY-MM-DD (UTC)"},"voice":{"type":"number"},"sms":{"type":"number"},"total":{"type":"number"}},"required":["date","voice","sms","total"]}},"days":{"type":"integer"},"hasData":{"type":"boolean"}},"required":["points","days","hasData"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":90,"default":30}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/billing/cdrs":{"get":{"operationId":"getBillingCdrs","tags":["Billing"],"summary":"List your call and message records","description":"Your call detail records (test probes excluded), newest first, cursor-paginated. With `format=csv` the response is a CSV file of up to 50,000 rows. For larger exports use `POST /billing/exports`.\n\n**Auth:** API key or JWT. Scoped keys need `account:read`.","responses":{"200":{"description":"One page of results, newest first.","content":{"application/json":{"schema":{"type":"object","required":["success","data","nextCursor","hasMore"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/BillingCdr"}},"nextCursor":{"type":"string","nullable":true,"description":"Pass as `cursor` to fetch the next page; null on the last page."},"hasMore":{"type":"boolean","description":"True when another page exists."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"from","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"kind","in":"query","required":false,"schema":{"type":"string","enum":["voice","sms"]}},{"name":"direction","in":"query","required":false,"schema":{"type":"string","enum":["outbound","inbound"]}},{"name":"routeId","in":"query","required":false,"description":"Only the calls on this route (JSON list only; the CSV ignores it)","schema":{"type":"string","format":"uuid"}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"format","in":"query","required":false,"description":"csv streams up to 50,000 rows","schema":{"type":"string","enum":["json","csv"]}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/billing/cdrs/failure-summary":{"get":{"operationId":"getBillingCdrsFailureSummary","tags":["Billing"],"summary":"Top reasons your calls failed","description":"Your failed calls over the last `days` (default 7, at most 31), grouped into plain-English reasons, largest first, each with whose move it is and a fix where there is one.\n\n**Auth:** API key or JWT. Scoped keys need `account:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"days":{"type":"integer"},"since":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"calls":{"type":"integer","description":"Voice attempts in the window"},"failed":{"type":"integer"},"rows":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"who":{"type":"string","enum":["you","route","destination","platform","unknown"]},"title":{"type":"string"},"explanation":{"type":"string"},"fix":{"type":"object","properties":{"label":{"type":"string"},"href":{"type":"string"}},"required":["label","href"]},"count":{"type":"integer"},"share":{"type":"number"}},"required":["key","who","title","explanation","count","share"]}}},"required":["days","since","calls","failed","rows"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":31,"default":7}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/billing/cdrs/export":{"get":{"operationId":"getBillingCdrsExport","tags":["Billing"],"summary":"Stream your call records as CSV","description":"Streams every matching record (up to 1,000,000 rows) as a CSV file in one response.\n\n**Auth:** API key or JWT. Scoped keys need `account:read`.","responses":{"200":{"description":"A CSV file of call detail records.","content":{"text/csv":{"schema":{"type":"string","format":"binary"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"from","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"kind","in":"query","required":false,"schema":{"type":"string","enum":["voice","sms"]}},{"name":"direction","in":"query","required":false,"schema":{"type":"string","enum":["outbound","inbound"]}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/billing/exports":{"post":{"operationId":"postBillingExports","tags":["Billing"],"summary":"Start a background call-record export","description":"Queues a CSV export job. At most 3 exports may be pending or running at once; a fourth gets 429 `TOO_MANY_EXPORTS`. Poll `GET /billing/exports` and download when `downloadable` is true.\n\n**Auth:** API key or JWT. Scoped keys need `account:read`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"202":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/BillingExportJob"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:read","x-error-codes":["TOO_MANY_EXPORTS"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"from":{"type":"string","format":"date-time"},"to":{"type":"string","format":"date-time"},"filters":{"type":"object","properties":{"from":{"type":"string","format":"date-time"},"to":{"type":"string","format":"date-time"},"kind":{"type":"string","enum":["voice","sms"]},"direction":{"type":"string","enum":["outbound","inbound"]}},"description":"Takes precedence over the top-level from/to"}}}}}},"x-px-example":{"path":{},"query":{},"body":{"from":"2026-10-01T09:00:00Z","to":"2026-10-01T09:00:00Z"}}},"get":{"operationId":"getBillingExports","tags":["Billing"],"summary":"List your call-record exports","description":"Your 50 most recent export jobs.\n\n**Auth:** API key or JWT. Scoped keys need `account:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/BillingExportJob"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/billing/exports/{id}/download":{"get":{"operationId":"getBillingExportsByIdDownload","tags":["Billing"],"summary":"Download a finished call-record export","description":"Returns the CSV file. Only the account that queued the export can download it (another account gets 404). 409 `EXPORT_NOT_READY` while the job is not finished; 410 `EXPORT_EXPIRED` once the retention sweep has deleted the file.\n\n**Auth:** API key or JWT. Scoped keys need `account:read`.","responses":{"200":{"description":"The export as a CSV file.","content":{"text/csv":{"schema":{"type":"string","format":"binary"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:read","x-error-codes":["EXPORT_NOT_READY","EXPORT_EXPIRED"],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/billing/invoices":{"get":{"operationId":"getBillingInvoices","tags":["Billing"],"summary":"List your receipts and statements","description":"Top-up receipts and statements (up to 200, newest first). For numbered tax invoices see `GET /billing/tax-invoices`.\n\n**Auth:** API key or JWT. Scoped keys need `account:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/BillingDocument"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/billing/invoices/{id}":{"get":{"operationId":"getBillingInvoicesById","tags":["Billing"],"summary":"Get a receipt or statement","description":"JSON by default; `format=html` returns a self-contained printable page.\n\n**Auth:** API key or JWT. Scoped keys need `account:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"number":{"type":"integer","description":"Sequential document number; printed as INV-000123"},"type":{"type":"string","enum":["topup_receipt","statement"]},"amount":{"$ref":"#/components/schemas/Money"},"currency":{"type":"string"},"periodStart":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"periodEnd":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"dataJson":{"type":"object","additionalProperties":{},"nullable":true}},"required":["id","number","type","amount","currency","periodStart","periodEnd","createdAt","dataJson"],"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"format","in":"query","required":false,"description":"html returns a printable page","schema":{"type":"string","enum":["json","html"]}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/billing/statements":{"get":{"operationId":"getBillingStatements","tags":["Billing"],"summary":"Get your monthly statement","description":"Every ledger line in a calendar month (UTC) with totals by type and the tax on platform fees. Totals and `net` are plain JSON numbers; line-item amounts are ledger strings. `format=csv` returns a CSV file.\n\n**Auth:** API key or JWT. Scoped keys need `account:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"month":{"type":"string"},"periodStart":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"periodEnd":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"net":{"type":"number","description":"credits + top-ups - charges - payouts"},"totals":{"type":"object","properties":{"charges":{"type":"number"},"credits":{"type":"number"},"topups":{"type":"number"},"payouts":{"type":"number"},"byType":{"type":"object","additionalProperties":{"type":"object","properties":{"amount":{"type":"number"},"count":{"type":"integer"}},"required":["amount","count"]}}},"required":["charges","credits","topups","payouts","byType"]},"lineItems":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"type":{"type":"string","enum":["topup","charge","credit","payout","platform_fee","test_credit","chargeback","refund_reversal","refund","transfer"]},"amount":{"$ref":"#/components/schemas/Money"},"reference":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","type","amount","reference","createdAt"]}},"tax":{"type":"object","properties":{"taxableSupply":{"type":"string","enum":["platform_fees"]},"base":{"type":"number"},"ratePct":{"type":"number"},"taxAmount":{"type":"number"},"total":{"type":"number"},"treatment":{"type":"string"},"label":{"type":"string"},"note":{"type":"string","nullable":true},"taxId":{"type":"string","nullable":true},"taxCountry":{"type":"string","nullable":true},"homeCountry":{"type":"string"}},"required":["taxableSupply","base","ratePct","taxAmount","total","treatment","label","note","taxId","taxCountry","homeCountry"],"additionalProperties":true}},"required":["month","periodStart","periodEnd","net","totals","lineItems","tax"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"month","in":"query","required":true,"description":"Calendar month, YYYY-MM (UTC)","schema":{"type":"string","pattern":"^\\d{4}-\\d{2}$"}},{"name":"format","in":"query","required":false,"schema":{"type":"string","enum":["json","csv"]}}],"x-px-example":{"path":{},"query":{"month":"<month>"}}}},"/api/v1/billing/earnings":{"get":{"operationId":"getBillingEarnings","tags":["Billing"],"summary":"Daily seller earnings","description":"Seller earnings (credit ledger) per UTC day for the last `window` days (1-90, default 30), oldest first and zero-filled, with the today / 7-day / 30-day windows.\n\n**Auth:** API key or JWT. Scoped keys need `account:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"window":{"type":"integer"},"points":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string","description":"YYYY-MM-DD (UTC)"},"credits":{"$ref":"#/components/schemas/Money"}},"required":["date","credits"]}},"total":{"$ref":"#/components/schemas/Money"},"hasData":{"type":"boolean"},"windows":{"type":"object","properties":{"today":{"$ref":"#/components/schemas/Money"},"last7d":{"$ref":"#/components/schemas/Money"},"last30d":{"$ref":"#/components/schemas/Money"}},"required":["today","last7d","last30d"]}},"required":["window","points","total","hasData","windows"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"window","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":90,"default":30}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/billing/today-kpis":{"get":{"operationId":"getBillingTodayKpis","tags":["Billing"],"summary":"Today at a glance","description":"Calls in progress (live reservations), and today's (UTC) calls, answered calls, ASR %, ACD seconds and messages from your own call records. Calls are counted as sessions; probes are excluded.\n\n**Auth:** API key or JWT. Scoped keys need `account:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"callsInProgress":{"type":"integer","nullable":true},"callsToday":{"type":"integer"},"answeredToday":{"type":"integer"},"asrToday":{"type":"number","nullable":true},"acdToday":{"type":"integer","nullable":true},"messagesToday":{"type":"integer"},"since":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["callsInProgress","callsToday","answeredToday","asrToday","acdToday","messagesToday","since","updatedAt"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/billing/hold-schedule":{"get":{"operationId":"getBillingHoldSchedule","tags":["Billing"],"summary":"When held money becomes withdrawable","description":"Each card top-up still inside the chargeback window with its release time, plus any customer-funded balance (never withdrawable, `releasesAt: null`), with the balance, held and withdrawable totals the payout path uses.\n\n**Auth:** API key or JWT. Scoped keys need `account:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"entries":{"type":"array","items":{"type":"object","properties":{"amount":{"$ref":"#/components/schemas/Money"},"releasesAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"source":{"type":"string","enum":["card","customer_funds"]}},"required":["amount","releasesAt","source"]}},"balance":{"$ref":"#/components/schemas/Money"},"held":{"$ref":"#/components/schemas/Money"},"withdrawable":{"$ref":"#/components/schemas/Money"},"holdDays":{"type":"integer"}},"required":["entries","balance","held","withdrawable","holdDays"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/billing/financial-activity/position":{"get":{"operationId":"getBillingFinancialActivityPosition","tags":["Billing"],"summary":"Get the financial position of your wallet or a sub-account","description":"Posted balance, credit limit, reserved for live calls, settlement holds, pending payments, and what that leaves to spend, with the source of each figure. Figures are plain JSON numbers (USD). Pass `customerId` for a sub-account you operate.\n\n**Auth:** API key or JWT. Scoped keys need `account:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"walletKind":{"type":"string","enum":["user","sub_account"]},"walletId":{"type":"string","format":"uuid"},"label":{"type":"string"},"currency":{"type":"string"},"postedBalance":{"type":"number"},"creditLimit":{"type":"number"},"creditLimitRecorded":{"type":"boolean"},"reservedForActiveCalls":{"type":"number"},"settlementHolds":{"type":"number"},"pendingPayments":{"type":"number"},"promotionalCredit":{"type":"number"},"confirmedFunds":{"type":"number"},"availableToSpend":{"type":"number"},"overCommitted":{"type":"boolean"},"negativeBalance":{"type":"string","enum":["not_negative","within_agreed_credit","beyond_agreed_credit"]},"beyondCreditBy":{"type":"number"},"activeCalls":{"type":"integer"},"reservationEnforced":{"type":"boolean","description":"True when reservations actually gate new calls, not just observe them"},"creditNote":{"type":"string"},"sources":{"type":"object","additionalProperties":{"type":"string"}}},"required":["walletKind","walletId","label","currency","postedBalance","creditLimit","creditLimitRecorded","reservedForActiveCalls","settlementHolds","pendingPayments","promotionalCredit","confirmedFunds","availableToSpend","overCommitted","negativeBalance","beyondCreditBy","activeCalls","reservationEnforced","creditNote","sources"],"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"customerId","in":"query","required":false,"description":"A sub-account you operate; omit for your own wallet","schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/billing/financial-activity/authorisations":{"get":{"operationId":"getBillingFinancialActivityAuthorisations","tags":["Billing"],"summary":"List live call authorisations on a wallet","description":"Funds currently reserved for calls in progress. Amounts are plain JSON numbers (USD).\n\n**Auth:** API key or JWT. Scoped keys need `account:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"calls":{"type":"array","items":{"type":"object","properties":{"callUuid":{"type":"string"},"amount":{"type":"number"},"expiresAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["callUuid","amount","expiresAt"]}},"total":{"type":"number"},"enforced":{"type":"boolean"}},"required":["calls","total","enforced"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"customerId","in":"query","required":false,"description":"A sub-account you operate; omit for your own wallet","schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/billing/financial-activity/reconciliation":{"get":{"operationId":"getBillingFinancialActivityReconciliation","tags":["Billing"],"summary":"Reconcile a wallet balance against its ledger","description":"Explains the posted balance by ledger component and reports anything it cannot explain as unreconciled, rather than as confirmed money. Amounts are plain JSON numbers (USD).\n\n**Auth:** API key or JWT. Scoped keys need `account:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"walletKind":{"type":"string","enum":["user","sub_account"]},"walletId":{"type":"string","format":"uuid"},"label":{"type":"string"},"currency":{"type":"string"},"postedBalance":{"type":"number"},"openingBalance":{"type":"object","properties":{"amount":{"type":"number"},"documented":{"type":"boolean"},"note":{"type":"string"}},"required":["amount","documented","note"]},"components":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"label":{"type":"string"},"amount":{"type":"number"},"count":{"type":"integer"},"source":{"type":"string"}},"required":["key","label","amount","count","source"]}},"explained":{"type":"number"},"unattributed":{"type":"object","properties":{"amount":{"type":"number"},"count":{"type":"integer"},"note":{"type":"string"}},"required":["amount","count","note"]},"unreconciled":{"type":"number"},"hasUnreconciled":{"type":"boolean"},"unpostedUsage":{"type":"object","properties":{"amount":{"type":"number"},"calls":{"type":"integer"},"note":{"type":"string"}},"required":["amount","calls","note"]},"checkedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["walletKind","walletId","label","currency","postedBalance","openingBalance","components","explained","unattributed","unreconciled","hasUnreconciled","unpostedUsage","checkedAt"],"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"customerId","in":"query","required":false,"description":"A sub-account you operate; omit for your own wallet","schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/billing/financial-activity/activity":{"get":{"operationId":"getBillingFinancialActivityActivity","tags":["Billing"],"summary":"List posted, pending and unposted money movements","description":"One timeline of posted ledger lines, pending payments and usage not yet posted. `truncated` is true when more rows matched than `limit`. Amounts are plain JSON numbers (USD).\n\n**Auth:** API key or JWT. Scoped keys need `account:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"rows":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"state":{"type":"string","enum":["posted","pending","usage"]},"at":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"kind":{"type":"string"},"label":{"type":"string"},"amount":{"type":"number"},"balanceAfter":{"type":"number","nullable":true},"reference":{"type":"string","nullable":true},"callId":{"type":"string","nullable":true},"traceTo":{"type":"string"}},"required":["id","state","at","kind","label","amount","balanceAfter","reference","callId","traceTo"],"additionalProperties":true}},"truncated":{"type":"boolean"}},"required":["rows","truncated"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"customerId","in":"query","required":false,"description":"A sub-account you operate; omit for your own wallet","schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500,"default":100}},{"name":"from","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"state","in":"query","required":false,"schema":{"type":"string","enum":["all","posted","pending","usage"]}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/billing/financial-activity/customers":{"get":{"operationId":"getBillingFinancialActivityCustomers","tags":["Billing"],"summary":"List sub-account wallets you operate with their positions","description":"Every non-closed sub-account with its balance, credit and what it can spend now. Amounts are plain JSON numbers.\n\n**Auth:** API key or JWT. Scoped keys need `account:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"label":{"type":"string"},"currency":{"type":"string"},"status":{"type":"string"},"postedBalance":{"type":"number"},"creditLimit":{"type":"number"},"confirmedFunds":{"type":"number"},"reservedForActiveCalls":{"type":"number"},"activeCalls":{"type":"integer"},"availableToSpend":{"type":"number"},"negativeWithinAgreedCredit":{"type":"boolean"},"beyondAgreedCredit":{"type":"boolean"}},"required":["id","label","currency","status","postedBalance","creditLimit","confirmedFunds","reservedForActiveCalls","activeCalls","availableToSpend","negativeWithinAgreedCredit","beyondAgreedCredit"]}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/interconnections/ips":{"get":{"operationId":"getInterconnectionsIps","tags":["Interconnections"],"summary":"List your whitelisted source IPs","description":"**Auth:** API key or JWT. Scoped keys need `account:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/WhitelistedIp"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}},"post":{"operationId":"postInterconnectionsIps","tags":["Interconnections"],"summary":"Whitelist a source IP for your traffic","description":"An address can authenticate for one account only; an address already registered elsewhere is refused with VALIDATION_ERROR.\n\n**Auth:** API key or JWT. Scoped keys need `account:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/WhitelistedIp"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"ipAddress":{"type":"string","minLength":7,"maxLength":49},"label":{"type":"string","maxLength":100}},"required":["ipAddress"]}}}},"x-px-example":{"path":{},"query":{},"body":{"ipAddress":"203.0.113.10"}}}},"/api/v1/interconnections/ips/{id}":{"delete":{"operationId":"deleteInterconnectionsIpsById","tags":["Interconnections"],"summary":"Remove a whitelisted source IP","description":"Traffic from the address is refused from then on.\n\n**Auth:** API key or JWT. Scoped keys need `account:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/Message"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/interconnections":{"get":{"operationId":"getInterconnections","tags":["Interconnections"],"summary":"List your interconnections","description":"One per purchase, with your credentials, the route (never its seller endpoint) and `pricing`: what you are actually billed on the route. `route.pricePerUnit` is the list price only.\n\n**Auth:** API key or JWT. Scoped keys need `account:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"purchaseId":{"type":"string","format":"uuid"},"type":{"type":"string","enum":["sip","smpp","api"]},"buyerEndpoint":{"type":"object","additionalProperties":{},"nullable":true,"description":"Your own connection settings and credentials"},"sellerEndpoint":{"enum":["null"],"nullable":true,"description":"Always null: the seller endpoint is never shown to buyers"},"status":{"type":"string","enum":["active","inactive"]},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"purchase":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string"},"sipUsername":{"type":"string","nullable":true},"sipPassword":{"type":"string","nullable":true},"smppSystemId":{"type":"string","nullable":true},"smppPassword":{"type":"string","nullable":true}},"required":["id","status","sipUsername","sipPassword","smppSystemId","smppPassword"],"nullable":true},"route":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"type":{"type":"string","enum":["voice","sms"]},"country":{"type":"string","nullable":true},"countryCode":{"type":"string","nullable":true},"prefix":{"type":"array","items":{"type":"string"}},"destinationName":{"type":"string","nullable":true,"description":"The listing name as a buyer reads it: generated by the platform, never the seller's text, and ending in the listing reference (e.g. \"Niger Mobile · Ref 7K2Q\", \"A-Z Voice · Premium · Full CLI · Ref 3MX9\"). Your own listings keep the name you gave them."},"listingRef":{"type":"string","description":"Anonymous short reference of the listing (4 characters, e.g. \"7K2Q\"): stable for the life of the listing, unique enough to tell two same-named listings apart, and derived from the listing alone (it says nothing about the seller). Absent on your own listings."},"pricePerUnit":{"allOf":[{"$ref":"#/components/schemas/Money"}],"description":"List price only; see `pricing` for what you pay"},"billingIncrement":{"type":"string","nullable":true},"jingleSipIp":{"enum":["null"],"nullable":true},"capacity":{"type":"integer","nullable":true},"rateCount":{"type":"integer","description":"Destinations on the rate deck; > 0 means priced per destination"}},"required":["id","type","country","countryCode","prefix","destinationName","pricePerUnit","billingIncrement","jingleSipIp","capacity","rateCount"],"nullable":true},"pricing":{"type":"object","properties":{"basis":{"type":"string","enum":["flat","per_destination"]}},"required":["basis"],"additionalProperties":true,"nullable":true,"description":"Your real rate basis for this route"}},"required":["id","purchaseId","type","buyerEndpoint","sellerEndpoint","status","createdAt","updatedAt","purchase","route","pricing"]}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/interconnections/{id}":{"get":{"operationId":"getInterconnectionsById","tags":["Interconnections"],"summary":"Get an interconnection","description":"In `buyerEndpoint` the SIP password is replaced by `sipPasswordSet` (here and on the two PUTs); the list endpoint carries your plaintext credentials for the connection card.\n\n**Auth:** API key or JWT. Scoped keys need `account:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/Interconnection"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}},"put":{"operationId":"putInterconnectionsById","tags":["Interconnections"],"summary":"Update an interconnection","description":"**Auth:** API key or JWT. Scoped keys need `account:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/Interconnection"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["active","inactive"]}}}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"status":"active"}}}},"/api/v1/interconnections/{id}/dlr-config":{"put":{"operationId":"putInterconnectionsByIdDlrConfig","tags":["Interconnections"],"summary":"Set delivery-receipt settings on an SMS interconnection","description":"Stores whether to request delivery receipts and the https callback URL for them.\n\n**Auth:** API key or JWT. Scoped keys need `account:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/Interconnection"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"requestDlrs":{"type":"boolean"},"dlrCallbackUrl":{"type":"string","format":"uri","nullable":true}},"required":["requestDlrs"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"requestDlrs":true}}}},"/api/v1/interconnections/test":{"post":{"operationId":"postInterconnectionsTest","tags":["Interconnections"],"summary":"Test connectivity on a purchased route","description":"`sip_options` probes reachability from every media worker. `test_call` places a real billed test call to `testNumber`; `smpp_bind` checks an SMS bind. Test calls and binds are capped per purchase per hour and per day.\n\n**Auth:** API key or JWT. Scoped keys need `account:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"status":{"type":"string","description":"Outcome: connected, degraded, failed, no_answer, error or unknown"},"message":{"type":"string"},"details":{"type":"object","additionalProperties":{},"description":"Diagnostic trace. Never carries the seller address."}},"required":["status","message","details"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"purchaseId":{"type":"string","format":"uuid"},"testType":{"type":"string","enum":["sip_options","test_call","smpp_bind"],"default":"sip_options"},"testNumber":{"type":"string","minLength":5,"maxLength":30},"testCli":{"type":"string","minLength":3,"maxLength":30}},"required":["purchaseId"]}}}},"x-px-example":{"path":{},"query":{},"body":{"purchaseId":"<purchaseId>"}},"x-px-billable":{"kind":"traffic","note":"Sends real test traffic over the purchased route."}}},"/api/v1/interconnections/routes/{routeId}/allow-addresses":{"get":{"operationId":"getInterconnectionsRoutesByRouteIdAllowAddresses","tags":["Interconnections"],"summary":"GET /api/v1/interconnections/routes/{routeId}/allow-addresses","description":"**Auth:** API key or JWT. Scoped keys need `account:read`.","responses":{"200":{"description":" Response shape not documented yet: the standard `{ \"success\": true, \"data\": ... }` envelope."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"routeId","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"routeId":"<routeId>"},"query":{}}}},"/api/v1/interconnections/routes/{routeId}/test-call":{"post":{"operationId":"postInterconnectionsRoutesByRouteIdTestCall","tags":["Interconnections"],"summary":"POST /api/v1/interconnections/routes/{routeId}/test-call","description":"**Auth:** API key or JWT. Scoped keys need `account:write`.\n\n**Rate limit:** 6 requests per minute per caller.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":" Response shape not documented yet: the standard `{ \"success\": true, \"data\": ... }` envelope."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:write","x-rate-limit":{"max":6,"window":"minute"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"routeId","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"routeId":"<routeId>"},"query":{}}}},"/api/v1/interconnections/status/summary":{"get":{"operationId":"getInterconnectionsStatusSummary","tags":["Interconnections"],"summary":"Get a summary of your interconnect setup","description":"**Auth:** API key or JWT. Scoped keys need `account:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"whitelistedIps":{"type":"integer"},"activePurchases":{"type":"integer"},"activeInterconnections":{"type":"integer"},"totalInterconnections":{"type":"integer"},"sipPublicIp":{"type":"string","description":"The edge address to send SIP traffic to"}},"required":["whitelistedIps","activePurchases","activeInterconnections","totalInterconnections","sipPublicIp"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/interconnections/health":{"get":{"operationId":"getInterconnectionsHealth","tags":["Interconnections"],"summary":"Get live connection health per purchase","description":"SIP purchases report whether the switch is up and the route configured; SMS purchases report their SMPP bind state.\n\n**Auth:** API key or JWT. Scoped keys need `account:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"purchaseId":{"type":"string","format":"uuid"},"protocol":{"type":"string","enum":["sip","smpp"]},"bound":{"type":"boolean"},"boundAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"lastMessageAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"remoteIp":{"type":"string","nullable":true},"configured":{"type":"boolean"},"reachable":{"type":"boolean"}},"required":["purchaseId","protocol","bound","boundAt","lastMessageAt","remoteIp","reachable"]}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/interconnections/{purchaseId}/rotate-credentials":{"post":{"operationId":"postInterconnectionsByPurchaseIdRotateCredentials","tags":["Interconnections"],"summary":"Rotate the SIP and SMPP credentials on a purchase","description":"Issues new credentials, returned once. The old ones stop working immediately and open SMPP binds are dropped.\n\n**Auth:** API key or JWT. Scoped keys need `account:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"sipUsername":{"type":"string"},"sipPassword":{"type":"string"},"smppSystemId":{"type":"string"},"smppPassword":{"type":"string"},"unboundSessions":{"type":"integer"},"message":{"type":"string"}},"required":["sipUsername","sipPassword","smppSystemId","smppPassword","unboundSessions","message"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"purchaseId","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"purchaseId":"<purchaseId>"},"query":{}}}},"/api/v1/route-messages/threads":{"get":{"operationId":"getRouteMessagesThreads","tags":["Route messages"],"summary":"List your route conversations","description":"The other party is shown by a label, never by account.\n\n**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"routeId":{"type":"string","format":"uuid"},"buyerId":{"type":"string","format":"uuid"},"role":{"type":"string","enum":["buyer","seller"]},"routeName":{"type":"string","description":"The listing name as a buyer reads it: generated by the platform, never the seller's text, and ending in the listing reference (e.g. \"Niger Mobile · Ref 7K2Q\", \"A-Z Voice · Premium · Full CLI · Ref 3MX9\"). Your own listings keep the name you gave them."},"otherParty":{"type":"string"},"unread":{"type":"integer"},"total":{"type":"integer"}},"required":["routeId","buyerId","role","routeName","otherParty","unread","total"],"additionalProperties":true}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/route-messages/{routeId}/{buyerId}":{"get":{"operationId":"getRouteMessagesByRouteIdByBuyerId","tags":["Route messages"],"summary":"Get one route conversation","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"routeId":{"type":"string","format":"uuid"},"buyerId":{"type":"string","format":"uuid"},"role":{"type":"string","enum":["buyer","seller"]},"routeName":{"type":"string","description":"The listing name as a buyer reads it: generated by the platform, never the seller's text, and ending in the listing reference (e.g. \"Niger Mobile · Ref 7K2Q\", \"A-Z Voice · Premium · Full CLI · Ref 3MX9\"). Your own listings keep the name you gave them."},"otherParty":{"type":"string"},"messages":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"routeId":{"type":"string","format":"uuid"},"buyerId":{"type":"string","format":"uuid"},"mine":{"type":"boolean"},"body":{"type":"string"},"readAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","routeId","buyerId","mine","body","readAt","createdAt"],"additionalProperties":true}}},"required":["routeId","buyerId","role","routeName","otherParty","messages"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"routeId","in":"path","required":true,"schema":{"type":"string"}},{"name":"buyerId","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"routeId":"<routeId>","buyerId":"<buyerId>"},"query":{}}}},"/api/v1/route-messages":{"post":{"operationId":"postRouteMessages","tags":["Route messages"],"summary":"Send a message about a route","description":"Contact details (emails, phone numbers, links, handles) are refused. Sellers must pass `buyerId` to start a thread.\n\n**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"routeId":{"type":"string","format":"uuid"},"buyerId":{"type":"string","format":"uuid"},"mine":{"type":"boolean"},"body":{"type":"string"},"readAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"senderId":{"type":"string","format":"uuid"}},"required":["id","routeId","buyerId","mine","body","readAt","createdAt","senderId"],"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"routeId":{"type":"string","format":"uuid"},"body":{"type":"string","minLength":1,"maxLength":4000},"buyerId":{"type":"string","format":"uuid"}},"required":["routeId","body"]}}}},"x-px-example":{"path":{},"query":{},"body":{"routeId":"<routeId>","body":"Hello from Acme"}}}},"/api/v1/route-reports":{"get":{"operationId":"getRouteReports","tags":["Route reports"],"summary":"List route problem reports you raised or received","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/RouteReport"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"role","in":"query","required":false,"schema":{"type":"string","enum":["buyer","seller"]}},{"name":"status","in":"query","required":false,"schema":{"type":"string"}}],"x-px-example":{"path":{},"query":{}}},"post":{"operationId":"postRouteReports","tags":["Route reports"],"summary":"Report a problem with a route you bought","description":"Optionally attach a CDR and a fresh SIP trace. The seller sees you under a pseudonym.\n\n**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/RouteReport"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"routeId":{"type":"string","format":"uuid"},"cdrId":{"type":"string","format":"uuid"},"category":{"type":"string","enum":["call_failure","connectivity","quality","other"]},"subject":{"type":"string","maxLength":200},"message":{"type":"string","minLength":1,"maxLength":4000},"attachSipTrace":{"type":"boolean"}},"required":["routeId","message"]}}}},"x-px-example":{"path":{},"query":{},"body":{"routeId":"<routeId>","message":"Hello from Acme"}}}},"/api/v1/route-reports/action-counts":{"get":{"operationId":"getRouteReportsActionCounts","tags":["Route reports"],"summary":"Count route reports waiting on you","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"seller":{"type":"integer"},"buyer":{"type":"integer"},"total":{"type":"integer"}},"required":["seller","buyer","total"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/route-reports/alerts":{"get":{"operationId":"getRouteReportsAlerts","tags":["Route reports"],"summary":"GET /api/v1/route-reports/alerts","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":" Response shape not documented yet: the standard `{ \"success\": true, \"data\": ... }` envelope."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/route-reports/alerts/{routeId}/calls":{"get":{"operationId":"getRouteReportsAlertsByRouteIdCalls","tags":["Route reports"],"summary":"GET /api/v1/route-reports/alerts/{routeId}/calls","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":" Response shape not documented yet: the standard `{ \"success\": true, \"data\": ... }` envelope."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"routeId","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"routeId":"<routeId>"},"query":{}}}},"/api/v1/route-reports/alerts/{routeId}/calls/{cdrId}/trace":{"get":{"operationId":"getRouteReportsAlertsByRouteIdCallsByCdrIdTrace","tags":["Route reports"],"summary":"GET /api/v1/route-reports/alerts/{routeId}/calls/{cdrId}/trace","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":" Response shape not documented yet: the standard `{ \"success\": true, \"data\": ... }` envelope."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"routeId","in":"path","required":true,"schema":{"type":"string"}},{"name":"cdrId","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"routeId":"<routeId>","cdrId":"<cdrId>"},"query":{}}}},"/api/v1/route-reports/{id}":{"get":{"operationId":"getRouteReportsById","tags":["Route reports"],"summary":"Get a route report with its thread","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/RouteReportThread"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/route-reports/{id}/messages":{"post":{"operationId":"postRouteReportsByIdMessages","tags":["Route reports"],"summary":"Reply on a route report","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/RouteReportThread"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"body":{"type":"string","minLength":1,"maxLength":4000}},"required":["body"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"body":"Hello from Acme"}}}},"/api/v1/route-reports/{id}/acknowledge":{"post":{"operationId":"postRouteReportsByIdAcknowledge","tags":["Route reports"],"summary":"Acknowledge a route report (seller)","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/RouteReportThread"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/route-reports/{id}/resolve":{"post":{"operationId":"postRouteReportsByIdResolve","tags":["Route reports"],"summary":"Mark a route report resolved (seller)","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/RouteReportThread"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"note":{"type":"string","maxLength":4000}}}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"note":"Example"}}}},"/api/v1/route-reports/{id}/confirm":{"post":{"operationId":"postRouteReportsByIdConfirm","tags":["Route reports"],"summary":"Confirm a route report is fixed (buyer)","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/RouteReportThread"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/route-reports/{id}/reopen":{"post":{"operationId":"postRouteReportsByIdReopen","tags":["Route reports"],"summary":"Reopen a resolved route report (buyer)","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/RouteReportThread"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"note":{"type":"string","maxLength":4000}}}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"note":"Example"}}}},"/api/v1/route-reports/{id}/escalate":{"post":{"operationId":"postRouteReportsByIdEscalate","tags":["Route reports"],"summary":"Escalate a route report to support","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/RouteReportThread"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"note":{"type":"string","maxLength":4000}}}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"note":"Example"}}}},"/api/v1/connections/lookup":{"get":{"operationId":"getConnectionsLookup","tags":["Connections"],"summary":"Look up the account behind a connect code","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/ConnectionProfile"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"token","in":"query","required":true,"schema":{"type":"string","minLength":6,"maxLength":64}}],"x-px-example":{"path":{},"query":{"token":"<token>"}}}},"/api/v1/connections/code":{"get":{"operationId":"getConnectionsCode","tags":["Connections"],"summary":"Get your connect code","description":"Created on first read. Share it (or its QR) so another account can connect with you.\n\n**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"token":{"type":"string"}},"required":["token"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/connections/code/rotate":{"post":{"operationId":"postConnectionsCodeRotate","tags":["Connections"],"summary":"Rotate your connect code","description":"The old code stops working. Existing connections are kept.\n\n**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"token":{"type":"string"}},"required":["token"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/connections/connect":{"post":{"operationId":"postConnectionsConnect","tags":["Connections"],"summary":"Connect with another account by its code","description":"Both sides can then see each other's public routes; the owner is notified.\n\n**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"counterparty":{"$ref":"#/components/schemas/ConnectionProfile"}},"required":["connectionId","counterparty"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string","minLength":6,"maxLength":64}},"required":["token"]}}}},"x-px-example":{"path":{},"query":{},"body":{"token":"<token>"}}}},"/api/v1/connections":{"get":{"operationId":"getConnections","tags":["Connections"],"summary":"List your connections","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"counterparty":{"$ref":"#/components/schemas/ConnectionProfile"},"visibleRouteCount":{"type":"integer"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","counterparty","visibleRouteCount","createdAt"]}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/connections/{id}":{"get":{"operationId":"getConnectionsById","tags":["Connections"],"summary":"Get a connection with the routes each side can see","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"counterparty":{"$ref":"#/components/schemas/ConnectionProfile"},"theirRoutes":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"type":{"type":"string","enum":["voice","sms"]},"country":{"type":"string","nullable":true},"countryCode":{"type":"string","nullable":true},"prefix":{"type":"array","items":{"type":"string"}},"destinationName":{"type":"string","nullable":true},"pricePerUnit":{"allOf":[{"$ref":"#/components/schemas/Money"}],"description":"Your negotiated price when the route was shared privately, else the list price"},"customPrice":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"US dollars as a decimal string with exactly 6 decimal places, e.g. \"0.012500\". Do money arithmetic with a decimal type, not floating point."},"cliType":{"type":"string","nullable":true},"capacity":{"type":"integer","nullable":true},"billingIncrement":{"type":"string","nullable":true},"expectedAsr":{"type":"string","nullable":true},"expectedAcd":{"type":"string","nullable":true},"routeType":{"type":"string","nullable":true},"visibility":{"type":"string"},"jingleSipIp":{"enum":["null"],"nullable":true},"supportedCodecs":{"type":"array","items":{"type":"string"},"nullable":true}},"required":["id","type","country","countryCode","prefix","destinationName","pricePerUnit","customPrice","cliType","capacity","billingIncrement","expectedAsr","expectedAcd","routeType","visibility","jingleSipIp","supportedCodecs"]}},"myRoutes":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"type":{"type":"string","enum":["voice","sms"]},"country":{"type":"string","nullable":true},"countryCode":{"type":"string","nullable":true},"prefix":{"type":"array","items":{"type":"string"}},"destinationName":{"type":"string","nullable":true},"pricePerUnit":{"allOf":[{"$ref":"#/components/schemas/Money"}],"description":"Your negotiated price when the route was shared privately, else the list price"},"customPrice":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"US dollars as a decimal string with exactly 6 decimal places, e.g. \"0.012500\". Do money arithmetic with a decimal type, not floating point."},"cliType":{"type":"string","nullable":true},"capacity":{"type":"integer","nullable":true},"billingIncrement":{"type":"string","nullable":true},"expectedAsr":{"type":"string","nullable":true},"expectedAcd":{"type":"string","nullable":true},"routeType":{"type":"string","nullable":true},"visibility":{"type":"string"},"jingleSipIp":{"enum":["null"],"nullable":true},"supportedCodecs":{"type":"array","items":{"type":"string"},"nullable":true}},"required":["id","type","country","countryCode","prefix","destinationName","pricePerUnit","customPrice","cliType","capacity","billingIncrement","expectedAsr","expectedAcd","routeType","visibility","jingleSipIp","supportedCodecs"]}},"mySharesPrivate":{"type":"boolean"},"theySharePrivate":{"type":"boolean"},"interconnect":{"type":"object","properties":{"whitelistedIps":{"type":"integer"},"activePurchases":{"type":"integer"}},"required":["whitelistedIps","activePurchases"]}},"required":["connectionId","counterparty","theirRoutes","myRoutes","mySharesPrivate","theySharePrivate","interconnect"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}},"delete":{"operationId":"deleteConnectionsById","tags":["Connections"],"summary":"Remove a connection","description":"Private route access granted through the connection is revoked on both sides.\n\n**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]}},"required":["ok"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/connections/{id}/share-private":{"post":{"operationId":"postConnectionsByIdSharePrivate","tags":["Connections"],"summary":"Share or stop sharing your private routes with a connection","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"sharing":{"type":"boolean"}},"required":["ok","sharing"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean"}},"required":["enabled"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"enabled":true}}}},"/api/v1/markets/summary":{"get":{"operationId":"getMarketsSummary","tags":["Markets"],"summary":"Get the marketplace summary","description":"Public counts for everyone; capacity, ASR, ACD and average price only for signed-in callers.\n\n**Auth:** optional. Works anonymously; a token or API key personalises the answer.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"routes":{"type":"integer"},"destinations":{"type":"integer"},"voiceRoutes":{"type":"integer"},"smsRoutes":{"type":"integer"},"hasRoutes":{"type":"boolean"},"hasActivityData":{"type":"boolean"},"capacity":{"type":"integer"},"avgAsr":{"type":"number","nullable":true},"measuredAsr":{"type":"number","nullable":true},"measuredAsrSample":{"type":"integer"},"avgAcd":{"type":"number","nullable":true},"avgPrice":{"type":"number","nullable":true,"description":"Display figure"},"topMovers":{"type":"array","items":{}},"marketStatus":{"type":"string"},"asOf":{"type":"string","format":"date-time","description":"Start of the 24h activity window"}},"required":["routes","destinations","voiceRoutes","smsRoutes","hasRoutes","hasActivityData","topMovers","marketStatus","asOf"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"optional","security":[{},{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/pricing/destinations":{"get":{"operationId":"getPricingDestinations","tags":["Markets"],"summary":"List destinations with live routes and their lowest rates","description":"Public. Every destination with at least one live, buyer-visible route, per product: slug, route count and lowest rate. Pass `type` for one product; without it both `voice` and `sms` lists are returned. Rebuilt at most every 10 minutes (`Cache-Control: public, max-age=600`). Rates are the sellers' list prices before the platform fee.\n\n**Auth:** none (public endpoint).","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"voice":{"type":"array","items":{"$ref":"#/components/schemas/PricingDestination"}},"sms":{"type":"array","items":{"$ref":"#/components/schemas/PricingDestination"}},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["updatedAt"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"public","security":[],"parameters":[{"name":"type","in":"query","required":false,"schema":{"type":"string","enum":["voice","sms"]}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/pricing/destinations/{slug}":{"get":{"operationId":"getPricingDestinationsBySlug","tags":["Markets"],"summary":"Get the live market for one destination","description":"Public. Lowest rate per number type, mobile operator breakouts, caller-ID and billing-increment mix, and the five cheapest routes as anonymous facts (price, caller ID, increment, stated ASR). The ASR here is the one the seller states; measured figures per listing are on GET /routes (`measured`). 404 when the destination has no live route of that type. Cached like the list.\n\n**Auth:** none (public endpoint).","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/PricingDestinationDetail"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"public","security":[],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","pattern":"^[a-z0-9-]{1,80}$"}},{"name":"type","in":"query","required":false,"schema":{"type":"string","enum":["voice","sms"],"default":"voice"}}],"x-px-example":{"path":{"slug":"<slug>"},"query":{}}}},"/api/v1/route-access":{"get":{"operationId":"getRouteAccess","tags":["Route access"],"summary":"List access grants and requests on your private route","description":"For the seller. Private routes are invite-only, so the requesting buyer's email and name are shown here.\n\n**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/RouteAccessGrant"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"routeId","in":"query","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{},"query":{"routeId":"<routeId>"}}},"post":{"operationId":"postRouteAccess","tags":["Route access"],"summary":"Grant a buyer access to your private route","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.\n\n**Rate limit:** 30 requests per hour per caller.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/RouteAccessGrant"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-rate-limit":{"max":30,"window":"hour"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"routeId":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"customPrice":{"anyOf":[{"type":"string"},{"type":"number"}],"nullable":true}},"required":["routeId","email"]}}}},"x-px-example":{"path":{},"query":{},"body":{"routeId":"<routeId>","email":"you@example.com"}}}},"/api/v1/route-access/request":{"post":{"operationId":"postRouteAccessRequest","tags":["Route access"],"summary":"Request access to a private route","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.\n\n**Rate limit:** 20 requests per hour per caller.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/RouteAccessGrant"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-rate-limit":{"max":20,"window":"hour"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"routeId":{"type":"string","format":"uuid"},"message":{"type":"string","maxLength":500}},"required":["routeId"]}}}},"x-px-example":{"path":{},"query":{},"body":{"routeId":"<routeId>"}}}},"/api/v1/route-access/{id}/approve":{"post":{"operationId":"postRouteAccessByIdApprove","tags":["Route access"],"summary":"Approve an access request","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/RouteAccessGrant"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"customPrice":{"anyOf":[{"type":"string"},{"type":"number"}],"nullable":true}}}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"customPrice":"<customPrice>"}}}},"/api/v1/route-access/{id}":{"patch":{"operationId":"patchRouteAccessById","tags":["Route access"],"summary":"Change the custom price on an access grant","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/RouteAccessGrant"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"customPrice":{"anyOf":[{"type":"string"},{"type":"number"}],"nullable":true}}}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"customPrice":"<customPrice>"}}},"delete":{"operationId":"deleteRouteAccessById","tags":["Route access"],"summary":"Revoke an access grant","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"}},"required":["id"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/public/test-coverage":{"get":{"operationId":"getPublicTestCoverage","tags":["System"],"summary":"GET /api/v1/public/test-coverage","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":" Response shape not documented yet: the standard `{ \"success\": true, \"data\": ... }` envelope."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/tickets":{"post":{"operationId":"postTickets","tags":["Support"],"summary":"Open a support ticket","description":"The message becomes the first entry in the thread and support is alerted.\n\n**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SupportTicket"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"subject":{"type":"string","minLength":3,"maxLength":200},"message":{"type":"string","minLength":1,"maxLength":5000},"category":{"type":"string","maxLength":50}},"required":["subject","message"]}}}},"x-px-example":{"path":{},"query":{},"body":{"subject":"<subject>","message":"Hello from Acme"}}},"get":{"operationId":"getTickets","tags":["Support"],"summary":"List your support tickets","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/SupportTicket"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/tickets/{id}":{"get":{"operationId":"getTicketsById","tags":["Support"],"summary":"Get a support ticket with its messages","description":"Internal staff notes are never included.\n\n**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid","nullable":true},"guestEmail":{"type":"string","nullable":true},"category":{"type":"string","description":"Ticket category, e.g. billing_dispute, technical_support, other"},"subject":{"type":"string"},"status":{"type":"string","enum":["open","in_progress","resolved","closed"]},"relatedRouteId":{"type":"string","format":"uuid","nullable":true},"relatedPurchaseId":{"type":"string","format":"uuid","nullable":true},"assignedTo":{"type":"string","format":"uuid","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"resolvedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"messages":{"type":"array","items":{"$ref":"#/components/schemas/SupportTicketMessage"}}},"required":["id","userId","guestEmail","category","subject","status","relatedRouteId","relatedPurchaseId","assignedTo","createdAt","resolvedAt","messages"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/tickets/{id}/messages":{"post":{"operationId":"postTicketsByIdMessages","tags":["Support"],"summary":"Reply to a support ticket","description":"Replying to a resolved ticket reopens it.\n\n**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"authorId":{"type":"string","format":"uuid","nullable":true},"message":{"type":"string"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"ticketId":{"type":"string","format":"uuid"}},"required":["id","authorId","message","createdAt","ticketId"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","minLength":1,"maxLength":5000}},"required":["message"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"message":"Hello from Acme"}}}},"/api/v1/support/tickets":{"post":{"operationId":"postSupportTickets","tags":["Support"],"summary":"Contact support without an account","description":"The public contact form. When a valid credential is sent the ticket is filed on that account instead of as a guest ticket; an invalid credential is ignored, never refused.\n\n**Auth:** optional. Works anonymously; a token or API key personalises the answer.\n\n**Rate limit:** 5 requests per hour per caller.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"}},"required":["id"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"optional","x-rate-limit":{"max":5,"window":"hour"},"security":[{},{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"subject":{"type":"string","minLength":3,"maxLength":200},"message":{"type":"string","minLength":1,"maxLength":5000},"email":{"type":"string","format":"email","maxLength":254}},"required":["subject","message","email"]}}}},"x-px-example":{"path":{},"query":{},"body":{"subject":"<subject>","message":"Hello from Acme","email":"you@example.com"}}}},"/api/v1/dnc":{"get":{"operationId":"getDnc","tags":["Do not call"],"summary":"List your do-not-call entries","description":"Your own entries plus platform-wide ones. Both are suppressed from dialer and SMS traffic.\n\n**Auth:** API key or JWT. Scoped keys need `dialer:write`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/DncEntry"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"dialer:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}},"post":{"operationId":"postDnc","tags":["Do not call"],"summary":"Add a number to your do-not-call list","description":"Adding a number already on the list returns the existing entry.\n\n**Auth:** API key or JWT. Scoped keys need `dialer:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/DncEntry"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"dialer:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"phoneNumber":{"type":"string","minLength":3,"maxLength":32},"reason":{"type":"string","maxLength":500}},"required":["phoneNumber"]}}}},"x-px-example":{"path":{},"query":{},"body":{"phoneNumber":"+447700900123"}}}},"/api/v1/dnc/export":{"get":{"operationId":"getDncExport","tags":["Do not call"],"summary":"Download your do-not-call list as CSV","description":"**Auth:** API key or JWT. Scoped keys need `dialer:write`.","responses":{"200":{"description":"Columns: phone_number, scope (mine or platform), source, reason, added_at.","content":{"text/csv":{"schema":{"type":"string","format":"binary"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"dialer:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/dnc/bulk":{"post":{"operationId":"postDncBulk","tags":["Do not call"],"summary":"Add many numbers to your do-not-call list","description":"Up to 10,000 per request. Numbers already listed are skipped.\n\n**Auth:** API key or JWT. Scoped keys need `dialer:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"inserted":{"type":"integer"},"submitted":{"type":"integer"}},"required":["inserted","submitted"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"dialer:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"numbers":{"type":"array","items":{"type":"string","minLength":3,"maxLength":32},"minItems":1,"maxItems":10000}},"required":["numbers"]}}}},"x-px-example":{"path":{},"query":{},"body":{"numbers":["+447700900123"]}}}},"/api/v1/dnc/{id}":{"delete":{"operationId":"deleteDncById","tags":["Do not call"],"summary":"Remove a number from your do-not-call list","description":"Only your own entries can be removed; a platform-wide entry or another account's id is 404.\n\n**Auth:** API key or JWT. Scoped keys need `dialer:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"deleted":{"type":"boolean","enum":[true]}},"required":["id","deleted"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"dialer:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/ai-agents":{"get":{"operationId":"getAiAgents","tags":["AI voice agents"],"summary":"List your AI voice agents","description":"**Auth:** API key or JWT. Scoped keys need `dialer:write`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/AiAgent"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"dialer:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}},"post":{"operationId":"postAiAgents","tags":["AI voice agents"],"summary":"Create an AI voice agent","description":"**Auth:** API key or JWT. Scoped keys need `dialer:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/AiAgent"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"dialer:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"voiceId":{"type":"string","maxLength":120,"nullable":true},"voiceProvider":{"type":"string","maxLength":40},"language":{"type":"string","maxLength":12},"firstMessage":{"type":"string","maxLength":500,"nullable":true},"systemPrompt":{"type":"string","minLength":1,"maxLength":8000},"model":{"type":"string","maxLength":60},"guardrails":{"type":"string","maxLength":4000,"nullable":true},"tools":{"type":"array","items":{"type":"string","maxLength":60},"maxItems":20},"maxCallSeconds":{"type":"integer","minimum":1,"maximum":3600},"enabled":{"type":"boolean"}},"required":["name","systemPrompt"]}}}},"x-px-example":{"path":{},"query":{},"body":{"name":"Acme","systemPrompt":"<systemPrompt>"}}}},"/api/v1/ai-agents/voices":{"get":{"operationId":"getAiAgentsVoices","tags":["AI voice agents"],"summary":"List the voices an agent can speak with","description":"A trimmed list (about 60), English non-premium voices first.\n\n**Auth:** API key or JWT. Scoped keys need `dialer:write`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/AiVoice"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"dialer:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/ai-agents/voices/preview":{"post":{"operationId":"postAiAgentsVoicesPreview","tags":["AI voice agents"],"summary":"Hear a voice speak a short line","description":"Returns MP3 audio of `text` (up to 300 characters) in the chosen voice.\n\n**Auth:** API key or JWT. Scoped keys need `dialer:write`.\n\n**Rate limit:** 10 requests per minute per caller.","responses":{"200":{"description":"MP3 audio of the line.","content":{"audio/mpeg":{"schema":{"type":"string","format":"binary"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"dialer:write","x-rate-limit":{"max":10,"window":"minute"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"voiceId":{"type":"string","minLength":1,"maxLength":120},"text":{"type":"string","minLength":1,"maxLength":300}},"required":["voiceId","text"]}}}},"x-px-example":{"path":{},"query":{},"body":{"voiceId":"<voiceId>","text":"Hello from Acme"}}}},"/api/v1/ai-agents/draft":{"post":{"operationId":"postAiAgentsDraft","tags":["AI voice agents"],"summary":"Draft an agent from a plain-English description","description":"Turns a description such as \"call leads and book demos\" into a name, opening line, script, guardrails and suggested tools. Nothing is saved; pass the result to POST /ai-agents.\n\n**Auth:** API key or JWT. Scoped keys need `dialer:write`.\n\n**Rate limit:** 20 requests per minute per caller.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/AiAgentDraft"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"dialer:write","x-rate-limit":{"max":20,"window":"minute"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"description":{"type":"string","minLength":1,"maxLength":2000}},"required":["description"]}}}},"x-px-example":{"path":{},"query":{},"body":{"description":"Example"}}}},"/api/v1/ai-agents/{id}":{"get":{"operationId":"getAiAgentsById","tags":["AI voice agents"],"summary":"Get an AI voice agent","description":"**Auth:** API key or JWT. Scoped keys need `dialer:write`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/AiAgent"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"dialer:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}},"patch":{"operationId":"patchAiAgentsById","tags":["AI voice agents"],"summary":"Update an AI voice agent","description":"**Auth:** API key or JWT. Scoped keys need `dialer:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/AiAgent"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"dialer:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"voiceId":{"type":"string","maxLength":120,"nullable":true},"voiceProvider":{"type":"string","maxLength":40},"language":{"type":"string","maxLength":12},"firstMessage":{"type":"string","maxLength":500,"nullable":true},"systemPrompt":{"type":"string","minLength":1,"maxLength":8000},"model":{"type":"string","maxLength":60},"guardrails":{"type":"string","maxLength":4000,"nullable":true},"tools":{"type":"array","items":{"type":"string","maxLength":60},"maxItems":20},"maxCallSeconds":{"type":"integer","minimum":1,"maximum":3600},"enabled":{"type":"boolean"}}}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"name":"Acme","voiceId":"<voiceId>"}}},"delete":{"operationId":"deleteAiAgentsById","tags":["AI voice agents"],"summary":"Delete an AI voice agent","description":"**Auth:** API key or JWT. Scoped keys need `dialer:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"}},"required":["id"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"dialer:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/ai-agents/{id}/simulate":{"post":{"operationId":"postAiAgentsByIdSimulate","tags":["AI voice agents"],"summary":"Simulate one conversation turn with an agent","description":"Send what the callee said (`message`) plus the prior turns (`history`); the agent answers with its spoken reply and what it would do next. No call is placed and nothing is billed.\n\n**Auth:** API key or JWT. Scoped keys need `dialer:write`.\n\n**Rate limit:** 20 requests per minute per caller.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/AiAgentTurn"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"dialer:write","x-rate-limit":{"max":20,"window":"minute"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"history":{"type":"array","items":{"type":"object","properties":{"role":{"type":"string","enum":["user","assistant"]},"content":{"type":"string","maxLength":4000}},"required":["role","content"]},"maxItems":60},"message":{"type":"string","minLength":1,"maxLength":2000}},"required":["message"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"message":"Hello from Acme"}}}},"/api/v1/revshare/market":{"get":{"operationId":"getRevshareMarket","tags":["Revenue share numbers"],"summary":"List revenue share number types on the marketplace","description":"One row per destination range type, with how many numbers are free and the payout per minute at each payment term. No sign-in. `total` is the number of free numbers across all rows.\n\n**Auth:** none (public endpoint).\n\n**Rate limit:** 60 requests per minute per caller.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"country":{"type":"string"},"countryCode":{"type":"string","nullable":true},"isoCountry":{"type":"string","nullable":true},"rangeType":{"type":"string"},"prefix":{"type":"string","description":"Common leading digits of the type's numbers"},"available":{"type":"integer"},"payout":{"type":"object","properties":{"1_1":{"$ref":"#/components/schemas/Money"},"7_1":{"$ref":"#/components/schemas/Money"},"15_15":{"$ref":"#/components/schemas/Money"}},"required":["1_1","7_1","15_15"]}},"required":["country","countryCode","isoCountry","rangeType","prefix","available","payout"]}},"total":{"type":"integer"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"public","x-rate-limit":{"max":60,"window":"minute"},"security":[],"x-px-example":{"path":{},"query":{}}}},"/api/v1/revshare/numbers":{"get":{"operationId":"getRevshareNumbers","tags":["Revenue share numbers"],"summary":"Browse the revenue share number pool","description":"Cheapest first. Rates shown are what you earn per minute at the best payment term.\n\n**Auth:** API key or JWT. Scoped keys need `revshare:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/RevshareNumber"}},"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"revshare:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"country","in":"query","required":false,"description":"Country name contains","schema":{"type":"string"}},{"name":"countryCode","in":"query","required":false,"schema":{"type":"string"}},{"name":"q","in":"query","required":false,"description":"Number starts with these digits","schema":{"type":"string"}},{"name":"numberFrom","in":"query","required":false,"schema":{"type":"string"}},{"name":"numberTo","in":"query","required":false,"schema":{"type":"string"}},{"name":"maxRate","in":"query","required":false,"schema":{"type":"number"}},{"name":"status","in":"query","required":false,"description":"Default available","schema":{"type":"string","enum":["available","taken","retired"]}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer"}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/revshare/numbers/{id}/take":{"post":{"operationId":"postRevshareNumbersByIdTake","tags":["Revenue share numbers"],"summary":"Take a revenue share number","description":"You earn on every inbound minute to it, at the rate for the payment term you choose, frozen at take time. There is no limit on how many numbers of one type you hold. 409 if someone else took it first.\n\n**Auth:** API key or JWT. Scoped keys need `revshare:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/RevshareTaking"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"revshare:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"term":{"type":"string","enum":["1_1","7_1","15_15"]}},"required":["term"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"term":"1_1"}}}},"/api/v1/revshare/take-one-of-each":{"post":{"operationId":"postRevshareTakeOneOfEach","tags":["Revenue share numbers"],"summary":"Take one number of every available type","description":"Takes the lowest available number of every number type in the pool. `taken` is how many were taken, `groups` how many types had a free number.\n\n**Auth:** API key or JWT. Scoped keys need `revshare:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"taken":{"type":"integer"},"groups":{"type":"integer"}},"required":["taken","groups"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"revshare:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"term":{"type":"string","enum":["1_1","7_1","15_15"]}},"required":["term"]}}}},"x-px-example":{"path":{},"query":{},"body":{"term":"1_1"}}}},"/api/v1/revshare/take-bulk":{"post":{"operationId":"postRevshareTakeBulk","tags":["Revenue share numbers"],"summary":"Take several revenue share numbers by id","description":"Up to 200 pool number ids in one request, all at one payment term. Each number goes through the same checks as a single take; a number someone else took first is listed in `failed` with the reason, and the rest are still taken.\n\n**Auth:** API key or JWT. Scoped keys need `revshare:write`.\n\n**Rate limit:** 10 requests per minute per caller.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"taken":{"type":"integer"},"failed":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"reason":{"type":"string"}},"required":["id","reason"]}}},"required":["taken","failed"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"revshare:write","x-rate-limit":{"max":10,"window":"minute"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"ids":{"type":"array","items":{"type":"string","format":"uuid"},"minItems":1,"maxItems":200},"term":{"type":"string","enum":["1_1","7_1","15_15"]}},"required":["ids","term"]}}}},"x-px-example":{"path":{},"query":{},"body":{"ids":["<id>"],"term":"1_1"}}}},"/api/v1/revshare/take-range":{"post":{"operationId":"postRevshareTakeRange","tags":["Revenue share numbers"],"summary":"Take revenue share numbers by range","description":"Takes up to `count` (1 to 200) available numbers whose digits start with `prefix` (3 to 15 digits, from the country code, no plus). Numbers are picked in number order, lowest first, so the same request on the same pool picks the same block. `term` defaults to `15_15`. `country` optionally narrows by dial code (digits) or part of the country name. Each number is taken on its own through the same checks as a single take; a number someone else takes while the request runs is skipped and the next one tried. `available_before` is how many matched before taking, `shortfall` how many fewer than `count` were taken. 409 when no number in the range is available.\n\n**Auth:** API key or JWT. Scoped keys need `revshare:write`.\n\n**Rate limit:** 10 requests per minute per caller.\n\n**Idempotency:** send an `X-Idempotency-Key` header to make retries safe; a replay within 24 hours returns the original response.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"taken":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"numberId":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"paymentTerm":{"type":"string","enum":["1_1","7_1","15_15"],"description":"Settlement term: earnings held 1, 7 or 15 days, then requestable any day; sets the rate (88%, 95%, 100%)"},"effectiveRate":{"allOf":[{"$ref":"#/components/schemas/Money"}],"description":"What you earn per minute on this number"},"ivrConfigId":{"type":"string","format":"uuid","nullable":true},"ivrMode":{"type":"string","enum":["single","split","geo"]},"status":{"type":"string","enum":["active","released"]},"callsCount":{"type":"integer"},"minutesTotal":{"type":"string"},"earningsTotal":{"$ref":"#/components/schemas/Money"},"lastCallAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"takenAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"releasedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"number":{"type":"string"}},"required":["id","numberId","userId","paymentTerm","effectiveRate","ivrConfigId","ivrMode","status","callsCount","minutesTotal","earningsTotal","lastCallAt","takenAt","releasedAt","number"]}},"requested":{"type":"integer"},"available_before":{"type":"integer"},"shortfall":{"type":"integer"}},"required":["taken","requested","available_before","shortfall"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"revshare:write","x-rate-limit":{"max":10,"window":"minute"},"x-idempotent":true,"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"X-Idempotency-Key","in":"header","required":false,"description":"Any unique string (a UUID is ideal). Replays within 24 hours return the first response instead of acting twice.","schema":{"type":"string","maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"prefix":{"type":"string","pattern":"^[0-9]{3,15}$"},"count":{"type":"integer","minimum":1,"maximum":200},"term":{"type":"string","enum":["1_1","7_1","15_15"],"default":"15_15"},"country":{"type":"string","maxLength":60}},"required":["prefix","count"]}}}},"x-px-example":{"path":{},"query":{},"body":{"prefix":"44","count":1}},"x-px-billable":{"kind":"money","note":"Moves money on your account."}}},"/api/v1/revshare/numbers/export":{"get":{"operationId":"getRevshareNumbersExport","tags":["Revenue share numbers"],"summary":"Download free revenue share numbers for an access test","description":"A CSV of available numbers (columns number, country, country_code, network_type, range, rate_per_min), filtered like the take page. `mode=range` (default) gives one number per destination range, `mode=all` every number; at most 2,000 rows. The `X-Rows-Capped: 1` header says the list was cut at the cap.\n\n**Auth:** API key or JWT. Scoped keys need `revshare:read`.\n\n**Rate limit:** 10 requests per minute per caller.","responses":{"200":{"description":"The test numbers as CSV, with a header row.","content":{"text/csv":{"schema":{"type":"string","format":"binary"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"revshare:read","x-rate-limit":{"max":10,"window":"minute"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"country","in":"query","required":false,"description":"Country name contains","schema":{"type":"string"}},{"name":"countryCode","in":"query","required":false,"description":"Dial code","schema":{"type":"string"}},{"name":"q","in":"query","required":false,"description":"Number starts with these digits","schema":{"type":"string"}},{"name":"mode","in":"query","required":false,"schema":{"type":"string","enum":["range","all"]}},{"name":"limit","in":"query","required":false,"description":"At most 2000","schema":{"type":"integer"}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/revshare/test-results":{"get":{"operationId":"getRevshareTestResults","tags":["Revenue share numbers"],"summary":"See which ranges your test calls reached","description":"Calls from your own origin prefixes that reached pool numbers in the last day or week, grouped by destination range and country. `prefixes` is a comma-separated list of up to 20 origin prefixes (2 to 7 digits from the country code). Only masked caller digits are stored, so a call logged before 30 Oct 2026 with 5 or 6 digits that could belong to a longer prefix is counted in `likelyCalls`. `trimmed` lists prefixes cut back to 7 digits.\n\n**Auth:** API key or JWT. Scoped keys need `revshare:read`.\n\n**Rate limit:** 30 requests per minute per caller.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"days":{"type":"integer"},"since":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"generatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"prefixes":{"type":"array","items":{"type":"object","properties":{"prefix":{"type":"string"},"iso":{"type":"string","nullable":true},"country":{"type":"string","nullable":true},"network":{"type":"string","nullable":true},"calls":{"type":"integer"},"lastAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true}},"required":["prefix","iso","country","network","calls","lastAt"]}},"totals":{"type":"object","properties":{"calls":{"type":"integer"},"ranges":{"type":"integer"},"countries":{"type":"integer"},"lastCallAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true}},"required":["calls","ranges","countries","lastCallAt"]},"countries":{"type":"array","items":{"type":"object","properties":{"iso":{"type":"string","nullable":true},"country":{"type":"string"},"calls":{"type":"integer"},"ranges":{"type":"integer"},"lastAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["iso","country","calls","ranges","lastAt"]}},"ranges":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"destPrefix":{"type":"string"},"destIso":{"type":"string","nullable":true},"destCountry":{"type":"string","nullable":true},"destNetwork":{"type":"string","nullable":true},"numberType":{"type":"string","enum":["mobile","fixed","premium","special","satellite","toll_free","unknown"]},"calls":{"type":"integer"},"likelyCalls":{"type":"integer"},"lastAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"origins":{"type":"array","items":{"type":"string"}},"destFree":{"type":"integer","nullable":true}},"required":["id","destPrefix","destIso","destCountry","destNetwork","numberType","calls","likelyCalls","lastAt","origins","destFree"]}},"truncated":{"type":"boolean"},"trimmed":{"type":"array","items":{"type":"string"}}},"required":["days","since","generatedAt","prefixes","totals","countries","ranges","truncated","trimmed"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"revshare:read","x-rate-limit":{"max":30,"window":"minute"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"prefixes","in":"query","required":true,"description":"Comma-separated origin prefixes, e.g. 5561,5581","schema":{"type":"string"}},{"name":"days","in":"query","required":false,"description":"Default 7","schema":{"type":"string","enum":["1","7"]}}],"x-px-example":{"path":{},"query":{"prefixes":"<prefixes>"}}}},"/api/v1/revshare/takings/{id}/release":{"post":{"operationId":"postRevshareTakingsByIdRelease","tags":["Revenue share numbers"],"summary":"Release a revenue share number back to the pool","description":"Stops earning on the number and returns it to the pool for anyone to take. Releasing a number already released returns it unchanged.\n\n**Auth:** API key or JWT. Scoped keys need `revshare:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/RevshareTaking"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"revshare:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/revshare/my-numbers":{"get":{"operationId":"getRevshareMyNumbers","tags":["Revenue share numbers"],"summary":"List the revenue share numbers you hold","description":"Active and released numbers with running call, minute and earnings totals.\n\n**Auth:** API key or JWT. Scoped keys need `revshare:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"numberId":{"type":"string","format":"uuid"},"number":{"type":"string"},"country":{"type":"string","nullable":true},"countryCode":{"type":"string","nullable":true},"carrier":{"type":"string","nullable":true},"paymentTerm":{"type":"string","enum":["1_1","7_1","15_15"],"description":"Settlement term: earnings held 1, 7 or 15 days, then requestable any day; sets the rate (88%, 95%, 100%)"},"ratePerMin":{"$ref":"#/components/schemas/Money"},"status":{"type":"string","enum":["active","released"]},"callsCount":{"type":"integer"},"minutesTotal":{"type":"string"},"earningsTotal":{"$ref":"#/components/schemas/Money"},"lastCallAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"ivrConfigId":{"type":"string","format":"uuid","nullable":true},"ivrMode":{"type":"string","enum":["single","split","geo"]},"takenAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"releasedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true}},"required":["id","numberId","number","country","countryCode","carrier","paymentTerm","ratePerMin","status","callsCount","minutesTotal","earningsTotal","lastCallAt","ivrConfigId","ivrMode","takenAt","releasedAt"]}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"revshare:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/revshare/cdrs":{"get":{"operationId":"getRevshareCdrs","tags":["Revenue share numbers"],"summary":"List calls to your revenue share numbers","description":"Newest first. `format=csv` downloads up to 5,000 rows as CSV.\n\n**Auth:** API key or JWT. Scoped keys need `revshare:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"numberId":{"type":"string","format":"uuid"},"fromCarrier":{"type":"string","nullable":true},"toNetwork":{"type":"string","nullable":true},"prefix":{"type":"string"},"callerNumber":{"type":"string","nullable":true,"description":"The full number that called your number; null when no caller ID was presented"},"ivrConfigId":{"type":"string","format":"uuid","nullable":true,"description":"Which of your IVR variants answered, when one did"},"originIso":{"type":"string","nullable":true},"originCountry":{"type":"string","nullable":true},"startedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"durationSec":{"type":"integer"},"ratePerMin":{"$ref":"#/components/schemas/Money"},"earnedAmount":{"$ref":"#/components/schemas/Money"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","numberId","fromCarrier","toNetwork","prefix","callerNumber","ivrConfigId","originIso","originCountry","startedAt","durationSec","ratePerMin","earnedAmount","createdAt"]}},"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"revshare:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"numberId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"from","in":"query","required":false,"description":"ISO date or timestamp","schema":{"type":"string"}},{"name":"to","in":"query","required":false,"schema":{"type":"string"}},{"name":"format","in":"query","required":false,"description":"`csv` returns a CSV download instead of JSON","schema":{"type":"string","enum":["csv"]}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer"}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/revshare/access-log":{"get":{"operationId":"getRevshareAccessLog","tags":["Revenue share numbers"],"summary":"Get the public revenue share call log","description":"Recent calls across the pool, with origin and destination geography for mapping.\n\n**Auth:** API key or JWT. Scoped keys need `revshare:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"fromCarrier":{"type":"string","nullable":true},"toNetwork":{"type":"string","nullable":true},"prefix":{"type":"string"},"country":{"type":"string","nullable":true},"startedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"toIso":{"type":"string","nullable":true},"toLat":{"type":"number","nullable":true},"toLng":{"type":"number","nullable":true},"fromIso":{"type":"string","nullable":true},"fromLat":{"type":"number","nullable":true},"fromLng":{"type":"number","nullable":true},"fromCountry":{"type":"string","nullable":true}},"required":["fromCarrier","toNetwork","prefix","country","startedAt","toIso","toLat","toLng","fromIso","fromLat","fromLng","fromCountry"],"additionalProperties":true}},"limit":{"type":"integer"},"offset":{"type":"integer"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"revshare:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"country","in":"query","required":false,"schema":{"type":"string"}},{"name":"since","in":"query","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer"}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/revshare/live-access":{"get":{"operationId":"getRevshareLiveAccess","tags":["Revenue share numbers"],"summary":"Get the live access sheet","description":"Every call seen reaching a pool number in the last day (`days=1`) or week (default): origin and destination digits, country, network and number type, with the totals and country pairs the map draws. Masked digits only. Refreshed every 30 seconds.\n\n**Auth:** API key or JWT. Scoped keys need `revshare:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/RevshareLiveAccess"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"revshare:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"string","enum":["1","7"]}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/revshare/live-calls":{"get":{"operationId":"getRevshareLiveCalls","tags":["Revenue share numbers"],"summary":"Get live calls on your revenue numbers","description":"Calls to your own numbers in progress right now, the last 20 that ended, and today's counters (UTC). The caller is shown as a masked prefix only. Times are epoch milliseconds. `switchView.fresh` false means the answered state may lag.\n\n**Auth:** API key or JWT. Scoped keys need `revshare:read`.\n\n**Rate limit:** 60 requests per minute per caller.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"calls":{"type":"array","items":{"type":"object","properties":{"callUuid":{"type":"string"},"takingId":{"type":"string","format":"uuid"},"numberId":{"type":"string","format":"uuid"},"number":{"type":"string"},"numberCountry":{"type":"string","nullable":true},"callerPrefix":{"type":"string"},"originIso":{"type":"string","nullable":true},"originCountry":{"type":"string","nullable":true},"originNetwork":{"type":"string","nullable":true},"delivery":{"type":"object","properties":{"mode":{"type":"string","enum":["greeting","switch"]},"target":{"type":"string","nullable":true},"transport":{"type":"string","enum":["udp","tcp"],"nullable":true},"skipReason":{"type":"string","nullable":true}},"required":["mode","target","transport","skipReason"]},"startedAt":{"type":"integer"},"state":{"type":"string","enum":["ringing","answered"]},"answeredAt":{"type":"integer","nullable":true},"deliveryState":{"type":"string","enum":["greeting","greeting_skipped","ringing_switch","answered_switch"]}},"required":["callUuid","takingId","numberId","number","numberCountry","callerPrefix","originIso","originCountry","originNetwork","delivery","startedAt","state","answeredAt","deliveryState"],"additionalProperties":true}},"ended":{"type":"array","items":{"type":"object","properties":{"callUuid":{"type":"string"},"takingId":{"type":"string","format":"uuid"},"numberId":{"type":"string","format":"uuid"},"number":{"type":"string"},"callerPrefix":{"type":"string"},"startedAt":{"type":"integer"},"endedAt":{"type":"integer"},"durationSec":{"type":"integer","nullable":true},"earned":{"allOf":[{"$ref":"#/components/schemas/Money"}],"nullable":true,"description":"US dollars as a decimal string with exactly 6 decimal places, e.g. \"0.012500\". Do money arithmetic with a decimal type, not floating point."},"deliveryOutcome":{"type":"string","enum":["delivered","fallback","caller_hung_up"],"nullable":true},"endedBy":{"type":"string","enum":["cdr","switch","expired"]}},"required":["callUuid","takingId","numberId","number","callerPrefix","startedAt","endedAt","durationSec","earned","deliveryOutcome","endedBy"],"additionalProperties":true}},"today":{"type":"object","properties":{"calls":{"type":"integer"},"answered":{"type":"integer"},"minutes":{"type":"number"},"earned":{"$ref":"#/components/schemas/Money"},"peakConcurrent":{"type":"integer"}},"required":["calls","answered","minutes","earned","peakConcurrent"]},"now":{"type":"object","properties":{"live":{"type":"integer"},"answered":{"type":"integer"},"ringing":{"type":"integer"}},"required":["live","answered","ringing"]},"switchView":{"type":"object","properties":{"fresh":{"type":"boolean"},"refreshedAt":{"type":"integer"}},"required":["fresh","refreshedAt"]},"serverTime":{"type":"integer"}},"required":["calls","ended","today","now","switchView","serverTime"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"revshare:read","x-rate-limit":{"max":60,"window":"minute"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/revshare/public/live-access":{"get":{"operationId":"getRevsharePublicLiveAccess","tags":["Revenue share numbers"],"summary":"Get the public live access sheet","description":"The live access sheet without sign-in: 5-digit prefixes on both sides, the newest 200 rows (`rowsCapped` says more existed) and opaque row ids. Totals still cover the whole window.\n\n**Auth:** none (public endpoint).\n\n**Rate limit:** 30 requests per minute per caller.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"days":{"type":"integer"},"since":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"generatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"totals":{"type":"object","properties":{"calls":{"type":"integer"},"lastHourCalls":{"type":"integer"},"originCountries":{"type":"integer"},"destinationCountries":{"type":"integer"},"lastCallAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true}},"required":["calls","lastHourCalls","originCountries","destinationCountries","lastCallAt"]},"topOrigins":{"type":"array","items":{"type":"object","properties":{"iso":{"type":"string","nullable":true},"country":{"type":"string"},"calls":{"type":"integer"},"lastAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["iso","country","calls","lastAt"]}},"topDestinations":{"type":"array","items":{"type":"object","properties":{"iso":{"type":"string","nullable":true},"country":{"type":"string"},"calls":{"type":"integer"},"lastAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["iso","country","calls","lastAt"]}},"byType":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","enum":["mobile","fixed","premium","special","satellite","toll_free","unknown"]},"calls":{"type":"integer"}},"required":["type","calls"]}},"pairs":{"type":"array","items":{"type":"object","properties":{"fromIso":{"type":"string","nullable":true},"fromCountry":{"type":"string"},"fromLat":{"type":"number","nullable":true},"fromLng":{"type":"number","nullable":true},"toIso":{"type":"string","nullable":true},"toCountry":{"type":"string"},"toLat":{"type":"number","nullable":true},"toLng":{"type":"number","nullable":true},"calls":{"type":"integer"},"lastHour":{"type":"integer"},"lastAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["fromIso","fromCountry","fromLat","fromLng","toIso","toCountry","toLat","toLng","calls","lastHour","lastAt"]}},"rows":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"startedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"originPrefix":{"type":"string","description":"Leading digits of the caller, never the full number"},"originIso":{"type":"string","nullable":true},"originCountry":{"type":"string","nullable":true},"originNetwork":{"type":"string","nullable":true},"originType":{"type":"string","enum":["mobile","fixed","premium","special","satellite","toll_free","unknown"]},"destPrefix":{"type":"string","description":"Leading digits of the pool number, at least 4 digits hidden"},"destIso":{"type":"string","nullable":true},"destCountry":{"type":"string","nullable":true},"destNetwork":{"type":"string","nullable":true},"numberType":{"type":"string","enum":["mobile","fixed","premium","special","satellite","toll_free","unknown"]},"durationSec":{"type":"integer","nullable":true},"destFree":{"type":"integer","nullable":true,"description":"Numbers starting with destPrefix still free to take"}},"required":["id","startedAt","originPrefix","originIso","originCountry","originNetwork","originType","destPrefix","destIso","destCountry","destNetwork","numberType","durationSec","destFree"]}},"truncated":{"type":"boolean"},"rowsCapped":{"type":"boolean"}},"required":["days","since","generatedAt","totals","topOrigins","topDestinations","byType","pairs","rows","truncated","rowsCapped"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"public","x-rate-limit":{"max":30,"window":"minute"},"security":[],"parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"string","enum":["1","7"]}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/revshare/public/interconnect":{"get":{"operationId":"getRevsharePublicInterconnect","tags":["Revenue share numbers"],"summary":"Get what your switch must allow for call delivery","description":"The addresses our delivered calls come from, signalling port, transports, media range, codecs, DTMF and ring time. The same sheet GET /delivery returns, without sign-in.\n\n**Auth:** none (public endpoint).\n\n**Rate limit:** 60 requests per minute per caller.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/RevshareInterconnect"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"public","x-rate-limit":{"max":60,"window":"minute"},"security":[],"x-px-example":{"path":{},"query":{}}}},"/api/v1/revshare/access-paths":{"get":{"operationId":"getRevshareAccessPaths","tags":["Revenue share numbers"],"summary":"List the carrier paths that reach the pool","description":"**Auth:** API key or JWT. Scoped keys need `revshare:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"fromCarrier":{"type":"string","nullable":true},"toNetwork":{"type":"string","nullable":true},"country":{"type":"string","nullable":true},"countryCode":{"type":"string","nullable":true},"numbers":{"type":"integer"},"toIso":{"type":"string","nullable":true},"toLat":{"type":"number","nullable":true},"toLng":{"type":"number","nullable":true},"fromIso":{"type":"string","nullable":true},"fromLat":{"type":"number","nullable":true},"fromLng":{"type":"number","nullable":true},"fromCountry":{"type":"string","nullable":true}},"required":["fromCarrier","toNetwork","country","countryCode","numbers","toIso","toLat","toLng","fromIso","fromLat","fromLng","fromCountry"],"additionalProperties":true}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"revshare:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"country","in":"query","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer"}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/revshare/rates":{"get":{"operationId":"getRevshareRates","tags":["Revenue share numbers"],"summary":"List revenue share rates by number type","description":"Available count and what you earn per minute at the best payment term. `format=csv` downloads CSV.\n\n**Auth:** API key or JWT. Scoped keys need `revshare:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"groupKey":{"type":"string"},"country":{"type":"string","nullable":true},"countryCode":{"type":"string","nullable":true},"isoCountry":{"type":"string","nullable":true},"lat":{"type":"number","nullable":true},"lng":{"type":"number","nullable":true},"availableCount":{"type":"integer"},"ratePerMin":{"$ref":"#/components/schemas/Money"}},"required":["groupKey","country","countryCode","isoCountry","lat","lng","availableCount","ratePerMin"],"additionalProperties":true}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"revshare:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"country","in":"query","required":false,"schema":{"type":"string"}},{"name":"countryCode","in":"query","required":false,"schema":{"type":"string"}},{"name":"maxRate","in":"query","required":false,"schema":{"type":"number"}},{"name":"format","in":"query","required":false,"description":"`csv` returns a CSV download instead of JSON","schema":{"type":"string","enum":["csv"]}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer"}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/revshare/balance":{"get":{"operationId":"getRevshareBalance","tags":["Revenue share numbers"],"summary":"Get your revenue share balance","description":"`available` = earned minus paid, requested and forfeited.\n\n**Auth:** API key or JWT. Scoped keys need `revshare:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"earned":{"$ref":"#/components/schemas/Money"},"paid":{"$ref":"#/components/schemas/Money"},"requested":{"$ref":"#/components/schemas/Money"},"available":{"$ref":"#/components/schemas/Money"}},"required":["earned","paid","requested","available"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"revshare:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/revshare/schedule":{"get":{"operationId":"getRevshareSchedule","tags":["Revenue share numbers"],"summary":"Get when each payout term next opens","description":"**Auth:** API key or JWT. Scoped keys need `revshare:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"type":"object","properties":{"term":{"type":"string","enum":["1_1","7_1","15_15"],"description":"Settlement term: earnings held 1, 7 or 15 days, then requestable any day; sets the rate (88%, 95%, 100%)"},"label":{"type":"string"},"cadence":{"type":"string"},"nextOpen":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"openNow":{"type":"boolean"}},"required":["term","label","cadence","nextOpen","openNow"]}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"revshare:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/revshare/statement":{"get":{"operationId":"getRevshareStatement","tags":["Revenue share numbers"],"summary":"Get a revenue share earnings statement","description":"Totals by number and by origin carrier for a period. `format=csv` downloads CSV.\n\n**Auth:** API key or JWT. Scoped keys need `revshare:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"period":{"type":"object","properties":{"from":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"to":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true}},"required":["from","to"]},"totals":{"type":"object","properties":{"calls":{"type":"integer"},"minutes":{"type":"number"},"earned":{"$ref":"#/components/schemas/Money"}},"required":["calls","minutes","earned"]},"byNumber":{"type":"array","items":{"type":"object","properties":{"number":{"type":"string"},"country":{"type":"string","nullable":true},"calls":{"type":"integer"},"minutes":{"type":"number"},"earned":{"$ref":"#/components/schemas/Money"}},"required":["number","country","calls","minutes","earned"]}},"byOrigin":{"type":"array","items":{"type":"object","properties":{"fromCarrier":{"type":"string","nullable":true},"calls":{"type":"integer"},"minutes":{"type":"number"},"earned":{"$ref":"#/components/schemas/Money"}},"required":["fromCarrier","calls","minutes","earned"]}}},"required":["period","totals","byNumber","byOrigin"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"revshare:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"from","in":"query","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","required":false,"schema":{"type":"string"}},{"name":"format","in":"query","required":false,"description":"`csv` returns a CSV download instead of JSON","schema":{"type":"string","enum":["csv"]}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/revshare/payouts":{"get":{"operationId":"getRevsharePayouts","tags":["Revenue share numbers"],"summary":"List your revenue share payout requests","description":"**Auth:** API key or JWT. Scoped keys need `revshare:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/RevsharePayout"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"revshare:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/revshare/ivr-configs":{"get":{"operationId":"getRevshareIvrConfigs","tags":["Revenue share numbers"],"summary":"List your IVR configurations","description":"**Auth:** API key or JWT. Scoped keys need `revshare:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/RevshareIvrConfig"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"revshare:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}},"post":{"operationId":"postRevshareIvrConfigs","tags":["Revenue share numbers"],"summary":"Create an IVR configuration","description":"**Auth:** API key or JWT. Scoped keys need `revshare:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/RevshareIvrConfig"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"revshare:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"type":"string","enum":["default_music","upload","tts"]},"takingId":{"type":"string","format":"uuid","nullable":true},"name":{"type":"string","maxLength":120,"nullable":true},"assetPath":{"type":"string","maxLength":1024,"nullable":true},"ttsText":{"type":"string","maxLength":4000,"nullable":true},"ttsVoiceId":{"type":"string","maxLength":120,"nullable":true},"status":{"type":"string","enum":["draft","active"]}},"required":["kind"]}}}},"x-px-example":{"path":{},"query":{},"body":{"kind":"default_music"}}}},"/api/v1/revshare/ivr-configs/{id}":{"patch":{"operationId":"patchRevshareIvrConfigsById","tags":["Revenue share numbers"],"summary":"Update an IVR configuration","description":"**Auth:** API key or JWT. Scoped keys need `revshare:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/RevshareIvrConfig"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"revshare:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"type":"string","enum":["default_music","upload","tts"]},"takingId":{"type":"string","format":"uuid","nullable":true},"name":{"type":"string","maxLength":120,"nullable":true},"assetPath":{"type":"string","maxLength":1024,"nullable":true},"ttsText":{"type":"string","maxLength":4000,"nullable":true},"ttsVoiceId":{"type":"string","maxLength":120,"nullable":true},"status":{"type":"string","enum":["draft","active"]}}}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"kind":"default_music","takingId":"<takingId>"}}},"delete":{"operationId":"deleteRevshareIvrConfigsById","tags":["Revenue share numbers"],"summary":"Delete an IVR configuration","description":"**Auth:** API key or JWT. Scoped keys need `revshare:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/Message"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"revshare:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/revshare/ivr-configs/preview":{"post":{"operationId":"postRevshareIvrConfigsPreview","tags":["Revenue share numbers"],"summary":"Preview text-to-speech audio before saving","description":"**Auth:** API key or JWT. Scoped keys need `revshare:write`.\n\n**Rate limit:** 20 requests per minute per caller.","responses":{"200":{"description":"The spoken text as MP3 audio.","content":{"audio/mpeg":{"schema":{"type":"string","format":"binary"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"revshare:write","x-rate-limit":{"max":20,"window":"minute"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"type":"string"},"ttsText":{"type":"string","minLength":1,"maxLength":600},"ttsVoiceId":{"type":"string","minLength":1}},"required":["ttsText","ttsVoiceId"]}}}},"x-px-example":{"path":{},"query":{},"body":{"ttsText":"<ttsText>","ttsVoiceId":"<ttsVoiceId>"}}}},"/api/v1/revshare/ivr-configs/{id}/generate":{"post":{"operationId":"postRevshareIvrConfigsByIdGenerate","tags":["Revenue share numbers"],"summary":"Generate the audio for a text-to-speech IVR","description":"Renders and stores the audio, and returns it.\n\n**Auth:** API key or JWT. Scoped keys need `revshare:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"The generated audio.","content":{"audio/mpeg":{"schema":{"type":"string","format":"binary"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"revshare:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/revshare/ivr-configs/{id}/preview":{"get":{"operationId":"getRevshareIvrConfigsByIdPreview","tags":["Revenue share numbers"],"summary":"Play an IVR configuration's audio","description":"**Auth:** API key or JWT. Scoped keys need `revshare:read`.","responses":{"200":{"description":"The stored audio, in the media type it was saved with.","content":{"audio/mpeg":{"schema":{"type":"string","format":"binary"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"revshare:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/revshare/ivr-configs/upload":{"post":{"operationId":"postRevshareIvrConfigsUpload","tags":["Revenue share numbers"],"summary":"Upload audio for an IVR","description":"Send a multipart `file` (with optional `takingId` and `name` fields), or JSON with `contentBase64` as below.\n\n**Auth:** API key or JWT. Scoped keys need `revshare:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/RevshareIvrConfig"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"revshare:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"contentBase64":{"type":"string"},"contentType":{"type":"string","maxLength":120,"nullable":true},"takingId":{"type":"string","format":"uuid","nullable":true},"name":{"type":"string","maxLength":120,"nullable":true}}}}}},"x-px-example":{"path":{},"query":{},"body":{"contentBase64":"<contentBase64>","contentType":"<contentType>"}}}},"/api/v1/revshare/takings/{id}":{"patch":{"operationId":"patchRevshareTakingsById","tags":["Revenue share numbers"],"summary":"Attach an IVR to a number you hold","description":"Send `ivrConfigId: null` to fall back to the default music loop.\n\n**Auth:** API key or JWT. Scoped keys need `revshare:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/RevshareTaking"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"revshare:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"ivrConfigId":{"type":"string","format":"uuid","nullable":true}}}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"ivrConfigId":"<ivrConfigId>"}}}},"/api/v1/revshare/takings/{id}/ivr":{"get":{"operationId":"getRevshareTakingsByIdIvr","tags":["Revenue share numbers"],"summary":"Get the IVR set on a number you hold","description":"**Auth:** API key or JWT. Scoped keys need `revshare:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/RevshareIvrSet"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"revshare:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}},"put":{"operationId":"putRevshareTakingsByIdIvr","tags":["Revenue share numbers"],"summary":"Replace the IVR set on a number you hold","description":"`single`: exactly one variant. `split`: two or more, each with a weight. `geo`: one per caller country plus at most one default.\n\n**Auth:** API key or JWT. Scoped keys need `revshare:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/RevshareIvrSet"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"revshare:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"mode":{"type":"string","enum":["single","split","geo"]},"variants":{"type":"array","items":{"type":"object","properties":{"ivrConfigId":{"type":"string","format":"uuid"},"weightPct":{"type":"integer","minimum":1,"maximum":100,"nullable":true},"originIso":{"type":"string","minLength":2,"maxLength":2,"nullable":true},"originCountry":{"type":"string","maxLength":120,"nullable":true},"enabled":{"type":"boolean","nullable":true}},"required":["ivrConfigId"]},"minItems":0}},"required":["mode","variants"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"mode":"single","variants":[{"ivrConfigId":"<ivrConfigId>"}]}}}},"/api/v1/revshare/takings/{id}/ivr-stats":{"get":{"operationId":"getRevshareTakingsByIdIvrStats","tags":["Revenue share numbers"],"summary":"Compare IVR variants on a number you hold","description":"Calls, minutes and earnings per variant and per caller country, with the best-earning variant once two have calls.\n\n**Auth:** API key or JWT. Scoped keys need `revshare:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"period":{"type":"object","properties":{"from":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"to":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true}},"required":["from","to"]},"byVariant":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}},"byCountry":{"type":"array","items":{"type":"object","properties":{"iso":{"type":"string","nullable":true},"country":{"type":"string","nullable":true},"calls":{"type":"integer"},"minutes":{"type":"number"},"earnings":{"type":"number"}},"required":["iso","country","calls","minutes","earnings"]}},"winner":{"type":"string","format":"uuid","nullable":true}},"required":["period","byVariant","byCountry","winner"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"revshare:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"from","in":"query","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","required":false,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/revshare/delivery":{"get":{"operationId":"getRevshareDelivery","tags":["Revenue share numbers"],"summary":"Get how calls to your revenue numbers are delivered","description":"Your account default (`greeting`: answered by your greeting, or `switch`: sent to your own SIP switch with your greeting as the fallback), every per-number override, the addresses our calls come from (allow these on your switch), each number's last delivery outcome, your connectivity test history and the remaining test allowance.\n\n**Auth:** API key or JWT. Scoped keys need `revshare:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"accountDefault":{"$ref":"#/components/schemas/RevshareDeliverySetting"},"overrides":{"type":"array","items":{"type":"object","properties":{"mode":{"type":"string","enum":["greeting","switch","inherit"]},"host":{"type":"string","nullable":true},"port":{"type":"integer"},"transport":{"type":"string","enum":["udp","tcp"]},"prefix":{"type":"string","nullable":true},"numberFormat":{"type":"string","enum":["e164","plus","national"]},"maxChannels":{"type":"integer","nullable":true},"updatedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"takingId":{"type":"string","format":"uuid"}},"required":["mode","host","port","transport","prefix","numberFormat","maxChannels","updatedAt","takingId"]}},"interconnect":{"$ref":"#/components/schemas/RevshareInterconnect"},"enabled":{"type":"boolean"},"status":{"type":"object","additionalProperties":{"type":"object","properties":{},"additionalProperties":true},"description":"Keyed by taking id: last outcome, last 24 hours, override mode"},"tests":{"type":"array","items":{"$ref":"#/components/schemas/RevshareDeliveryTest"}},"allowance":{"$ref":"#/components/schemas/RevshareTestAllowance"}},"required":["accountDefault","overrides","interconnect","enabled","status","tests","allowance"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"revshare:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}},"put":{"operationId":"putRevshareDelivery","tags":["Revenue share numbers"],"summary":"Set how calls to your revenue numbers are delivered (account default)","description":"`mode` `greeting` or `switch`. For `switch`: `host` is the public IPv4 address or hostname of your switch (private, reserved and our own addresses are refused), `port` 5060 or 1024-65535, `transport` udp or tcp, optional `prefix` (digits, * and #), `numberFormat` e164 (no plus, default), plus, or national (country code removed), optional `maxChannels`. If your switch does not answer within 20 seconds or refuses the call, or `maxChannels` is reached, the call is answered by your greeting instead and still earns. Earnings are always measured on our side.\n\n**Auth:** API key or JWT. Scoped keys need `revshare:write`.\n\n**Rate limit:** 30 requests per minute per caller.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/RevshareDeliverySettings"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"revshare:write","x-rate-limit":{"max":30,"window":"minute"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"mode":{"type":"string","enum":["greeting","switch","inherit"]},"host":{"type":"string","maxLength":253,"nullable":true},"port":{"type":"integer","minimum":1,"maximum":65535,"nullable":true},"transport":{"type":"string","enum":["udp","tcp"],"nullable":true},"prefix":{"type":"string","maxLength":20,"pattern":"^[0-9*#]*$","nullable":true},"numberFormat":{"type":"string","enum":["e164","plus","national"],"nullable":true},"maxChannels":{"type":"integer","minimum":1,"maximum":10000,"nullable":true}},"required":["mode"]}}}},"x-px-example":{"path":{},"query":{},"body":{"mode":"greeting"}}}},"/api/v1/revshare/takings/{id}/delivery":{"get":{"operationId":"getRevshareTakingsByIdDelivery","tags":["Revenue share numbers"],"summary":"Get call delivery for one number you hold","description":"The number's own override (`inherit` when it follows the account default), the setting it resolves to, and its recent delivery outcomes.\n\n**Auth:** API key or JWT. Scoped keys need `revshare:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/RevshareTakingDelivery"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"revshare:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}},"put":{"operationId":"putRevshareTakingsByIdDelivery","tags":["Revenue share numbers"],"summary":"Set call delivery for one number you hold","description":"Same fields as the account default. `mode: inherit` removes the override so the number follows the account default.\n\n**Auth:** API key or JWT. Scoped keys need `revshare:write`.\n\n**Rate limit:** 30 requests per minute per caller.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/RevshareTakingDelivery"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"revshare:write","x-rate-limit":{"max":30,"window":"minute"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"mode":{"type":"string","enum":["greeting","switch","inherit"]},"host":{"type":"string","maxLength":253,"nullable":true},"port":{"type":"integer","minimum":1,"maximum":65535,"nullable":true},"transport":{"type":"string","enum":["udp","tcp"],"nullable":true},"prefix":{"type":"string","maxLength":20,"pattern":"^[0-9*#]*$","nullable":true},"numberFormat":{"type":"string","enum":["e164","plus","national"],"nullable":true},"maxChannels":{"type":"integer","minimum":1,"maximum":10000,"nullable":true}},"required":["mode"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"mode":"greeting"}}}},"/api/v1/revshare/delivery/tests":{"get":{"operationId":"getRevshareDeliveryTests","tags":["Revenue share numbers"],"summary":"List your connectivity tests","description":"The last 20 tests, newest first, and the remaining allowance (10 a day, 300 a month, UTC).\n\n**Auth:** API key or JWT. Scoped keys need `revshare:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"tests":{"type":"array","items":{"$ref":"#/components/schemas/RevshareDeliveryTest"}},"allowance":{"$ref":"#/components/schemas/RevshareTestAllowance"}},"required":["tests","allowance"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"revshare:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/revshare/delivery/test":{"post":{"operationId":"postRevshareDeliveryTest","tags":["Revenue share numbers"],"summary":"Send a connectivity test call to your switch","description":"Calls your configured switch from each of our addresses, exactly as a delivered call is addressed, holds an answered call for one second and then ends it (or stops after 20 seconds without an answer). Reports whether it was answered, the final SIP code, post-dial delay, time to answer and which of our addresses it came from. Not billed and not credited. Omit `testNumber` to dial one of your own numbers. 10 tests a day and 300 a month per account; one at a time.\n\n**Auth:** API key or JWT. Scoped keys need `revshare:write`.\n\n**Rate limit:** 4 requests per minute per caller.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"test":{"$ref":"#/components/schemas/RevshareDeliveryTest"},"allowance":{"$ref":"#/components/schemas/RevshareTestAllowance"}},"required":["test","allowance"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"revshare:write","x-rate-limit":{"max":4,"window":"minute"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"takingId":{"type":"string","format":"uuid","nullable":true},"testNumber":{"type":"string","pattern":"^\\+?[0-9]{6,16}$","nullable":true}}}}}},"x-px-example":{"path":{},"query":{},"body":{"takingId":"<takingId>","testNumber":"+447700900123"}}}},"/api/v1/dids/catalog":{"get":{"operationId":"getDidsCatalog","tags":["Phone numbers"],"summary":"Browse the number catalogue","description":"Number groups by country, city and type, with the price of each SKU. While the number store is switched off this answers 200 with `data: { disabled: true, comingSoon: true, message }`.\n\n**Auth:** API key or JWT. Scoped keys need `numbers:read`.","responses":{"200":{"description":"One page of number groups. Note: `groups`, `total` and `page` sit at the TOP level beside `success`, not under `data`.","content":{"application/json":{"schema":{"type":"object","required":["success","success","groups","total","page"],"properties":{"success":{"type":"boolean","enum":[true]},"groups":{"type":"array","items":{"$ref":"#/components/schemas/DidCatalogGroup"}},"total":{"type":"integer","nullable":true},"page":{"type":"integer"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"numbers:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"countryId","in":"query","required":false,"description":"From GET .../catalog/countries","schema":{"type":"string","maxLength":64}},{"name":"typeId","in":"query","required":false,"description":"From GET .../catalog/types","schema":{"type":"string","maxLength":64}},{"name":"search","in":"query","required":false,"description":"Text match over country, city, area prefix and type; digits also match the start of the full dialling prefix (\"4420\" finds London). Spans the whole catalogue once it is indexed, otherwise the fetched page","schema":{"type":"string","maxLength":120}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200}},{"name":"sort","in":"query","required":false,"description":"Order by the cheapest monthly price, setup price or location. Omitted: the catalogue order","schema":{"type":"string","enum":["monthly_asc","monthly_desc","setup_asc","location_asc"]}},{"name":"maxMonthly","in":"query","required":false,"description":"Only groups whose cheapest monthly price is at most this, in USD","schema":{"type":"number","minimum":0}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/dids/catalog/countries":{"get":{"operationId":"getDidsCatalogCountries","tags":["Phone numbers"],"summary":"List countries with numbers for sale","description":"While the number store is switched off this answers 200 with `data: { disabled: true, comingSoon: true, message }`.\n\n**Auth:** API key or JWT. Scoped keys need `numbers:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/DidCatalogCountry"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"numbers:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/dids/catalog/types":{"get":{"operationId":"getDidsCatalogTypes","tags":["Phone numbers"],"summary":"List number types for sale","description":"While the number store is switched off this answers 200 with `data: { disabled: true, comingSoon: true, message }`.\n\n**Auth:** API key or JWT. Scoped keys need `numbers:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/DidCatalogType"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"numbers:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/dids/buy":{"post":{"operationId":"postDidsBuy","tags":["Phone numbers"],"summary":"Buy a phone number","description":"Charges the setup price plus the first month to your own platform balance and orders the number. When `subAccountId` names one of your customers, the number is held for them but your balance still pays, now and at every renewal; a customer's balance or credit line never does, and a purchase your balance does not cover is refused (`400`). It starts `pending`; `number` is null until provisioning completes. Requires a verified identity where KYC is enforced.\n\n**Auth:** API key or JWT. Scoped keys need `numbers:write`.\n\n**Idempotency:** send an `X-Idempotency-Key` header to make retries safe; a replay within 24 hours returns the original response.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/Did"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"numbers:write","x-error-codes":["KYC_REQUIRED"],"x-idempotent":true,"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"X-Idempotency-Key","in":"header","required":false,"description":"Any unique string (a UUID is ideal). Replays within 24 hours return the first response instead of acting twice.","schema":{"type":"string","maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"skuId":{"type":"string","minLength":1,"maxLength":64},"groupId":{"type":"string","minLength":1,"maxLength":64},"countryId":{"type":"string","maxLength":64},"country":{"type":"string","maxLength":120},"city":{"type":"string","maxLength":120,"nullable":true},"areaPrefix":{"type":"string","maxLength":16,"nullable":true},"didType":{"type":"string","maxLength":40,"nullable":true},"subAccountId":{"type":"string","format":"uuid","description":"Buy the number for one of your sub-accounts: the number is held for them, and your own platform balance pays for it (setup, first month and every renewal), never the sub-account's balance or credit"}},"required":["skuId","groupId"]}}}},"x-px-example":{"path":{},"query":{},"body":{"skuId":"<skuId>","groupId":"<groupId>"}},"x-px-billable":{"kind":"money","note":"Buys a phone number, charged to your balance."}}},"/api/v1/dids/mine":{"get":{"operationId":"getDidsMine","tags":["Phone numbers"],"summary":"List your phone numbers","description":"While the number store is switched off this answers 200 with `data: { disabled: true, comingSoon: true, message }`.\n\n**Auth:** API key or JWT. Scoped keys need `numbers:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/Did"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"numbers:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/dids/listing-request":{"get":{"operationId":"getDidsListingRequest","tags":["Phone numbers"],"summary":"Get your request to list numbers on the marketplace","description":"Your latest request, plus a profile prefill for the form. Works while the number store is off.\n\n**Auth:** API key or JWT. Scoped keys need `numbers:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/DidListingRequestView"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"numbers:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}},"post":{"operationId":"postDidsListingRequest","tags":["Phone numbers"],"summary":"Ask to list your numbers on the marketplace","description":"Our team reviews the request and lists the numbers by hand. One open request at a time (409 CONFLICT otherwise). A validation failure here answers 400 with `error.field` naming the first bad field instead of a `details` array.\n\n**Auth:** API key or JWT. Scoped keys need `numbers:write`.\n\n**Rate limit:** 5 requests per 10 minutes per caller.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string"},"submittedAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"}},"required":["id","status","submittedAt"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"numbers:write","x-rate-limit":{"max":5,"window":"10 minutes"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"companyName":{"type":"string","maxLength":255,"nullable":true},"contactName":{"type":"string","minLength":2,"maxLength":255},"contactEmail":{"type":"string","format":"email","maxLength":255,"nullable":true},"contactPhone":{"type":"string","maxLength":40,"nullable":true},"selectedDidIds":{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":500,"description":"Numbers from your portfolio to list"},"didCount":{"type":"integer","nullable":true},"countries":{"type":"string","maxLength":255,"nullable":true},"numberTypes":{"type":"string","maxLength":255,"nullable":true},"monthlyVolume":{"type":"string","maxLength":255,"nullable":true},"targetPrice":{"type":"string","maxLength":2000,"nullable":true},"notes":{"type":"string","maxLength":4000,"nullable":true}},"required":["contactName"]}}}},"x-px-example":{"path":{},"query":{},"body":{"contactName":"<contactName>"}}}},"/api/v1/dids/cli-eligible":{"get":{"operationId":"getDidsCliEligible","tags":["Phone numbers"],"summary":"List your numbers usable as outbound caller IDs","description":"Active, provisioned numbers you own.\n\n**Auth:** API key or JWT. Scoped keys need `numbers:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/DidCliEligible"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"numbers:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/dids/to-cli-set":{"post":{"operationId":"postDidsToCliSet","tags":["Phone numbers"],"summary":"Add your numbers to a dialer caller-ID set","description":"Adds the chosen (or all) active numbers so they rotate as caller IDs on voice campaigns.\n\n**Auth:** API key or JWT. Scoped keys need `numbers:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"inserted":{"type":"integer"},"skipped":{"type":"integer"},"rejects":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"reason":{"type":"string"}},"required":["value","reason"]}}},"required":["inserted","skipped","rejects"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"numbers:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"setId":{"type":"string","format":"uuid","description":"One of your dialer caller-ID sets"},"didIds":{"anyOf":[{"type":"array","items":{"type":"string","format":"uuid"}},{"type":"string","enum":["all"]}],"description":"Omit or \"all\" for every active number"}},"required":["setId"]}}}},"x-px-example":{"path":{},"query":{},"body":{"setId":"<setId>"}}}},"/api/v1/dids/{id}":{"get":{"operationId":"getDidsById","tags":["Phone numbers"],"summary":"Get one of your phone numbers","description":"**Auth:** API key or JWT. Scoped keys need `numbers:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/Did"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"numbers:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/dids/{id}/routing":{"patch":{"operationId":"patchDidsByIdRouting","tags":["Phone numbers"],"summary":"Point a number at one destination (and an optional backup)","description":"The simple form of call routing: a primary and an optional failover backup. Hosted softphone lines and any extra destinations are left alone. Use PUT for the full call flow.\n\n**Auth:** API key or JWT. Scoped keys need `numbers:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/Did"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"numbers:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"mode":{"type":"string","enum":["sip","forward"]},"target":{"type":"string","minLength":1,"maxLength":255,"description":"host[:port] for sip, E.164 for forward"},"backupMode":{"type":"string","enum":["sip","forward"],"nullable":true,"description":"Defaults to `mode`"},"backupTarget":{"type":"string","maxLength":255,"nullable":true,"description":"null or \"\" clears the backup; omit to keep it"}},"required":["mode","target"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"mode":"sip","target":"<target>"}}},"get":{"operationId":"getDidsByIdRouting","tags":["Phone numbers"],"summary":"Get a number's call flow","description":"Ring strategy and ordered destinations. Hosted line passwords are never included.\n\n**Auth:** API key or JWT. Scoped keys need `numbers:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/DidCallFlow"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"numbers:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}},"put":{"operationId":"putDidsByIdRouting","tags":["Phone numbers"],"summary":"Replace a number's call flow","description":"Full replace: an endpoint sent with an id is kept or updated, one without an id is created, and any existing endpoint you leave out is deleted (hosted lines included, so send them back by id to keep them).\n\n**Auth:** API key or JWT. Scoped keys need `numbers:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/DidCallFlow"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"numbers:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"strategy":{"type":"string","enum":["failover","simultaneous"]},"timeoutSec":{"type":"integer","minimum":5,"maximum":600},"endpoints":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Send an existing id to keep or update it; omit to create"},"kind":{"type":"string","enum":["sip","forward","hosted"]},"target":{"type":"string","maxLength":255,"nullable":true,"description":"Required for sip and forward; ignored for hosted"},"label":{"type":"string","maxLength":120,"nullable":true},"priority":{"type":"integer","minimum":1,"maximum":999},"enabled":{"type":"boolean"}},"required":["kind"]},"maxItems":25}},"required":["endpoints"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"endpoints":[{"kind":"sip"}]}}}},"/api/v1/dids/{id}/sip-lines":{"get":{"operationId":"getDidsByIdSipLines","tags":["Phone numbers"],"summary":"List a number's softphone lines","description":"Passwords are not included; use reveal.\n\n**Auth:** API key or JWT. Scoped keys need `numbers:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/DidSipLine"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"numbers:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}},"post":{"operationId":"postDidsByIdSipLines","tags":["Phone numbers"],"summary":"Create a softphone line on a number","description":"Returns the full login, password included, once.\n\n**Auth:** API key or JWT. Scoped keys need `numbers:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/DidSipLineLogin"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"numbers:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string","maxLength":120,"nullable":true}}}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"label":"Acme"}}}},"/api/v1/dids/{id}/sip-lines/{lineId}/reveal":{"post":{"operationId":"postDidsByIdSipLinesByLineIdReveal","tags":["Phone numbers"],"summary":"Reveal a softphone line's login","description":"**Auth:** API key or JWT. Scoped keys need `numbers:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/DidSipLineLogin"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"numbers:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"lineId","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>","lineId":"<lineId>"},"query":{}}}},"/api/v1/dids/{id}/sip-lines/{lineId}":{"delete":{"operationId":"deleteDidsByIdSipLinesByLineId","tags":["Phone numbers"],"summary":"Delete a softphone line","description":"**Auth:** API key or JWT. Scoped keys need `numbers:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"deleted":{"type":"boolean"}},"required":["id","deleted"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"numbers:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"lineId","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>","lineId":"<lineId>"},"query":{}}}},"/api/v1/dids/{id}/auto-renew":{"patch":{"operationId":"patchDidsByIdAutoRenew","tags":["Phone numbers"],"summary":"Turn monthly auto-renew on or off","description":"With auto-renew off, the number is released at its next renewal date instead of being charged.\n\n**Auth:** API key or JWT. Scoped keys need `numbers:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/Did"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"numbers:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean"}},"required":["enabled"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"enabled":true}}}},"/api/v1/dids/{id}/call-capacity":{"get":{"operationId":"getDidsByIdCallCapacity","tags":["Phone numbers"],"summary":"GET /api/v1/dids/{id}/call-capacity","description":"**Auth:** API key or JWT. Scoped keys need `numbers:read`.","responses":{"200":{"description":" Response shape not documented yet: the standard `{ \"success\": true, \"data\": ... }` envelope."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"numbers:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}},"put":{"operationId":"putDidsByIdCallCapacity","tags":["Phone numbers"],"summary":"PUT /api/v1/dids/{id}/call-capacity","description":"**Auth:** API key or JWT. Scoped keys need `numbers:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":" Response shape not documented yet: the standard `{ \"success\": true, \"data\": ... }` envelope."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"numbers:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/dids/{id}/cdrs":{"get":{"operationId":"getDidsByIdCdrs","tags":["Phone numbers"],"summary":"List inbound calls to a number","description":"Recent inbound calls, newest first, with a calls and minutes total.\n\n**Auth:** API key or JWT. Scoped keys need `numbers:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/DidCalls"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"numbers:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Newest first; default 200","schema":{"type":"integer","minimum":1,"maximum":500}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/dids/{id}/ai-agent":{"get":{"operationId":"getDidsByIdAiAgent","tags":["Phone numbers"],"summary":"See which AI voice agent answers a number","description":"Returns the agent pointed at this number (or null), whether inbound AI answering is switched on for the platform, and the per-minute AI voice rate.\n\n**Auth:** API key or JWT. Scoped keys need `numbers:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/DidAiAgent"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"numbers:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}},"put":{"operationId":"putDidsByIdAiAgent","tags":["Phone numbers"],"summary":"Point a number at an AI voice agent","description":"Send `{ \"agentId\": \"<your agent id>\" }` and inbound calls to the number are answered by that agent instead of ringing the number's call flow; send `{ \"agentId\": null }` to go back to the call flow, which is kept untouched meanwhile. Billed per second at the AI voice per-minute rate to the number's owner, on top of the number's monthly price. Each call is capped at the agent's maximum call length and at what your balance covers; when the agent is disabled or your balance covers less than 30 seconds, the number rings its call flow as usual. The agent must belong to your account.\n\n**Auth:** API key or JWT. Scoped keys need `numbers:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/DidAiAgent"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"numbers:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"agentId":{"type":"string","format":"uuid","nullable":true,"description":"One of your AI agents (GET /ai-agents), or null to clear"}},"required":["agentId"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"agentId":"<agentId>"}}}},"/api/v1/dids/{id}/features":{"get":{"operationId":"getDidsByIdFeatures","tags":["Phone numbers"],"summary":"Get a number's voicemail, recording, IVR and schedule settings","description":"A number with nothing configured rings its call flow as normal.\n\n**Auth:** API key or JWT. Scoped keys need `numbers:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/DidFeatures"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"numbers:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/dids/{id}/features/voicemail":{"put":{"operationId":"putDidsByIdFeaturesVoicemail","tags":["Phone numbers"],"summary":"Configure voicemail on a number","description":"**Auth:** API key or JWT. Scoped keys need `numbers:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/DidFeatures"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"numbers:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean"},"mode":{"type":"string","enum":["on_no_answer","always"]},"greetingAssetId":{"type":"string","format":"uuid","nullable":true},"transcribe":{"type":"boolean"}}}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"enabled":true,"mode":"on_no_answer"}}}},"/api/v1/dids/{id}/features/recording":{"put":{"operationId":"putDidsByIdFeaturesRecording","tags":["Phone numbers"],"summary":"Configure call recording on a number","description":"**Auth:** API key or JWT. Scoped keys need `numbers:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/DidFeatures"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"numbers:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean"},"announce":{"type":"boolean"},"retentionDays":{"type":"integer","minimum":0,"maximum":3650}}}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"enabled":true,"announce":true}}}},"/api/v1/dids/{id}/features/ivr":{"put":{"operationId":"putDidsByIdFeaturesIvr","tags":["Phone numbers"],"summary":"Configure the IVR menu on a number","description":"**Auth:** API key or JWT. Scoped keys need `numbers:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/DidFeatures"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"numbers:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean"},"greetingAssetId":{"type":"string","format":"uuid","nullable":true},"timeoutSec":{"type":"integer","minimum":1,"maximum":30},"maxRetries":{"type":"integer","minimum":1,"maximum":5},"options":{"type":"array","items":{"type":"object","properties":{"digit":{"type":"string","minLength":1,"maxLength":1,"description":"0-9, * or #"},"action":{"type":"string","enum":["endpoint","voicemail","hangup"]},"endpointId":{"type":"string","format":"uuid","nullable":true},"label":{"type":"string","maxLength":120,"nullable":true}},"required":["digit","action"]},"maxItems":12,"description":"Replaces the whole menu when sent"}}}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"enabled":true,"greetingAssetId":"<greetingAssetId>"}}}},"/api/v1/dids/{id}/features/schedule":{"put":{"operationId":"putDidsByIdFeaturesSchedule","tags":["Phone numbers"],"summary":"Configure business-hours routing on a number","description":"**Auth:** API key or JWT. Scoped keys need `numbers:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/DidFeatures"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"numbers:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean"},"timezone":{"type":"string","maxLength":64,"description":"IANA zone, e.g. Europe/London"},"schedule":{"type":"object","required":["sun","mon","tue","wed","thu","fri","sat"],"properties":{"sun":{"type":"array","items":{"type":"object","properties":{"open":{"type":"string","maxLength":5,"description":"HH:MM"},"close":{"type":"string","maxLength":5,"description":"HH:MM"}},"required":["open","close"]}},"mon":{"type":"array","items":{"type":"object","properties":{"open":{"type":"string","maxLength":5,"description":"HH:MM"},"close":{"type":"string","maxLength":5,"description":"HH:MM"}},"required":["open","close"]}},"tue":{"type":"array","items":{"type":"object","properties":{"open":{"type":"string","maxLength":5,"description":"HH:MM"},"close":{"type":"string","maxLength":5,"description":"HH:MM"}},"required":["open","close"]}},"wed":{"type":"array","items":{"type":"object","properties":{"open":{"type":"string","maxLength":5,"description":"HH:MM"},"close":{"type":"string","maxLength":5,"description":"HH:MM"}},"required":["open","close"]}},"thu":{"type":"array","items":{"type":"object","properties":{"open":{"type":"string","maxLength":5,"description":"HH:MM"},"close":{"type":"string","maxLength":5,"description":"HH:MM"}},"required":["open","close"]}},"fri":{"type":"array","items":{"type":"object","properties":{"open":{"type":"string","maxLength":5,"description":"HH:MM"},"close":{"type":"string","maxLength":5,"description":"HH:MM"}},"required":["open","close"]}},"sat":{"type":"array","items":{"type":"object","properties":{"open":{"type":"string","maxLength":5,"description":"HH:MM"},"close":{"type":"string","maxLength":5,"description":"HH:MM"}},"required":["open","close"]}}}},"holidays":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string","maxLength":10,"description":"YYYY-MM-DD"},"name":{"type":"string","maxLength":120}},"required":["date"]}},"outsideHoursAction":{"type":"string","enum":["voicemail","endpoints","hangup"]},"closedEndpoints":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","enum":["sip","forward"]},"target":{"type":"string","minLength":1,"maxLength":255},"label":{"type":"string","maxLength":120,"nullable":true},"priority":{"type":"integer","minimum":1,"maximum":999},"enabled":{"type":"boolean"}},"required":["kind","target"]},"maxItems":25}}}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"enabled":true,"timezone":"<timezone>"}}}},"/api/v1/dids/{id}/greetings":{"get":{"operationId":"getDidsByIdGreetings","tags":["Phone numbers"],"summary":"List a number's uploaded greetings","description":"**Auth:** API key or JWT. Scoped keys need `numbers:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/DidGreeting"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"numbers:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}},"post":{"operationId":"postDidsByIdGreetings","tags":["Phone numbers"],"summary":"Upload a voicemail or IVR greeting","description":"WAV or MP3, up to 8 MB. Send multipart with a `file` part (and `kind` as a field or query parameter), or JSON with `contentBase64`.\n\n**Auth:** API key or JWT. Scoped keys need `numbers:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/DidGreeting"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"numbers:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"type":"string","enum":["voicemail_greeting","ivr_greeting"]},"name":{"type":"string","maxLength":120,"nullable":true},"contentBase64":{"type":"string","description":"WAV or MP3, base64, up to 8 MB. Or send multipart with a `file` part"}},"required":["kind"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"kind":"voicemail_greeting"}}}},"/api/v1/dids/{id}/greetings/{assetId}/audio":{"get":{"operationId":"getDidsByIdGreetingsByAssetIdAudio","tags":["Phone numbers"],"summary":"Download a greeting's audio","description":"**Auth:** API key or JWT. Scoped keys need `numbers:read`.","responses":{"200":{"description":"The greeting audio bytes (WAV or MP3; the Content-Type says which).","content":{"audio/*":{"schema":{"type":"string","format":"binary"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"numbers:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"assetId","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>","assetId":"<assetId>"},"query":{}}}},"/api/v1/dids/{id}/greetings/{assetId}":{"delete":{"operationId":"deleteDidsByIdGreetingsByAssetId","tags":["Phone numbers"],"summary":"Delete a greeting","description":"**Auth:** API key or JWT. Scoped keys need `numbers:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"deleted":{"type":"boolean"}},"required":["id","deleted"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"numbers:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"assetId","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>","assetId":"<assetId>"},"query":{}}}},"/api/v1/dids/{id}/recordings":{"get":{"operationId":"getDidsByIdRecordings","tags":["Phone numbers"],"summary":"List call recordings on a number","description":"**Auth:** API key or JWT. Scoped keys need `numbers:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/DidRecording"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"numbers:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Newest first; default 200","schema":{"type":"integer","minimum":1,"maximum":500}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/dids/{id}/recordings/{recId}/audio":{"get":{"operationId":"getDidsByIdRecordingsByRecIdAudio","tags":["Phone numbers"],"summary":"Download a call recording","description":"**Auth:** API key or JWT. Scoped keys need `numbers:read`.","responses":{"200":{"description":"The recording audio bytes (WAV or MP3; the Content-Type says which).","content":{"audio/*":{"schema":{"type":"string","format":"binary"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"numbers:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"recId","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>","recId":"<recId>"},"query":{}}}},"/api/v1/dids/{id}/recordings/{recId}":{"delete":{"operationId":"deleteDidsByIdRecordingsByRecId","tags":["Phone numbers"],"summary":"Delete a call recording","description":"**Auth:** API key or JWT. Scoped keys need `numbers:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"deleted":{"type":"boolean"}},"required":["id","deleted"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"numbers:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"recId","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>","recId":"<recId>"},"query":{}}}},"/api/v1/dids/{id}/voicemails":{"get":{"operationId":"getDidsByIdVoicemails","tags":["Phone numbers"],"summary":"List voicemails on a number","description":"**Auth:** API key or JWT. Scoped keys need `numbers:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/DidRecording"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"numbers:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Newest first; default 200","schema":{"type":"integer","minimum":1,"maximum":500}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/dids/{id}/voicemails/{recId}/audio":{"get":{"operationId":"getDidsByIdVoicemailsByRecIdAudio","tags":["Phone numbers"],"summary":"Download a voicemail","description":"**Auth:** API key or JWT. Scoped keys need `numbers:read`.","responses":{"200":{"description":"The voicemail audio bytes (WAV or MP3; the Content-Type says which).","content":{"audio/*":{"schema":{"type":"string","format":"binary"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"numbers:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"recId","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>","recId":"<recId>"},"query":{}}}},"/api/v1/dids/{id}/voicemails/{recId}/heard":{"post":{"operationId":"postDidsByIdVoicemailsByRecIdHeard","tags":["Phone numbers"],"summary":"Mark a voicemail heard or unheard","description":"**Auth:** API key or JWT. Scoped keys need `numbers:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"heard":{"type":"boolean"}},"required":["id","heard"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"numbers:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"recId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"heard":{"type":"boolean","description":"Default true"}}}}}},"x-px-example":{"path":{"id":"<id>","recId":"<recId>"},"query":{},"body":{"heard":true}}}},"/api/v1/dids/{id}/voicemails/{recId}":{"delete":{"operationId":"deleteDidsByIdVoicemailsByRecId","tags":["Phone numbers"],"summary":"Delete a voicemail","description":"**Auth:** API key or JWT. Scoped keys need `numbers:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"deleted":{"type":"boolean"}},"required":["id","deleted"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"numbers:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"recId","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>","recId":"<recId>"},"query":{}}}},"/api/v1/dids/{id}/release":{"post":{"operationId":"postDidsByIdRelease","tags":["Phone numbers"],"summary":"Release a phone number","description":"Cancels the number and stops its monthly charge. Irreversible: the number goes back to the carrier.\n\n**Auth:** API key or JWT. Scoped keys need `numbers:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/Did"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"numbers:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/dids/{id}/sms-settings":{"get":{"operationId":"getDidsByIdSmsSettings","tags":["Phone numbers"],"summary":"Get a number's SMS settings","description":"While SMS on numbers is switched off this answers 200 with `data: { disabled: true, comingSoon: true, message }`.\n\n**Auth:** API key or JWT. Scoped keys need `numbers:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/DidSmsSettings"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"numbers:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}},"put":{"operationId":"putDidsByIdSmsSettings","tags":["Phone numbers"],"summary":"Update a number's SMS settings","description":"**Auth:** API key or JWT. Scoped keys need `numbers:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/DidSmsSettings"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"numbers:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"smsEnabled":{"type":"boolean"},"forwardWebhookUrl":{"type":"string","maxLength":2048,"nullable":true,"description":"https only; null or \"\" clears it"},"notifyEmail":{"type":"string","maxLength":255,"nullable":true,"description":"null or \"\" clears it"}}}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"smsEnabled":true,"forwardWebhookUrl":"<forwardWebhookUrl>"}}}},"/api/v1/dids/{id}/messages/conversations":{"get":{"operationId":"getDidsByIdMessagesConversations","tags":["Phone numbers"],"summary":"List SMS conversations on a number","description":"One row per other party, newest activity first, with unread counts.\n\n**Auth:** API key or JWT. Scoped keys need `numbers:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/DidConversation"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"numbers:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/dids/{id}/messages":{"get":{"operationId":"getDidsByIdMessages","tags":["Phone numbers"],"summary":"List SMS messages on a number","description":"Newest first. Page older with `before` set to the previous `nextBefore`.\n\n**Auth:** API key or JWT. Scoped keys need `numbers:read`.","responses":{"200":{"description":"A page of messages. Note: `messages` and `nextBefore` sit at the TOP level beside `success`, not under `data`.","content":{"application/json":{"schema":{"type":"object","required":["success","success","messages","nextBefore"],"properties":{"success":{"type":"boolean","enum":[true]},"messages":{"type":"array","items":{"$ref":"#/components/schemas/DidMessage"}},"nextBefore":{"type":"string","nullable":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"numbers:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"peer","in":"query","required":false,"description":"One conversation; omit for the number's whole log","schema":{"type":"string"}},{"name":"before","in":"query","required":false,"description":"ISO timestamp: page older than this (use `nextBefore`)","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Default 50","schema":{"type":"integer","minimum":1,"maximum":200}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}},"post":{"operationId":"postDidsByIdMessages","tags":["Phone numbers"],"summary":"Send an SMS from one of your numbers","description":"Charges per segment, then hands the message to the carrier. A hard send failure refunds the charge and marks the message failed.\n\n**Auth:** API key or JWT. Scoped keys need `numbers:write`.\n\n**Idempotency:** send an `X-Idempotency-Key` header to make retries safe; a replay within 24 hours returns the original response.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"direction":{"type":"string","enum":["in","out"]},"from":{"type":"string"},"to":{"type":"string"},"peer":{"type":"string","description":"The other party, digits only; the conversation key"},"body":{"type":"string"},"segments":{"type":"integer"},"status":{"type":"string","enum":["received","queued","sent","delivered","failed"]},"error":{"type":"string","nullable":true},"providerMessageId":{"type":"string","nullable":true,"description":"Upstream carrier message id"},"readAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)","nullable":true},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"cost":{"allOf":[{"$ref":"#/components/schemas/Money"}],"description":"What you were charged; 0.000000 when failed and refunded"}},"required":["id","direction","from","to","peer","body","segments","status","error","providerMessageId","readAt","createdAt","cost"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"numbers:write","x-idempotent":true,"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"X-Idempotency-Key","in":"header","required":false,"description":"Any unique string (a UUID is ideal). Replays within 24 hours return the first response instead of acting twice.","schema":{"type":"string","maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"to":{"type":"string","minLength":3,"maxLength":32},"body":{"type":"string","minLength":1,"maxLength":1600},"idempotencyKey":{"type":"string","minLength":1,"maxLength":80,"nullable":true,"description":"A retry with the same key returns the original message"}},"required":["to","body"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"to":"+447700900123","body":"Hello from Acme"}},"x-px-billable":{"kind":"traffic","note":"Sends a real SMS from your number, billed to your balance."}}},"/api/v1/dids/{id}/messages/read":{"post":{"operationId":"postDidsByIdMessagesRead","tags":["Phone numbers"],"summary":"Mark an SMS conversation read","description":"**Auth:** API key or JWT. Scoped keys need `numbers:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"updated":{"type":"integer"}},"required":["updated"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"numbers:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"peer":{"type":"string","minLength":1,"maxLength":32}},"required":["peer"]}}}},"x-px-example":{"path":{"id":"<id>"},"query":{},"body":{"peer":"<peer>"}}}},"/api/v1/dids/search":{"get":{"operationId":"getDidsSearch","tags":["Phone numbers"],"summary":"Search the catalogue by digit pattern or vanity run","description":"Scans catalogue pages for groups whose dialing prefix matches. While the number store is switched off this answers 200 with `data: { disabled: true, comingSoon: true, message }`.\n\n**Auth:** API key or JWT. Scoped keys need `numbers:read`.","responses":{"200":{"description":"Matching groups under `data`, like every other endpoint. The same `hits`, `scannedPages` and `truncated` are also repeated at the top level beside `success` for clients written before `data` was added; that copy is deprecated, read `data`.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"hits":{"type":"array","items":{"type":"object","properties":{"groupId":{"type":"string","description":"Pass to POST /dids/buy with a skuId"},"country":{"type":"string"},"countryId":{"type":"string","description":"Catalogue country id (filter value), not an ISO code"},"countryPrefix":{"type":"string"},"city":{"type":"string","nullable":true},"areaPrefix":{"type":"string","nullable":true},"typeId":{"type":"string","nullable":true},"typeName":{"type":"string","nullable":true,"description":"Local, National, Mobile, Toll-free..."},"skus":{"type":"array","items":{"$ref":"#/components/schemas/DidCatalogSku"}},"dialingPrefix":{"type":"string","description":"Country prefix plus area prefix"},"vanity":{"type":"boolean"}},"required":["groupId","country","countryId","countryPrefix","city","areaPrefix","typeId","typeName","skus","dialingPrefix","vanity"]}},"scannedPages":{"type":"integer"},"truncated":{"type":"boolean","description":"True when the scan budget ran out before the end of the catalogue"}},"required":["hits","scannedPages","truncated"]},"hits":{"type":"array","items":{"type":"object","properties":{"groupId":{"type":"string","description":"Pass to POST /dids/buy with a skuId"},"country":{"type":"string"},"countryId":{"type":"string","description":"Catalogue country id (filter value), not an ISO code"},"countryPrefix":{"type":"string"},"city":{"type":"string","nullable":true},"areaPrefix":{"type":"string","nullable":true},"typeId":{"type":"string","nullable":true},"typeName":{"type":"string","nullable":true,"description":"Local, National, Mobile, Toll-free..."},"skus":{"type":"array","items":{"$ref":"#/components/schemas/DidCatalogSku"}},"dialingPrefix":{"type":"string","description":"Country prefix plus area prefix"},"vanity":{"type":"boolean"}},"required":["groupId","country","countryId","countryPrefix","city","areaPrefix","typeId","typeName","skus","dialingPrefix","vanity"]}},"scannedPages":{"type":"integer"},"truncated":{"type":"boolean","description":"True when the scan budget ran out before the end of the catalogue"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"numbers:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"pattern","in":"query","required":false,"description":"Digits to match against the dialing prefix (country + area)","schema":{"type":"string","maxLength":24}},{"name":"match","in":"query","required":false,"description":"Default contains","schema":{"type":"string","enum":["contains","starts_with","ends_with","exact"]}},{"name":"vanity","in":"query","required":false,"description":"Only prefixes with repeating or sequential runs","schema":{"type":"string","enum":["true","false","1","0","yes","no","on","off"]}},{"name":"countryId","in":"query","required":false,"schema":{"type":"string","maxLength":64}},{"name":"typeId","in":"query","required":false,"schema":{"type":"string","maxLength":64}},{"name":"text","in":"query","required":false,"description":"Text over country, city and type name","schema":{"type":"string","maxLength":120}},{"name":"limit","in":"query","required":false,"description":"Default 50","schema":{"type":"integer","minimum":1,"maximum":100}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/dids/bulk-buy":{"post":{"operationId":"postDidsBulkBuy","tags":["Phone numbers"],"summary":"Buy several phone numbers in one request","description":"Buys each item in order and reports a result per item. Stops buying once your balance runs out and marks the rest `skipped`.\n\n**Auth:** API key or JWT. Scoped keys need `numbers:write`.\n\n**Idempotency:** send an `X-Idempotency-Key` header to make retries safe; a replay within 24 hours returns the original response.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/DidBulkBuyResult"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"numbers:write","x-idempotent":true,"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"X-Idempotency-Key","in":"header","required":false,"description":"Any unique string (a UUID is ideal). Replays within 24 hours return the first response instead of acting twice.","schema":{"type":"string","maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"skuId":{"type":"string","minLength":1,"maxLength":64},"groupId":{"type":"string","minLength":1,"maxLength":64},"countryId":{"type":"string","maxLength":64},"country":{"type":"string","maxLength":120},"city":{"type":"string","maxLength":120,"nullable":true},"areaPrefix":{"type":"string","maxLength":16,"nullable":true},"didType":{"type":"string","maxLength":40,"nullable":true}},"required":["skuId","groupId"]},"minItems":1,"maxItems":25}},"required":["items"]}}}},"x-px-example":{"path":{},"query":{},"body":{"items":[{"skuId":"<skuId>","groupId":"<groupId>"}]}},"x-px-billable":{"kind":"money","note":"Buys a phone number, charged to your balance."}}},"/api/v1/dids/analytics/overview":{"get":{"operationId":"getDidsAnalyticsOverview","tags":["Phone numbers"],"summary":"Get a spend and usage overview across your numbers","description":"**Auth:** API key or JWT. Scoped keys need `numbers:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/DidNumbersOverview"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"numbers:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/dids/{id}/analytics":{"get":{"operationId":"getDidsByIdAnalytics","tags":["Phone numbers"],"summary":"Get spend and usage analytics for a number","description":"Totals and a month-by-month series. Spend figures are USD display numbers.\n\n**Auth:** API key or JWT. Scoped keys need `numbers:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/DidAnalytics"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"numbers:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"months","in":"query","required":false,"description":"Trailing months in the series","schema":{"type":"integer"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/account/ips":{"get":{"operationId":"getAccountIps","tags":["Account"],"summary":"List your dedicated IP addresses","description":"Empty, with `enabled: false`, while dedicated IPs are not offered.\n\n**Auth:** API key or JWT. Scoped keys need `account:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/AccountDedicatedIp"}},"enabled":{"type":"boolean"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/account/ips/interconnect":{"get":{"operationId":"getAccountIpsInterconnect","tags":["Account"],"summary":"Get your SIP interconnect details","description":"Everything needed to connect: where to send traffic, which addresses our calls leave from, and what is already authorised.\n\n**Auth:** API key or JWT. Scoped keys need `account:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/AccountInterconnect"},"enabled":{"type":"boolean"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/account/ips/connectivity":{"get":{"operationId":"getAccountIpsConnectivity","tags":["Account"],"summary":"Get your connectivity brief","description":"Where to send traffic, what to whitelist and how you are recognised, including per-purchase destinations, in plain language. Also carries `smpp` ({ host, port } to bind to our SMPP gateway) and `sipServer` ({ host, port } a sub-account or softphone registers to).\n\n**Auth:** API key or JWT. Scoped keys need `account:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/AccountConnectivityBrief"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/account/ips/activate":{"post":{"operationId":"postAccountIpsActivate","tags":["Account"],"summary":"Take a dedicated ingress IP","description":"Idempotent: when you already hold one it is returned with `created: false` and nothing is charged. Answers 201 when a new address was assigned.\n\n**Auth:** API key or JWT. Scoped keys need `account:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/AccountActivatedIp"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}},"x-px-billable":{"kind":"money","note":"Takes a dedicated IP address."}}},"/api/v1/account/ips/activate-egress":{"post":{"operationId":"postAccountIpsActivateEgress","tags":["Account"],"summary":"Take a dedicated egress IP","description":"Idempotent like the ingress version. Refused with VALIDATION_ERROR while dedicated sending addresses are not available.\n\n**Auth:** API key or JWT. Scoped keys need `account:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/AccountActivatedIp"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}},"x-px-billable":{"kind":"money","note":"Takes a dedicated IP address."}}},"/api/v1/account/ips/{id}/release":{"post":{"operationId":"postAccountIpsByIdRelease","tags":["Account"],"summary":"Release a dedicated IP","description":"Hands the address back to the pool. `id` is the assignment id or IP id from the list.\n\n**Auth:** API key or JWT. Scoped keys need `account:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"released":{"type":"boolean","enum":[true]},"address":{"type":"string"},"ipId":{"type":"string","format":"uuid"}},"required":["released","address","ipId"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/verify/start":{"post":{"operationId":"postVerifyStart","tags":["Verify"],"summary":"Start a verification: a code by SMS or voice, or a call-in","description":"Generates a code of `length` digits (default 6), sends it over `channel`, and returns a `verificationId`. We store only a keyed hash (HMAC) of the code; the code itself is never stored or logged. The code expires after `expirySeconds` (default 600). SMS languages: en, es, fr, de, pt, hi, ar. Voice languages: en, es, fr, de, pt, hi. `from` is the SMS sender ID (defaults to your brand) or, for voice, the caller ID. Billed as the SMS or call that carries the code: the route rate plus the platform fee, no verification fee. A test key sends nothing, charges test credit and returns `testCode` so you can finish the flow. Omit `strategy` and the code goes out over Smart Routing's `best_quality` route for the destination (plain calls and SMS default to `balanced`). Limits, shared by voice passcodes and the Verify API: 5 codes per number per hour, 30 seconds between codes to the same number, a per-account daily cap, and a cap on codes into one number range per hour. A limit answers 429 with `details.retryAfterSeconds`. Embargoed destinations, premium-rate / satellite / high-risk ranges and numbers on your Do-Not-Contact list are refused with 400. CALL-IN (`channel: \"call_in\"`): uses a phone number YOU hold. Buy one in the DID Store in the country of the people you verify, then switch it on with POST /verify/call-in/numbers. No code is sent. The response carries `callNumber`; show it to your user and ask them to call it FROM `to`. The call is matched by its caller ID and ended straight away without being answered, so it is free for the caller, and the verification turns `approved`. Learn the result from the `verification.approved` webhook (or `verification.expired` when nobody called in time), or poll GET /verify/{id}. `expirySeconds` defaults to 300 for call-in. Each of your call-in numbers verifies phone numbers in its own country (dial code); a `to` with no call-in number for its country answers 400. Price: a flat fee per APPROVED verification (see coverage), taken from your balance when the call arrives; an expired verification is free. Your balance must cover one verification to start. Starting again with the same `reference`, or for the same `to` while one is pending, returns the pending verification instead of a new one. A test key returns a real-looking verification that no call can approve: finish it with POST /verify/{id}/simulate-call. A caller ID is weaker proof than a code: use call-in to confirm a phone number at sign-up, and a code for high-risk actions such as account recovery or payments.\n\n**Auth:** API key or JWT. Scoped keys need `verify:write`.\n\n**Rate limit:** 10 requests per second per caller.\n\n**Idempotency:** send an `X-Idempotency-Key` header to make retries safe; a replay within 24 hours returns the original response.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"anyOf":[{"$ref":"#/components/schemas/VerifyStartResult"},{"$ref":"#/components/schemas/CallInVerification"}]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"verify:write","x-rate-limit":{"max":10,"window":"second"},"x-idempotent":true,"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"X-Idempotency-Key","in":"header","required":false,"description":"Any unique string (a UUID is ideal). Replays within 24 hours return the first response instead of acting twice.","schema":{"type":"string","maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"to":{"type":"string","pattern":"^\\+?[1-9][0-9]{6,14}$"},"channel":{"type":"string","enum":["sms","voice","call_in"],"description":"`sms` or `voice` send a code; `call_in` returns a number the user calls from `to`, and the call itself verifies them"},"reference":{"type":"string","pattern":"^[A-Za-z0-9._:@-]{1,128}$","description":"Your own id for this request (e.g. your user or session id). Echoed on every read and webhook; a pending verification is reused when you start again with the same reference"},"length":{"type":"integer","minimum":4,"maximum":10},"language":{"type":"string","pattern":"^[a-z]{2}$"},"brand":{"type":"string","maxLength":120,"description":"Brand read out / sent. Cleaned to letters, digits and spaces, max 30 characters"},"expirySeconds":{"type":"integer","minimum":60,"maximum":3600},"from":{"type":"string","minLength":1,"maxLength":30},"strategy":{"type":"string","enum":["cheapest","best_quality","balanced"]},"route":{"type":"string","enum":["smart","direct"]}},"required":["to","channel"]}}}},"x-px-example":{"path":{},"query":{},"body":{"to":"+447700900123","channel":"sms"}},"x-px-billable":{"kind":"traffic","note":"Sends a real SMS or places a real voice call carrying the code, billed as that message or call. A test key simulates it."}}},"/api/v1/verify/check":{"post":{"operationId":"postVerifyCheck","tags":["Verify"],"summary":"Check the code a user entered","description":"`approved` exactly once: a code is single use, and a second check of an approved verification answers `denied` with reason `already_used`. Five attempts in total; the fifth wrong guess answers `max_attempts` and the verification is dead. After `expiresAt` every check answers `expired`, even with the right code. Spaces and dashes in the submitted code are ignored. The comparison is constant-time.\n\n**Auth:** API key or JWT. Scoped keys need `verify:write`.\n\n**Rate limit:** 20 requests per second per caller.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/VerifyCheckResult"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"verify:write","x-rate-limit":{"max":20,"window":"second"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"verificationId":{"type":"string","format":"uuid"},"code":{"type":"string","minLength":1,"maxLength":32}},"required":["verificationId","code"]}}}},"x-px-example":{"path":{},"query":{},"body":{"verificationId":"<verificationId>","code":"482913"}}}},"/api/v1/verify/call-in/coverage":{"get":{"operationId":"getVerifyCallInCoverage","tags":["Verify"],"summary":"Call-in coverage, numbers and price","description":"The call-in numbers your account can use, the dial code each verifies, and the price per approved verification.\n\n**Auth:** API key or JWT. Scoped keys need `verify:write`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/CallInCoverage"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"verify:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/verify/call-in/numbers":{"get":{"operationId":"getVerifyCallInNumbers","tags":["Verify"],"summary":"Your phone numbers and their call-in setting","description":"Every phone number on your account (DID Store) with whether it answers call-in verifications, and the dial code it verifies.\n\n**Auth:** API key or JWT. Scoped keys need `verify:write`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/CallInNumber"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"verify:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}},"post":{"operationId":"postVerifyCallInNumbers","tags":["Verify"],"summary":"Use one of your phone numbers for call-in verification","description":"Switches call-in ON for an active number you hold. From then on every call to it is treated as a verification attempt and ended without being answered, so any ringing set up on the number stops until you switch call-in off. The number verifies phone numbers in its own country (dial code). Live keys only.\n\n**Auth:** API key or JWT. Scoped keys need `verify:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/CallInNumber"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"verify:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"phoneNumberId":{"type":"string","format":"uuid"}},"required":["phoneNumberId"]}}}},"x-px-example":{"path":{},"query":{},"body":{"phoneNumberId":"<phoneNumberId>"}}}},"/api/v1/verify/call-in/numbers/{phoneNumberId}":{"delete":{"operationId":"deleteVerifyCallInNumbersByPhoneNumberId","tags":["Verify"],"summary":"Stop using a number for call-in verification","description":"Switches call-in OFF for the number; calls to it ring as set up again. Pending call-in verifications on it simply expire. Live keys only.\n\n**Auth:** API key or JWT. Scoped keys need `verify:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"allOf":[{"$ref":"#/components/schemas/CallInNumber"}],"nullable":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"verify:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"phoneNumberId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"phoneNumberId":"<phoneNumberId>"},"query":{}}}},"/api/v1/verify":{"get":{"operationId":"getVerify","tags":["Verify"],"summary":"List recent verifications","description":"Newest first. Filter by your `reference`, `status` or `channel`. Test keys see only test verifications, live keys only live ones.\n\n**Auth:** API key or JWT. Scoped keys need `verify:write`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"anyOf":[{"$ref":"#/components/schemas/Verification"},{"$ref":"#/components/schemas/CallInVerification"}]}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"verify:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"reference","in":"query","required":false,"schema":{"type":"string","maxLength":128}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["pending","approved","expired","max_attempts","failed"]}},{"name":"channel","in":"query","required":false,"schema":{"type":"string","enum":["sms","voice","call_in"]}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/verify/{id}":{"get":{"operationId":"getVerifyById","tags":["Verify"],"summary":"Get the state of a verification","description":"Status, attempts used and how the code was delivered (never the code). For a call-in verification: whether the call arrived, from which caller ID and when.\n\n**Auth:** API key or JWT. Scoped keys need `verify:write`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"anyOf":[{"$ref":"#/components/schemas/Verification"},{"$ref":"#/components/schemas/CallInVerification"}]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"verify:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/verify/{id}/simulate-call":{"post":{"operationId":"postVerifyByIdSimulateCall","tags":["Verify"],"summary":"Simulate the user's call (test keys only)","description":"Approves a pending test-key call-in verification as if the call came from its `to` number, and sends the same `verification.approved` webhook with `simulated: true`. Nothing is charged. Live keys answer 400.\n\n**Auth:** API key or JWT. Scoped keys need `verify:write`.\n\n**Rate limit:** 10 requests per second per caller.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/CallInVerification"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"verify:write","x-rate-limit":{"max":10,"window":"second"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/billing/tax-invoices":{"get":{"operationId":"getBillingTaxInvoices","tags":["Billing"],"summary":"List your tax invoices","description":"Numbered tax invoices (gap-free per account), newest first, up to 500.\n\n**Auth:** API key or JWT. Scoped keys need `account:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/TaxInvoiceSummary"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/billing/tax-invoices/generate":{"post":{"operationId":"postBillingTaxInvoicesGenerate","tags":["Billing"],"summary":"Generate the tax invoice for a month","description":"Idempotent per period: if the month already has an invoice it is returned with `alreadyExisted: true` and status 200; a new one returns 201. 503 when the invoice register is not available on this node.\n\n**Auth:** API key or JWT. Scoped keys need `account:write`.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"201":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"seq":{"type":"integer","description":"Gap-free per-account sequence"},"number":{"type":"string"},"period":{"type":"string","description":"YYYY-MM"},"periodStart":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"periodEnd":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"currency":{"type":"string"},"subtotal":{"type":"string","description":"Decimal string"},"taxAmount":{"type":"string","description":"Decimal string"},"total":{"type":"string","description":"Decimal string"},"createdAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"dataJson":{"type":"object","additionalProperties":{},"nullable":true,"description":"Frozen line items and the tax section as issued"},"alreadyExisted":{"type":"boolean"}},"required":["id","seq","number","period","periodStart","periodEnd","currency","subtotal","taxAmount","total","createdAt","dataJson","alreadyExisted"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:write","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"period":{"type":"string","pattern":"^\\d{4}-\\d{2}$"}},"required":["period"]}}}},"x-px-example":{"path":{},"query":{},"body":{"period":"<period>"}}}},"/api/v1/billing/tax-invoices/{id}":{"get":{"operationId":"getBillingTaxInvoicesById","tags":["Billing"],"summary":"Get a tax invoice","description":"JSON by default; `format=html` returns a printable invoice page.\n\n**Auth:** API key or JWT. Scoped keys need `account:read`.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/TaxInvoice"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-required-scope":"account:read","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"format","in":"query","required":false,"description":"html returns a printable page","schema":{"type":"string","enum":["json","html"]}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/public/numbers/catalog":{"get":{"operationId":"getPublicNumbersCatalog","tags":["Phone numbers"],"summary":"Browse the public number catalogue","description":"No account needed: prices only, for pre-signup browsing. While the number store is switched off this answers 200 with `data: { disabled: true, comingSoon: true, message }`.\n\n**Auth:** none (public endpoint).\n\n**Rate limit:** 30 requests per minute per caller.","responses":{"200":{"description":"One page of number groups. Note: `groups`, `total` and `page` sit at the TOP level beside `success`, not under `data`.","content":{"application/json":{"schema":{"type":"object","required":["success","success","groups","total","page"],"properties":{"success":{"type":"boolean","enum":[true]},"groups":{"type":"array","items":{"$ref":"#/components/schemas/DidCatalogGroup"}},"total":{"type":"integer","nullable":true},"page":{"type":"integer"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"public","x-rate-limit":{"max":30,"window":"minute"},"security":[],"parameters":[{"name":"countryId","in":"query","required":false,"description":"From GET .../catalog/countries","schema":{"type":"string","maxLength":64}},{"name":"typeId","in":"query","required":false,"description":"From GET .../catalog/types","schema":{"type":"string","maxLength":64}},{"name":"search","in":"query","required":false,"description":"Text match over country, city, area prefix and type; digits also match the start of the full dialling prefix (\"4420\" finds London). Spans the whole catalogue once it is indexed, otherwise the fetched page","schema":{"type":"string","maxLength":120}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200}},{"name":"sort","in":"query","required":false,"description":"Order by the cheapest monthly price, setup price or location. Omitted: the catalogue order","schema":{"type":"string","enum":["monthly_asc","monthly_desc","setup_asc","location_asc"]}},{"name":"maxMonthly","in":"query","required":false,"description":"Only groups whose cheapest monthly price is at most this, in USD","schema":{"type":"number","minimum":0}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/public/numbers/catalog/summary":{"get":{"operationId":"getPublicNumbersCatalogSummary","tags":["Phone numbers"],"summary":"Number catalogue market summary","description":"No account needed. The store's live figures: how many countries and number groups are for sale, and the cheapest monthly price by number type and by country. Prices only. Indexed in the background and refreshed about every 20 minutes. While the number store is switched off this answers 200 with `data: { disabled: true, comingSoon: true, message }`.\n\n**Auth:** none (public endpoint).\n\n**Rate limit:** 15 requests per minute per caller.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/DidCatalogSummary"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"public","x-rate-limit":{"max":15,"window":"minute"},"security":[],"x-px-example":{"path":{},"query":{}}}},"/api/v1/public/numbers/catalog/countries":{"get":{"operationId":"getPublicNumbersCatalogCountries","tags":["Phone numbers"],"summary":"List countries in the public number catalogue","description":"While the number store is switched off this answers 200 with `data: { disabled: true, comingSoon: true, message }`.\n\n**Auth:** none (public endpoint).\n\n**Rate limit:** 15 requests per minute per caller.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/DidCatalogCountry"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"public","x-rate-limit":{"max":15,"window":"minute"},"security":[],"x-px-example":{"path":{},"query":{}}}},"/api/v1/public/numbers/catalog/types":{"get":{"operationId":"getPublicNumbersCatalogTypes","tags":["Phone numbers"],"summary":"List number types in the public number catalogue","description":"While the number store is switched off this answers 200 with `data: { disabled: true, comingSoon: true, message }`.\n\n**Auth:** none (public endpoint).\n\n**Rate limit:** 15 requests per minute per caller.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/DidCatalogType"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"public","x-rate-limit":{"max":15,"window":"minute"},"security":[],"x-px-example":{"path":{},"query":{}}}},"/api/v1/pricing/ai-voice":{"get":{"operationId":"getPricingAiVoice","tags":["System"],"summary":"Get the public AI voice price per minute","description":"The same per-minute rate the billing engine charges for AI-connected minutes, metered per second (`billingIncrementSeconds: 1`). Sell price only. No authentication, and it never answers 401, so a signed-in page can call it safely. Cacheable for 5 minutes (`Cache-Control: public, max-age=300`).\n\n**Auth:** none (public endpoint).\n\n**Rate limit:** 60 requests per minute per caller.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"ratePerMin":{"type":"number","description":"USD per AI-connected minute (a JSON number, for display)"},"currency":{"type":"string","enum":["USD"]},"billingIncrementSeconds":{"type":"integer"}},"required":["ratePerMin","currency","billingIncrementSeconds"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"public","x-rate-limit":{"max":60,"window":"minute"},"security":[],"x-px-example":{"path":{},"query":{}}}},"/api/v1/public/listings/parse":{"post":{"operationId":"postPublicListingsParse","tags":["Marketplace routes"],"summary":"Read a rate sheet into a draft listing (no account needed)","description":"Multipart upload (field `file`, optional `note`). Returns the proposed listing and parsed rates; stores nothing.\n\n**Auth:** none (public endpoint).\n\n**Rate limit:** 6 requests per minute per caller.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{},"additionalProperties":true,"description":"Proposed listing, parsed rates and `truncated`"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"public","x-rate-limit":{"max":6,"window":"minute"},"security":[],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","description":"CSV or Excel rate sheet (binary)"},"note":{"type":"string","maxLength":500}},"required":["file"]}}}},"x-px-example":{"path":{},"query":{}}}},"/api/v1/public/listings":{"post":{"operationId":"postPublicListings","tags":["Marketplace routes"],"summary":"Save a draft listing to claim after sign-up","description":"Returns a token; the listing is created only when a signed-in account claims it.\n\n**Auth:** none (public endpoint).\n\n**Rate limit:** 10 requests per 10 minutes per caller.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"token":{"type":"string"},"expiresAt":{"type":"string","format":"date-time","description":"ISO-8601 timestamp (UTC)"},"rateCount":{"type":"integer"},"destinationName":{"type":"string"}},"required":["token","expiresAt","rateCount","destinationName"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"public","x-rate-limit":{"max":10,"window":"10 minutes"},"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"payload":{},"rates":{"type":"array","items":{"type":"object","properties":{"destinationName":{"type":"string"},"operator":{"type":"string","nullable":true},"prefix":{"type":"string"},"ratePerUnit":{"type":"string"},"billingIncrement":{"type":"string","nullable":true},"minDuration":{"type":"number","nullable":true}},"required":["prefix","ratePerUnit"]},"maxItems":20000},"sourceFilename":{"type":"string","maxLength":512},"contactEmail":{"type":"string","format":"email","maxLength":255},"contactCompany":{"type":"string","maxLength":255},"currency":{"type":"string","pattern":"^[A-Za-z]{3}$"},"fxRate":{"type":"number","exclusiveMinimum":true,"minimum":0},"sheetRates":{"type":"integer","minimum":0}}}}}},"x-px-example":{"path":{},"query":{},"body":{"payload":"<payload>","rates":[{"prefix":"44","ratePerUnit":"<ratePerUnit>"}]}}}},"/api/v1/public/listings/{token}":{"get":{"operationId":"getPublicListingsByToken","tags":["Marketplace routes"],"summary":"Look at a saved draft listing","description":"**Auth:** none (public endpoint).\n\n**Rate limit:** 30 requests per minute per caller.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"alreadyClaimed":{"type":"boolean"},"routeId":{"type":"string","format":"uuid","nullable":true},"destinationName":{"type":"string"},"type":{"type":"string","enum":["voice","sms"]},"country":{"type":"string"},"rateCount":{"type":"integer"},"sourceFilename":{"type":"string","nullable":true}},"required":["alreadyClaimed"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"public","x-rate-limit":{"max":30,"window":"minute"},"security":[],"parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"token":"<token>"},"query":{}}}},"/api/v1/listings/pending":{"get":{"operationId":"getListingsPending","tags":["Marketplace routes"],"summary":"GET /api/v1/listings/pending","description":"**Auth:** API key or JWT. Not available to scoped keys. Use a full-access key or a dashboard session.\n\n**Rate limit:** 30 requests per minute per caller.","responses":{"200":{"description":" Response shape not documented yet: the standard `{ \"success\": true, \"data\": ... }` envelope."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"key","x-rate-limit":{"max":30,"window":"minute"},"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/status/page":{"get":{"operationId":"getStatusPage","tags":["Status"],"summary":"Get the public status page","description":"Overall state, component groups with 90-day history, active and recent incidents, and scheduled maintenance. Cached for 15 seconds.\n\n**Auth:** none (public endpoint).\n\n**Rate limit:** 120 requests per minute per caller.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/StatusPage"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"public","x-rate-limit":{"max":120,"window":"minute"},"security":[],"x-px-example":{"path":{},"query":{}}}},"/api/v1/status/active":{"get":{"operationId":"getStatusActive","tags":["Status"],"summary":"Is anything wrong right now","description":"A slim projection of GET /status/page for in-app notices: `active` (any unresolved incident or maintenance in progress), the overall state, unresolved incidents with their newest update, and maintenance in progress. Cached for 15 seconds.\n\n**Auth:** none (public endpoint).\n\n**Rate limit:** 120 requests per minute per caller.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{},"additionalProperties":true,"description":"{ active, overall: { state, message }, incidents: [{ id, title, impact, status, startedAt, componentIds, latestUpdate }], maintenance: [{ id, title, scheduledStart, scheduledEnd, componentIds }], generatedAt }"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"public","x-rate-limit":{"max":120,"window":"minute"},"security":[],"x-px-example":{"path":{},"query":{}}}},"/api/v1/status/incidents":{"get":{"operationId":"getStatusIncidents","tags":["Status"],"summary":"List past incidents","description":"**Auth:** none (public endpoint).\n\n**Rate limit:** 120 requests per minute per caller.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/StatusIncident"}},"nextCursor":{"type":"string","nullable":true}},"required":["items","nextCursor"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"public","x-rate-limit":{"max":120,"window":"minute"},"security":[],"parameters":[{"name":"cursor","in":"query","required":false,"description":"The `nextCursor` from the previous page","schema":{"type":"string","maxLength":200}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/status/incidents/{id}":{"get":{"operationId":"getStatusIncidentsById","tags":["Status"],"summary":"Get one incident with its updates","description":"**Auth:** none (public endpoint).\n\n**Rate limit:** 120 requests per minute per caller.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/StatusIncident"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"public","x-rate-limit":{"max":120,"window":"minute"},"security":[],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"x-px-example":{"path":{"id":"<id>"},"query":{}}}},"/api/v1/status/feed.xml":{"get":{"operationId":"getStatusFeedXml","tags":["Status"],"summary":"Subscribe to status updates as an RSS feed","description":"**Auth:** none (public endpoint).\n\n**Rate limit:** 120 requests per minute per caller.","responses":{"200":{"description":"RSS 2.0 feed of incidents and maintenance.","content":{"application/rss+xml":{"schema":{"type":"string"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"public","x-rate-limit":{"max":120,"window":"minute"},"security":[],"x-px-example":{"path":{},"query":{}}}},"/api/v1/status/subscribe":{"post":{"operationId":"postStatusSubscribe","tags":["Status"],"summary":"Subscribe an email address to status updates","description":"Sends a confirmation email. The answer is the same whether or not the address was already subscribed.\n\n**Auth:** none (public endpoint).\n\n**Rate limit:** 5 requests per hour per caller.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/Message"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"public","x-rate-limit":{"max":5,"window":"hour"},"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","format":"email","maxLength":254}},"required":["email"]}}}},"x-px-example":{"path":{},"query":{},"body":{"email":"you@example.com"}}}},"/api/v1/status/subscribe/confirm":{"get":{"operationId":"getStatusSubscribeConfirm","tags":["Status"],"summary":"Confirm a status subscription from the email link","description":"**Auth:** none (public endpoint).\n\n**Rate limit:** 30 requests per 10 minutes per caller.","responses":{"302":{"description":"Redirects to the status page with the outcome.","headers":{"Location":{"schema":{"type":"string"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"public","x-rate-limit":{"max":30,"window":"10 minutes"},"security":[],"parameters":[{"name":"token","in":"query","required":false,"schema":{"type":"string","maxLength":200}}],"x-px-example":{"path":{},"query":{}}}},"/api/v1/status/unsubscribe":{"get":{"operationId":"getStatusUnsubscribe","tags":["Status"],"summary":"Unsubscribe from status updates from the email link","description":"**Auth:** none (public endpoint).\n\n**Rate limit:** 30 requests per 10 minutes per caller.","responses":{"302":{"description":"Redirects to the status page with the outcome.","headers":{"Location":{"schema":{"type":"string"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"public","x-rate-limit":{"max":30,"window":"10 minutes"},"security":[],"parameters":[{"name":"token","in":"query","required":false,"schema":{"type":"string","maxLength":200}}],"x-px-example":{"path":{},"query":{}}},"post":{"operationId":"postStatusUnsubscribe","tags":["Status"],"summary":"Unsubscribe from status updates in one click","description":"The RFC 8058 one-click unsubscribe target used by mail clients.\n\n**Auth:** none (public endpoint).\n\n**Rate limit:** 120 requests per minute per caller.\n\n**Test keys:** refused with 403 `TEST_KEY_NOT_ALLOWED`. This action has no test mode, so it would change your live account. Use a live key.","responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"result":{"type":"string","description":"Outcome, e.g. unsubscribed or invalid"}},"required":["result"]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}},"x-auth":"public","x-rate-limit":{"max":120,"window":"minute"},"security":[],"parameters":[{"name":"token","in":"query","required":false,"schema":{"type":"string","maxLength":200}}],"x-px-example":{"path":{},"query":{}}}}}}