{"openapi":"3.1.0","info":{"title":"Onedex API","version":"1.0.0","description":"Buy eSIMs, airtime, data bundles and verification numbers from your Onedex wallet, and read the catalog for every other Onedex service. All prices are in NGN and every purchase is debited from a single shared wallet. See https://your-onedex-domain/api-docs for the full guide.","contact":{"url":"https://your-onedex-domain/api-docs"}},"servers":[{"url":"https://your-onedex-domain/api/v1","description":"Production"}],"security":[{"bearerAuth":[]}],"tags":[{"name":"Wallet","description":"Read the shared wallet balance."},{"name":"eSIM","description":"Browse and buy data eSIMs."},{"name":"Bills","description":"Nigerian airtime and data bundles."},{"name":"Marketplace","description":"Browse and buy from the product catalog."},{"name":"Numbers","description":"Buy one-time verification numbers and long-term rentals. A one-time number holds its price in escrow rather than charging it: poll the activation until a code lands (charged) or cancel it for the hold back (free). Rentals are charged upfront for the whole window and are not refundable."},{"name":"Boost","description":"Buy social engagement from the SMM panels. Charged upfront, delivered over time: place an order, poll it, and cancel or refill it. Undelivered units are refunded proportionally when an order is cancelled or ends Partial."},{"name":"Checkmark","description":"Browse account-verification listings. Read-only."},{"name":"Subscriptions","description":"Browse and order subscription top-ups. Ordering holds the price in escrow rather than charging it: requests are fulfilled by hand, so poll the request until it completes (charged) or fails (hold released in full)."}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"An API key from the Onedex Developer console, sent as 'Authorization: Bearer odx_live_...'. Required on every endpoint, including catalog reads."}}},"paths":{"/balance":{"get":{"tags":["Wallet"],"operationId":"getBalance","summary":"Get wallet balance","description":"Returns the spendable wallet balance for the key's owner. Free to call. Referral commission is held separately and is not included.","responses":{"200":{"description":"Current balance.","content":{"application/json":{"schema":{"type":"object","properties":{"balance":{"type":"number"},"currency":{"type":"string","enum":["NGN"]}},"required":["balance","currency"]}}}},"401":{"description":"Missing, malformed, revoked or unknown API key.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"429":{"description":"Per-key rate limit exceeded.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"502":{"description":"Upstream provider failed. You were not charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}}},"/esim/packages":{"get":{"tags":["eSIM"],"operationId":"listEsimPackages","summary":"List eSIM packages","description":"The eSIM catalog grouped by country. Prices are in NGN with the account's Premium discount already applied. Free to call. Package ids are not stable indefinitely — resolve them here rather than hardcoding.","responses":{"200":{"description":"Catalog grouped by country.","content":{"application/json":{"schema":{"type":"object","properties":{"countries":{"type":"array","items":{"type":"object","properties":{"country_code":{"type":"string"},"title":{"type":"string"},"packages":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"data":{"type":"string"},"days":{"type":"integer"},"unlimited":{"type":"boolean"},"price":{"type":"number"},"currency":{"type":"string","enum":["NGN"]}}}}}}}},"required":["countries"]}}}},"401":{"description":"Missing, malformed, revoked or unknown API key.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"429":{"description":"Per-key rate limit exceeded.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"502":{"description":"Upstream provider failed. You were not charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}}},"/esim/orders":{"post":{"tags":["eSIM"],"operationId":"createEsimOrder","summary":"Buy an eSIM","description":"Purchases a package and returns the issued eSIM with QR and activation details. The wallet is debited before the upstream order is placed and reversed in full if issuing fails. Send an Idempotency-Key so a retry after a timeout replays the issued eSIM rather than buying a second one.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"A unique value per purchase — a UUID is ideal. The first request stores its result; repeats replay it with an 'Idempotent-Replay: true' header instead of spending again. Scoped to your account, expires after 24 hours."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"package_id":{"type":"string","description":"An id from /esim/packages."},"packageId":{"type":"string","description":"Accepted alias for package_id."}},"required":["package_id"]}}}},"responses":{"200":{"description":"The issued eSIM.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"price":{"type":"number"},"currency":{"type":"string","enum":["NGN"]},"iccid":{"type":"string"},"qrcode":{"type":"string"},"qrcode_url":{"type":"string"},"lpa":{"type":"string"},"matching_id":{"type":"string"},"data":{"type":"string"},"validity_days":{"type":"integer"}}}}}},"400":{"description":"Malformed request or failed validation.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"401":{"description":"Missing, malformed, revoked or unknown API key.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"402":{"description":"Insufficient wallet balance. You were not charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"409":{"description":"A request with this Idempotency-Key is still in flight. Retry the same key shortly to read its result.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"422":{"description":"This Idempotency-Key was already used with a different request body. Use a new key for a new purchase.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"429":{"description":"Per-key rate limit exceeded.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"500":{"description":"The upstream order succeeded but recording it failed. Your wallet was restored; contact support before retrying.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"502":{"description":"Upstream provider failed. You were not charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}}},"/bills/data-plans":{"get":{"tags":["Bills"],"operationId":"listDataPlans","summary":"List data plans","description":"Nigerian data bundles currently on sale across MTN, Airtel, Glo and 9mobile. Free to call. Availability changes through the day — fetch immediately before ordering.","responses":{"200":{"description":"Available plans.","content":{"application/json":{"schema":{"type":"object","properties":{"plans":{"type":"array","items":{"type":"object","properties":{"package_code":{"type":"string"},"network":{"type":"string","enum":["mtn","airtel","glo","9mobile"]},"data":{"type":"string"},"type":{"type":"string"},"validity":{"type":"string"},"price":{"type":"number"},"currency":{"type":"string","enum":["NGN"]}}}}},"required":["plans"]}}}},"401":{"description":"Missing, malformed, revoked or unknown API key.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"429":{"description":"Per-key rate limit exceeded.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"502":{"description":"Upstream provider failed. You were not charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}}},"/bills/airtime":{"post":{"tags":["Bills"],"operationId":"buyAirtime","summary":"Buy airtime","description":"Tops up a Nigerian number. 'amount' is the face value the recipient receives; the 'price' in the response is the larger sum debited from your wallet. Premium discounts do not apply. Send an Idempotency-Key so a retry after a timeout does not top up twice.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"A unique value per purchase — a UUID is ideal. The first request stores its result; repeats replay it with an 'Idempotent-Replay: true' header instead of spending again. Scoped to your account, expires after 24 hours."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"network":{"type":"string","enum":["mtn","airtel","glo","9mobile"]},"phone":{"type":"string","description":"Recipient number. 080…, +234… and 234… are all normalized."},"amount":{"type":"integer","minimum":50,"maximum":50000,"description":"Face value in NGN. Decimals are truncated."}},"required":["network","phone","amount"]}}}},"responses":{"200":{"description":"Airtime delivered.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"Onedex order id."},"price":{"type":"number","description":"NGN actually debited from the wallet."},"currency":{"type":"string","enum":["NGN"]},"reference":{"type":"string","description":"Upstream provider reference."},"status":{"type":"string","enum":["success"]}},"required":["id","price","currency","status"]}}}},"400":{"description":"Malformed request or failed validation.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"401":{"description":"Missing, malformed, revoked or unknown API key.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"402":{"description":"Insufficient wallet balance. You were not charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"409":{"description":"A request with this Idempotency-Key is still in flight. Retry the same key shortly to read its result.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"422":{"description":"This Idempotency-Key was already used with a different request body. Use a new key for a new purchase.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"429":{"description":"Per-key rate limit exceeded.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"500":{"description":"The upstream order succeeded but recording it failed. Your wallet was restored; contact support before retrying.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"502":{"description":"Upstream provider failed. You were not charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}}},"/bills/data":{"post":{"tags":["Bills"],"operationId":"buyDataBundle","summary":"Buy a data bundle","description":"Delivers a data bundle to a Nigerian number. The network is inferred from the package code. Premium discounts do not apply. Send an Idempotency-Key so a retry after a timeout does not deliver twice.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"A unique value per purchase — a UUID is ideal. The first request stores its result; repeats replay it with an 'Idempotent-Replay: true' header instead of spending again. Scoped to your account, expires after 24 hours."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"phone":{"type":"string"},"package_code":{"type":"string","description":"A package_code from /bills/data-plans."},"packageCode":{"type":"string","description":"Accepted alias for package_code."}},"required":["phone","package_code"]}}}},"responses":{"200":{"description":"Bundle delivered.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"Onedex order id."},"price":{"type":"number","description":"NGN actually debited from the wallet."},"currency":{"type":"string","enum":["NGN"]},"reference":{"type":"string","description":"Upstream provider reference."},"status":{"type":"string","enum":["success"]}},"required":["id","price","currency","status"]}}}},"400":{"description":"Malformed request or failed validation.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"401":{"description":"Missing, malformed, revoked or unknown API key.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"402":{"description":"Insufficient wallet balance. You were not charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"409":{"description":"A request with this Idempotency-Key is still in flight. Retry the same key shortly to read its result.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"422":{"description":"This Idempotency-Key was already used with a different request body. Use a new key for a new purchase.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"429":{"description":"Per-key rate limit exceeded.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"500":{"description":"The upstream order succeeded but recording it failed. Your wallet was restored; contact support before retrying.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"502":{"description":"Upstream provider failed. You were not charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}}},"/store/products":{"get":{"tags":["Marketplace"],"operationId":"listStoreProducts","summary":"List marketplace products","description":"The marketplace catalog with live stock counts, in NGN with the account's Premium discount already applied. Free to call. Read-only: buying claims a stock unit and is done from the dashboard.","parameters":[{"name":"category","in":"query","required":false,"schema":{"type":"string"},"description":"Case-insensitive exact category filter."}],"responses":{"200":{"description":"Catalog with stock.","content":{"application/json":{"schema":{"type":"object","properties":{"products":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"category":{"type":"string"},"image_url":{"type":"string","nullable":true},"price":{"type":"number"},"currency":{"type":"string","enum":["NGN"]},"stock":{"type":"integer","description":"Unsold units available right now."}}}}},"required":["products"]}}}},"401":{"description":"Missing, malformed, revoked or unknown API key.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"429":{"description":"Per-key rate limit exceeded.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"502":{"description":"Upstream provider failed. You were not charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}}},"/store/orders":{"post":{"tags":["Marketplace"],"operationId":"createStoreOrder","summary":"Buy marketplace products","description":"Claims the requested number of stock units, debits the wallet and returns the purchased items in the response. Nothing here calls an external provider, so every failure rolls back fully — a non-2xx means you were not charged. Send an Idempotency-Key so a retry after a timeout replays the same items rather than buying more.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"A unique value per purchase — a UUID is ideal. The first request stores its result; repeats replay it with an 'Idempotent-Replay: true' header instead of spending again. Scoped to your account, expires after 24 hours."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"product_id":{"type":"string","description":"An id from /store/products."},"productId":{"type":"string","description":"Accepted alias for product_id."},"quantity":{"type":"integer","minimum":1,"maximum":50,"default":1,"description":"Units to buy. Each unit is a separate item."}},"required":["product_id"]}}}},"responses":{"200":{"description":"Order delivered, with the purchased items.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"product_id":{"type":"string"},"product_name":{"type":"string"},"quantity":{"type":"integer"},"unit_price":{"type":"number"},"price":{"type":"number","description":"Total debited."},"currency":{"type":"string","enum":["NGN"]},"status":{"type":"string","enum":["delivered"]},"items":{"type":"array","description":"The purchased goods. Store these — this is the delivery.","items":{"type":"object","properties":{"id":{"type":"string"},"value":{"type":"string"}}}}},"required":["id","price","currency","items"]}}}},"400":{"description":"Malformed request or unknown product_id.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"401":{"description":"Missing, malformed, revoked or unknown API key.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"402":{"description":"Insufficient wallet balance. You were not charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"409":{"description":"Not enough stock, or a request with this Idempotency-Key is still in flight. The message says which. You were not charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"422":{"description":"This Idempotency-Key was already used with a different request body.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"429":{"description":"Per-key rate limit exceeded.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"502":{"description":"Upstream provider failed. You were not charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"503":{"description":"The order could not be recorded and was rolled back in full. You were not charged — safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}}},"/verify/countries":{"get":{"tags":["Numbers"],"operationId":"listVerifyCountries","summary":"List number countries","description":"Countries that have verification numbers available, for use as the 'country' argument to /verify/services. Free to call.","parameters":[{"name":"server","in":"query","required":false,"schema":{"type":"string","enum":["server-1","server-1","server-1"]},"description":"Which server to query. Defaults to the primary. Each server carries its own countries, services, stock and prices, so a country sold out on one is often available on the other. An unrecognised value is rejected rather than silently defaulted."}],"responses":{"200":{"description":"Available countries.","content":{"application/json":{"schema":{"type":"object","properties":{"countries":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"has_services":{"type":"boolean"},"operators":{"type":"array","items":{"type":"string"}}}}}},"required":["countries"]}}}},"401":{"description":"Missing, malformed, revoked or unknown API key.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"429":{"description":"Per-key rate limit exceeded.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"502":{"description":"Upstream provider failed. You were not charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}}},"/verify/services":{"get":{"tags":["Numbers"],"operationId":"listVerifyServices","summary":"List number services and prices","description":"Services available in a country with live stock counts and NGN prices including the account's Premium discount. Free to call. Pass a 'code' from here as 'service' when buying a number. The price here is INDICATIVE — it comes from the upstream's aggregate catalog and is typically a little above what you actually pay, because buying takes the cheapest operator. For the exact figure, read /verify/servers, whose cheapest option is the price a purchase will be held at.","parameters":[{"name":"country","in":"query","required":true,"schema":{"type":"string"},"description":"A country id from /verify/countries."},{"name":"operators","in":"query","required":false,"schema":{"type":"string"},"description":"Comma-separated operator filter, or 'any'."},{"name":"server","in":"query","required":false,"schema":{"type":"string","enum":["server-1","server-1","server-1"]},"description":"Which server to query. Defaults to the primary. Each server carries its own countries, services, stock and prices, so a country sold out on one is often available on the other. An unrecognised value is rejected rather than silently defaulted."}],"responses":{"200":{"description":"Services on sale.","content":{"application/json":{"schema":{"type":"object","properties":{"services":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string"},"name":{"type":"string"},"count":{"type":"integer","description":"Numbers in stock, when the upstream reports it."},"price":{"type":"number"},"currency":{"type":"string","enum":["NGN"]}}}}},"required":["services"]}}}},"400":{"description":"Missing 'country'.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"401":{"description":"Missing, malformed, revoked or unknown API key.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"429":{"description":"Per-key rate limit exceeded.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"502":{"description":"Upstream provider failed. You were not charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}}},"/verify/servers":{"get":{"tags":["Numbers"],"operationId":"listVerifyServers","summary":"List operator options for a service","description":"Per-option prices for a country + service, cheapest first, so you can pick before buying. Pass an 'operator' value straight back as 'operators' on POST /verify/activations. Free to call.","parameters":[{"name":"country","in":"query","required":true,"schema":{"type":"string"},"description":"A country id from /verify/countries."},{"name":"service","in":"query","required":true,"schema":{"type":"string"},"description":"A service code from /verify/services."},{"name":"server","in":"query","required":false,"schema":{"type":"string","enum":["server-1","server-1","server-1"]},"description":"Which server to query. Defaults to the primary. Each server carries its own countries, services, stock and prices, so a country sold out on one is often available on the other. An unrecognised value is rejected rather than silently defaulted."}],"responses":{"200":{"description":"Options on sale.","content":{"application/json":{"schema":{"type":"object","properties":{"servers":{"type":"array","items":{"type":"object","properties":{"operator":{"type":"string"},"label":{"type":"string"},"price":{"type":"number"},"currency":{"type":"string","enum":["NGN"]},"count":{"type":"integer"}}}}},"required":["servers"]}}}},"400":{"description":"Missing 'country' or 'service'.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"401":{"description":"Missing, malformed, revoked or unknown API key.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"429":{"description":"Per-key rate limit exceeded.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"502":{"description":"Upstream provider failed. You were not charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}}},"/verify/activations":{"post":{"tags":["Numbers"],"operationId":"buyVerifyNumber","summary":"Buy a one-time number","description":"Buys a number and holds its price in escrow — you are NOT charged yet. Poll GET /verify/activations/{id} until 'status' becomes 'received' (the hold settles into a real charge and 'otp_code'/'sms_text' are filled in) or the window lapses. Give up early with POST /verify/activations/{id}/cancel and the whole hold comes straight back. This is a three-call flow by design: buy, poll, then either read the code or cancel.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"A unique value per purchase — a UUID is ideal. The first request stores its result; repeats replay it with an 'Idempotent-Replay: true' header instead of spending again. Scoped to your account, expires after 24 hours."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"service":{"type":"string","description":"A service code from /verify/services."},"country":{"type":"string","description":"A country id from /verify/countries."},"operators":{"oneOf":[{"type":"array","items":{"type":"string"}},{"type":"string"}],"description":"Preferred operator(s) from /verify/servers, as an array or a comma-separated string. Omit to take the cheapest."},"server":{"type":"string","enum":["server-1","server-1","server-1"],"description":"Which server to buy from. Defaults to the primary. Each server carries its own countries, services, stock and prices."},"service_name":{"type":"string","description":"Optional label stored with the order."},"country_name":{"type":"string","description":"Optional label stored with the order."}},"required":["service","country"]}}}},"responses":{"200":{"description":"Number issued, price held in escrow. Nothing has been charged yet.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"Pass this to the poll and cancel calls."},"status":{"type":"string","enum":["waiting","received","cancelled","expired"],"description":"'waiting' — the hold is open and no code has arrived. 'received' — a code (or an SMS body) landed and the wallet was charged. 'cancelled'/'expired' — the hold was released in full."},"phone_number":{"type":"string"},"service":{"type":"string"},"service_name":{"type":["string","null"]},"country":{"type":"string"},"country_name":{"type":["string","null"]},"server":{"type":"string","enum":["server-1","server-1","server-1"],"description":"Which server the number came from."},"price":{"type":"number","description":"NGN held in escrow. Only debited for real once status is 'received'."},"currency":{"type":"string","enum":["NGN"]},"charged":{"type":"boolean","description":"True once the hold has settled into an actual wallet charge."},"otp_code":{"type":["string","null"],"description":"The parsed verification code, when one could be extracted."},"sms_text":{"type":["string","null"],"description":"The full SMS body. Some messages carry no parseable code — this is still a delivery and is still charged."},"expires_at":{"type":["string","null"],"format":"date-time","description":"When the number stops accepting SMS and the hold is released."},"created_at":{"type":"string","format":"date-time"},"resends":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["waiting","received","expired"]},"price":{"type":"number"},"charged":{"type":"boolean"},"otp_code":{"type":["string","null"]},"sms_text":{"type":["string","null"]},"expires_at":{"type":["string","null"],"format":"date-time"},"created_at":{"type":"string","format":"date-time"}}},"description":"Paid re-requests on this number, oldest first."},"poll_after_ms":{"type":["integer","null"],"description":"Milliseconds to wait before reading this resource again, or null once nothing further can change."}},"required":["id","status","phone_number","price","currency","charged"]}}}},"400":{"description":"Malformed request or failed validation.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"401":{"description":"Missing, malformed, revoked or unknown API key.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"402":{"description":"Insufficient wallet balance. You were not charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"409":{"description":"A request with this Idempotency-Key is still in flight. Retry the same key shortly to read its result.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"422":{"description":"This Idempotency-Key was already used with a different request body. Use a new key for a new purchase.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"429":{"description":"Per-key rate limit exceeded.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"502":{"description":"Upstream provider failed. You were not charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"503":{"description":"The number could not be recorded and was rolled back in full — the hold was released and the number handed back. Nothing was charged; safe to retry with the same Idempotency-Key.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}},"get":{"tags":["Numbers"],"operationId":"listVerifyActivations","summary":"List recent numbers","description":"Your recent numbers, newest first. This is the recovery path when a purchase response is lost on the wire: the number is here, so resume polling it instead of buying another. Free to call.","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["waiting","received","cancelled","expired"]},"description":"Return only numbers in this state."}],"responses":{"200":{"description":"Recent numbers.","content":{"application/json":{"schema":{"type":"object","properties":{"activations":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Pass this to the poll and cancel calls."},"status":{"type":"string","enum":["waiting","received","cancelled","expired"],"description":"'waiting' — the hold is open and no code has arrived. 'received' — a code (or an SMS body) landed and the wallet was charged. 'cancelled'/'expired' — the hold was released in full."},"phone_number":{"type":"string"},"service":{"type":"string"},"service_name":{"type":["string","null"]},"country":{"type":"string"},"country_name":{"type":["string","null"]},"server":{"type":"string","enum":["server-1","server-1","server-1"],"description":"Which server the number came from."},"price":{"type":"number","description":"NGN held in escrow. Only debited for real once status is 'received'."},"currency":{"type":"string","enum":["NGN"]},"charged":{"type":"boolean","description":"True once the hold has settled into an actual wallet charge."},"otp_code":{"type":["string","null"],"description":"The parsed verification code, when one could be extracted."},"sms_text":{"type":["string","null"],"description":"The full SMS body. Some messages carry no parseable code — this is still a delivery and is still charged."},"expires_at":{"type":["string","null"],"format":"date-time","description":"When the number stops accepting SMS and the hold is released."},"created_at":{"type":"string","format":"date-time"},"resends":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["waiting","received","expired"]},"price":{"type":"number"},"charged":{"type":"boolean"},"otp_code":{"type":["string","null"]},"sms_text":{"type":["string","null"]},"expires_at":{"type":["string","null"],"format":"date-time"},"created_at":{"type":"string","format":"date-time"}}},"description":"Paid re-requests on this number, oldest first."},"poll_after_ms":{"type":["integer","null"],"description":"Milliseconds to wait before reading this resource again, or null once nothing further can change."}},"required":["id","status","phone_number","price","currency","charged"]}}},"required":["activations"]}}}},"400":{"description":"Invalid 'limit'.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"401":{"description":"Missing, malformed, revoked or unknown API key.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"429":{"description":"Per-key rate limit exceeded.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"502":{"description":"Upstream provider failed. You were not charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}}},"/verify/activations/{id}":{"get":{"tags":["Numbers"],"operationId":"getVerifyActivation","summary":"Poll a number for its code","description":"Reading a number is what advances it: when a code lands the escrow settles into a real charge, and when the window closes the hold is released. Keep calling while 'poll_after_ms' is non-null. Free to call, but each call counts against the key's rate limit — respect 'poll_after_ms' rather than polling flat out.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"The Onedex id returned when the number was bought."}],"responses":{"200":{"description":"Current state of the number.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"Pass this to the poll and cancel calls."},"status":{"type":"string","enum":["waiting","received","cancelled","expired"],"description":"'waiting' — the hold is open and no code has arrived. 'received' — a code (or an SMS body) landed and the wallet was charged. 'cancelled'/'expired' — the hold was released in full."},"phone_number":{"type":"string"},"service":{"type":"string"},"service_name":{"type":["string","null"]},"country":{"type":"string"},"country_name":{"type":["string","null"]},"server":{"type":"string","enum":["server-1","server-1","server-1"],"description":"Which server the number came from."},"price":{"type":"number","description":"NGN held in escrow. Only debited for real once status is 'received'."},"currency":{"type":"string","enum":["NGN"]},"charged":{"type":"boolean","description":"True once the hold has settled into an actual wallet charge."},"otp_code":{"type":["string","null"],"description":"The parsed verification code, when one could be extracted."},"sms_text":{"type":["string","null"],"description":"The full SMS body. Some messages carry no parseable code — this is still a delivery and is still charged."},"expires_at":{"type":["string","null"],"format":"date-time","description":"When the number stops accepting SMS and the hold is released."},"created_at":{"type":"string","format":"date-time"},"resends":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["waiting","received","expired"]},"price":{"type":"number"},"charged":{"type":"boolean"},"otp_code":{"type":["string","null"]},"sms_text":{"type":["string","null"]},"expires_at":{"type":["string","null"],"format":"date-time"},"created_at":{"type":"string","format":"date-time"}}},"description":"Paid re-requests on this number, oldest first."},"poll_after_ms":{"type":["integer","null"],"description":"Milliseconds to wait before reading this resource again, or null once nothing further can change."}},"required":["id","status","phone_number","price","currency","charged"]}}}},"401":{"description":"Missing, malformed, revoked or unknown API key.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"404":{"description":"No number with that id on this account.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"429":{"description":"Per-key rate limit exceeded.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"502":{"description":"Upstream provider failed. You were not charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}}},"/verify/activations/{id}/cancel":{"post":{"tags":["Numbers"],"operationId":"cancelVerifyActivation","summary":"Cancel a waiting number","description":"Hands the number back and releases the whole hold. Because a cancelled number is never charged, 'refunded' here is a released hold and no transaction is written. Only numbers still in 'waiting' can be cancelled — once a code has landed the purchase is settled and final.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"The Onedex id returned when the number was bought."}],"responses":{"200":{"description":"Cancelled and released.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["cancelled"]},"refunded":{"type":"number"},"currency":{"type":"string","enum":["NGN"]}},"required":["id","status","refunded"]}}}},"400":{"description":"This number is no longer in 'waiting'.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"401":{"description":"Missing, malformed, revoked or unknown API key.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"404":{"description":"No number with that id on this account.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"429":{"description":"Per-key rate limit exceeded.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"502":{"description":"Upstream provider failed. You were not charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}}},"/verify/activations/{id}/resend":{"post":{"tags":["Numbers"],"operationId":"resendVerifyActivation","summary":"Request another SMS","description":"Asks the same number for another SMS. Free while the first code is still outstanding ('charged': false — the original hold covers it). Once a code has landed and settled, this is a new purchase at the same price with its own hold and window; poll the activation and watch it resolve under 'resends'. Not every upstream supports this.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"The Onedex id returned when the number was bought."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"A unique value per purchase — a UUID is ideal. The first request stores its result; repeats replay it with an 'Idempotent-Replay: true' header instead of spending again. Scoped to your account, expires after 24 hours."}],"responses":{"200":{"description":"Another SMS was requested.","content":{"application/json":{"schema":{"type":"object","properties":{"activation_id":{"type":"string"},"charged":{"type":"boolean","description":"False when the original hold already covers this SMS."},"price":{"type":"number"},"currency":{"type":"string","enum":["NGN"]},"resend_id":{"type":["string","null"]}},"required":["activation_id","charged"]}}}},"400":{"description":"The number is no longer active, or its upstream cannot resend — cancel for the hold back and buy a new one.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"401":{"description":"Missing, malformed, revoked or unknown API key.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"402":{"description":"Insufficient wallet balance. You were not charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"404":{"description":"No number with that id on this account.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"409":{"description":"Another SMS is already on the way for this number.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"429":{"description":"Per-key rate limit exceeded.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"502":{"description":"Upstream provider failed. You were not charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"503":{"description":"The request could not be started. You were not charged — safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}}},"/verify/rentals/catalog":{"get":{"tags":["Numbers"],"operationId":"listRentalCatalog","summary":"List rentable countries","description":"Countries available for long-term rental with their day-durations, priced in NGN including the account's Premium discount. Use a country's 'id' as 'line_id' when renting. Free to call.","responses":{"200":{"description":"Rentable countries.","content":{"application/json":{"schema":{"type":"object","properties":{"countries":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Send this as 'line_id' to rent."},"name":{"type":"string"},"country_short":{"type":"string"},"region":{"type":"string"},"count":{"type":"integer"},"durations":{"type":"array","items":{"type":"object","properties":{"days":{"type":"integer"},"price":{"type":"number"},"currency":{"type":"string","enum":["NGN"]}}}}}}}},"required":["countries"]}}}},"401":{"description":"Missing, malformed, revoked or unknown API key.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"429":{"description":"Per-key rate limit exceeded.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"502":{"description":"Upstream provider failed. You were not charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}}},"/verify/rentals":{"post":{"tags":["Numbers"],"operationId":"rentVerifyNumber","summary":"Rent a long-term number","description":"Rents a number for a fixed number of days. Unlike a one-time number there is no escrow: the full price is debited immediately and is NOT refundable — the line is yours for the whole window whether or not any SMS arrives. Read its inbox with GET /verify/rentals/{id}.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"A unique value per purchase — a UUID is ideal. The first request stores its result; repeats replay it with an 'Idempotent-Replay: true' header instead of spending again. Scoped to your account, expires after 24 hours."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"line_id":{"type":"string","description":"A country 'id' from /verify/rentals/catalog."},"days":{"type":"integer","minimum":1,"description":"A duration offered for that country."},"country_name":{"type":"string","description":"Optional label stored with the rental."},"country_short":{"type":"string","description":"Optional label stored with the rental."}},"required":["line_id","days"]}}}},"responses":{"200":{"description":"Rental issued and charged in full.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["active","finished","expired"]},"phone_number":{"type":"string"},"country":{"type":"string"},"country_name":{"type":["string","null"]},"days":{"type":"integer","description":"Length of the rented window."},"price":{"type":"number","description":"NGN debited in full at purchase. Rentals are never refunded."},"currency":{"type":"string","enum":["NGN"]},"sms_count":{"type":"integer"},"messages":{"type":"array","description":"Every SMS received during the window, oldest first.","items":{"type":"object","properties":{"sender":{"type":"string"},"text":{"type":"string"},"code":{"type":["string","null"]},"received_at":{"type":"string"}}}},"expires_at":{"type":"string","format":"date-time"},"created_at":{"type":"string","format":"date-time"},"poll_after_ms":{"type":["integer","null"],"description":"Milliseconds to wait before reading this resource again, or null once nothing further can change."}},"required":["id","status","phone_number","price","currency"]}}}},"400":{"description":"Malformed request or failed validation.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"401":{"description":"Missing, malformed, revoked or unknown API key.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"402":{"description":"Insufficient wallet balance. You were not charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"409":{"description":"A request with this Idempotency-Key is still in flight. Retry the same key shortly to read its result.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"422":{"description":"This Idempotency-Key was already used with a different request body. Use a new key for a new purchase.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"429":{"description":"Per-key rate limit exceeded.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"502":{"description":"Upstream provider failed. You were not charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"503":{"description":"The number could not be recorded and was rolled back in full — the hold was released and the number handed back. Nothing was charged; safe to retry with the same Idempotency-Key.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}},"get":{"tags":["Numbers"],"operationId":"listVerifyRentals","summary":"List recent rentals","description":"Your recent rentals, newest first — the recovery path for a purchase whose response was lost. Inboxes are not included; read one rental to fetch its messages. Free to call.","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["active","finished","expired"]},"description":"Return only rentals in this state."}],"responses":{"200":{"description":"Recent rentals.","content":{"application/json":{"schema":{"type":"object","properties":{"rentals":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["active","finished","expired"]},"phone_number":{"type":"string"},"country":{"type":"string"},"country_name":{"type":["string","null"]},"days":{"type":"integer","description":"Length of the rented window."},"price":{"type":"number","description":"NGN debited in full at purchase. Rentals are never refunded."},"currency":{"type":"string","enum":["NGN"]},"sms_count":{"type":"integer"},"messages":{"type":"array","description":"Every SMS received during the window, oldest first.","items":{"type":"object","properties":{"sender":{"type":"string"},"text":{"type":"string"},"code":{"type":["string","null"]},"received_at":{"type":"string"}}}},"expires_at":{"type":"string","format":"date-time"},"created_at":{"type":"string","format":"date-time"},"poll_after_ms":{"type":["integer","null"],"description":"Milliseconds to wait before reading this resource again, or null once nothing further can change."}},"required":["id","status","phone_number","price","currency"]}}},"required":["rentals"]}}}},"400":{"description":"Invalid 'limit'.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"401":{"description":"Missing, malformed, revoked or unknown API key.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"429":{"description":"Per-key rate limit exceeded.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"502":{"description":"Upstream provider failed. You were not charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}}},"/verify/rentals/{id}":{"get":{"tags":["Numbers"],"operationId":"getVerifyRental","summary":"Read a rental and its inbox","description":"Returns the rental with every SMS received during its window, oldest first, so you can match codes to whatever you sent. Keep calling while 'poll_after_ms' is non-null; once the paid window closes the rental flips to 'expired' and stops receiving.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"The Onedex id returned when the number was bought."}],"responses":{"200":{"description":"Current state of the rental, with its messages.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["active","finished","expired"]},"phone_number":{"type":"string"},"country":{"type":"string"},"country_name":{"type":["string","null"]},"days":{"type":"integer","description":"Length of the rented window."},"price":{"type":"number","description":"NGN debited in full at purchase. Rentals are never refunded."},"currency":{"type":"string","enum":["NGN"]},"sms_count":{"type":"integer"},"messages":{"type":"array","description":"Every SMS received during the window, oldest first.","items":{"type":"object","properties":{"sender":{"type":"string"},"text":{"type":"string"},"code":{"type":["string","null"]},"received_at":{"type":"string"}}}},"expires_at":{"type":"string","format":"date-time"},"created_at":{"type":"string","format":"date-time"},"poll_after_ms":{"type":["integer","null"],"description":"Milliseconds to wait before reading this resource again, or null once nothing further can change."}},"required":["id","status","phone_number","price","currency"]}}}},"401":{"description":"Missing, malformed, revoked or unknown API key.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"404":{"description":"No rental with that id on this account.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"429":{"description":"Per-key rate limit exceeded.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"502":{"description":"Upstream provider failed. You were not charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}}},"/verify/rentals/{id}/finish":{"post":{"tags":["Numbers"],"operationId":"finishVerifyRental","summary":"End a rental early","description":"Releases the line upstream and closes the rental. There is NO refund — the window was paid for at purchase, so 'refunded' is always 0. Use this when you're done with a number, not to undo a rental.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"The Onedex id returned when the number was bought."}],"responses":{"200":{"description":"Rental closed.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["finished"]},"refunded":{"type":"number","enum":[0]},"currency":{"type":"string","enum":["NGN"]}},"required":["id","status"]}}}},"400":{"description":"This rental is not active.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"401":{"description":"Missing, malformed, revoked or unknown API key.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"404":{"description":"No rental with that id on this account.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"429":{"description":"Per-key rate limit exceeded.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"502":{"description":"Upstream provider failed. You were not charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}}},"/checkmark/listings":{"get":{"tags":["Checkmark"],"operationId":"listCheckmarkListings","summary":"List checkmark listings","description":"Active verification listings in NGN with the account's Premium discount already applied. Free to call. Read-only: requests are fulfilled by hand and credential-type listings take an account password, so ordering stays in the dashboard.","responses":{"200":{"description":"Active listings.","content":{"application/json":{"schema":{"type":"object","properties":{"listings":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"platform":{"type":"string"},"title":{"type":"string"},"description":{"type":"string","nullable":true},"image_url":{"type":"string","nullable":true},"verification_type":{"type":"string","enum":["username","credentials"]},"price":{"type":"number"},"currency":{"type":"string","enum":["NGN"]}}}}},"required":["listings"]}}}},"401":{"description":"Missing, malformed, revoked or unknown API key.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"429":{"description":"Per-key rate limit exceeded.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"502":{"description":"Upstream provider failed. You were not charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}}},"/topup/listings":{"get":{"tags":["Subscriptions"],"operationId":"listTopupListings","summary":"List subscription listings","description":"Active subscription and top-up listings in NGN with the account's Premium discount already applied. Free to call. An id from here is what POST /topup/orders is placed against.","responses":{"200":{"description":"Active listings.","content":{"application/json":{"schema":{"type":"object","properties":{"listings":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"platform":{"type":"string"},"title":{"type":"string"},"description":{"type":"string","nullable":true},"instructions":{"type":"string","nullable":true,"description":"What the buyer must supply as the account for this listing (player ID, profile link, login email …)."},"image_url":{"type":"string","nullable":true},"price":{"type":"number"},"currency":{"type":"string","enum":["NGN"]}}}}},"required":["listings"]}}}},"401":{"description":"Missing, malformed, revoked or unknown API key.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"429":{"description":"Per-key rate limit exceeded.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"502":{"description":"Upstream provider failed. You were not charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}}},"/topup/orders":{"post":{"tags":["Subscriptions"],"operationId":"createTopupOrder","summary":"Order a subscription top-up","description":"Places a subscription request against a listing. Nothing is charged: the discounted listing price is held in escrow and only becomes a real charge once the request is fulfilled — a rejected request hands the whole hold back. Fulfilment is manual, so this returns a 'processing' request, not a finished purchase; poll GET /topup/orders/{id} while poll_after_ms is non-null. Send an Idempotency-Key so a retry after a timeout replays the same request instead of placing a second one.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"A unique value per purchase — a UUID is ideal. The first request stores its result; repeats replay it with an 'Idempotent-Replay: true' header instead of spending again. Scoped to your account, expires after 24 hours."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"listing_id":{"type":"string","description":"An id from /topup/listings."},"listingId":{"type":"string","description":"Accepted alias for listing_id."},"account":{"type":"string","description":"The account to top up — email, phone, username or player id. What exactly to send is in the listing's 'instructions' field."},"contact":{"type":"string","description":"Email, phone or WhatsApp we can reach the buyer on if the request needs a question answered."}},"required":["listing_id","account","contact"]}}}},"responses":{"200":{"description":"Request submitted, price held in escrow.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"Pass this to the poll call."},"status":{"type":"string","enum":["processing","completed","failed"]},"listing_id":{"type":["string","null"]},"platform":{"type":["string","null"]},"title":{"type":["string","null"]},"account":{"type":"string"},"contact":{"type":["string","null"]},"price":{"type":"number","description":"NGN held in escrow."},"currency":{"type":"string","enum":["NGN"]},"charged":{"type":"boolean","description":"True only once the request completed. Until then the price is a hold, not a charge."},"notes":{"type":["string","null"],"description":"What the fulfilling admin wrote — typically the reason a request failed."},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":["string","null"],"format":"date-time"},"poll_after_ms":{"type":["integer","null"],"description":"Milliseconds to wait before reading this resource again, or null once nothing further can change."}},"required":["id","status","price","currency","charged"]}}}},"400":{"description":"Malformed request, missing account/contact, or an unknown or inactive listing_id.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"401":{"description":"Missing, malformed, revoked or unknown API key.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"402":{"description":"Insufficient wallet balance. Nothing was held.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"409":{"description":"A request with this Idempotency-Key is still in flight. Retry shortly to read its result.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"422":{"description":"This Idempotency-Key was already used with a different request body.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"429":{"description":"Per-key rate limit exceeded.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"502":{"description":"Upstream provider failed. You were not charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"503":{"description":"The request could not be recorded and the hold was released in full. You were not charged — safe to retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}},"get":{"tags":["Subscriptions"],"operationId":"listTopupOrders","summary":"List subscription requests","description":"Your recent subscription requests, newest first. This is the recovery path for a submission whose response was lost: it still shows up here, so resume polling it instead of paying twice. Free to call.","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"description":"How many requests to return. Clamped to 100."},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["processing","completed","failed"]},"description":"Return only requests in this state."}],"responses":{"200":{"description":"Recent requests.","content":{"application/json":{"schema":{"type":"object","properties":{"orders":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Pass this to the poll call."},"status":{"type":"string","enum":["processing","completed","failed"]},"listing_id":{"type":["string","null"]},"platform":{"type":["string","null"]},"title":{"type":["string","null"]},"account":{"type":"string"},"contact":{"type":["string","null"]},"price":{"type":"number","description":"NGN held in escrow."},"currency":{"type":"string","enum":["NGN"]},"charged":{"type":"boolean","description":"True only once the request completed. Until then the price is a hold, not a charge."},"notes":{"type":["string","null"],"description":"What the fulfilling admin wrote — typically the reason a request failed."},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":["string","null"],"format":"date-time"},"poll_after_ms":{"type":["integer","null"],"description":"Milliseconds to wait before reading this resource again, or null once nothing further can change."}},"required":["id","status","price","currency","charged"]}}},"required":["orders"]}}}},"400":{"description":"limit or status failed validation.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"401":{"description":"Missing, malformed, revoked or unknown API key.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"429":{"description":"Per-key rate limit exceeded.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"502":{"description":"Upstream provider failed. You were not charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}}},"/topup/orders/{id}":{"get":{"tags":["Subscriptions"],"operationId":"getTopupOrder","summary":"Poll a subscription request","description":"Reads one request. Unlike a verification number, this call moves no money — it only reports where a human got to. 'processing' means still in the queue; 'completed' with charged: true is the end of the happy path; 'failed' means the hold went back untouched and 'notes' says why. Free to call.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"The Onedex id returned when the request was placed."}],"responses":{"200":{"description":"The request.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"Pass this to the poll call."},"status":{"type":"string","enum":["processing","completed","failed"]},"listing_id":{"type":["string","null"]},"platform":{"type":["string","null"]},"title":{"type":["string","null"]},"account":{"type":"string"},"contact":{"type":["string","null"]},"price":{"type":"number","description":"NGN held in escrow."},"currency":{"type":"string","enum":["NGN"]},"charged":{"type":"boolean","description":"True only once the request completed. Until then the price is a hold, not a charge."},"notes":{"type":["string","null"],"description":"What the fulfilling admin wrote — typically the reason a request failed."},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":["string","null"],"format":"date-time"},"poll_after_ms":{"type":["integer","null"],"description":"Milliseconds to wait before reading this resource again, or null once nothing further can change."}},"required":["id","status","price","currency","charged"]}}}},"401":{"description":"Missing, malformed, revoked or unknown API key.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"404":{"description":"No such request on this account.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"429":{"description":"Per-key rate limit exceeded.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"502":{"description":"Upstream provider failed. You were not charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}}},"/boost/servers":{"get":{"tags":["Boost"],"operationId":"listBoostServers","summary":"List boost servers","description":"The boost panels available to your account. Each carries its own catalog and prices, so read the catalog on the server you intend to order from. Free to call.","responses":{"200":{"description":"Configured servers.","content":{"application/json":{"schema":{"type":"object","properties":{"servers":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","enum":["server-1","server-2"]},"label":{"type":"string"}}}}},"required":["servers"]}}}},"401":{"description":"Missing, malformed, revoked or unknown API key.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"429":{"description":"Per-key rate limit exceeded.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"502":{"description":"Upstream provider failed. You were not charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}}},"/boost/services":{"get":{"tags":["Boost"],"operationId":"listBoostServices","summary":"List boost services","description":"One server's catalog in NGN with the account's Premium discount already applied. Rates are per 1000 units: an order costs quantity / 1000 × rate_per_1000. Every entry carries the extra inputs its type needs in 'requires', and 'quantity_from' when the quantity is derived from a list rather than sent. A catalog runs to thousands of entries — narrow it with category and search rather than pulling all of it before every order. Free to call.","parameters":[{"name":"server","in":"query","required":false,"schema":{"type":"string","enum":["server-1","server-2"]},"description":"Which server to read. Defaults to the primary. Each server has its own catalog, prices and minimums, so a service id is only valid on the server it was read from. An unrecognised value is rejected rather than silently defaulted."},{"name":"category","in":"query","required":false,"schema":{"type":"string"},"description":"Exact category match, e.g. 'Instagram Followers'."},{"name":"search","in":"query","required":false,"schema":{"type":"string"},"description":"Case-insensitive substring match on the service name."}],"responses":{"200":{"description":"Matching services.","content":{"application/json":{"schema":{"type":"object","properties":{"services":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer","description":"Pass as service_id. Only valid on this server."},"name":{"type":"string"},"category":{"type":"string"},"type":{"type":"string","description":"Panel service type — Default, Custom Comments, Mentions, Poll …"},"min":{"type":"integer"},"max":{"type":"integer"},"rate_per_1000":{"type":"number"},"currency":{"type":"string","enum":["NGN"]},"requires":{"type":"array","items":{"type":"string","enum":["comments","usernames","hashtag","username","answer_number"]},"description":"Extra fields this service needs on top of link and quantity."},"quantity_from":{"type":["string","null"],"enum":["comments","usernames",null],"description":"When set, do NOT send quantity — it is the number of lines in this list."}}}}},"required":["services"]}}}},"400":{"description":"Unknown server.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"401":{"description":"Missing, malformed, revoked or unknown API key.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"429":{"description":"Per-key rate limit exceeded.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"502":{"description":"Upstream provider failed. You were not charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"503":{"description":"The panel's catalog is unavailable right now.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}}},"/boost/orders":{"post":{"tags":["Boost"],"operationId":"createBoostOrder","summary":"Place a boost order","description":"Debits the wallet in full and submits the order to the panel. There is no escrow here: if the panel rejects the order the debit is reversed and nothing is recorded, but once accepted the money is spent and only comes back as a proportional refund for undelivered units. Delivery is never instant — a 200 means accepted and running, so poll GET /boost/orders/{id} while poll_after_ms is non-null. Send an Idempotency-Key: a replayed order is a second paid order.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"A unique value per purchase — a UUID is ideal. The first request stores its result; repeats replay it with an 'Idempotent-Replay: true' header instead of spending again. Scoped to your account, expires after 24 hours."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"service_id":{"type":"integer","description":"An id from /boost/services on the same server."},"link":{"type":"string","description":"The profile, post or video URL to deliver to."},"quantity":{"type":"integer","description":"Units to deliver, within the service's min and max. Omit for services with a quantity_from list."},"server":{"type":"string","enum":["server-1","server-2"],"description":"Defaults to the primary server."},"comments":{"type":["array","string"],"items":{"type":"string"},"description":"Custom Comments services: one comment per array entry (or per line). The quantity is the count."},"usernames":{"type":["array","string"],"items":{"type":"string"},"description":"Custom-list Mentions services: one username per array entry (or per line). The quantity is the count."},"hashtag":{"type":"string","description":"Hashtag-targeted Mentions services."},"username":{"type":"string","description":"Mentions services that pull from a profile's followers."},"answer_number":{"type":"string","description":"Poll services: which answer to vote for."}},"required":["service_id","link"]}}}},"responses":{"200":{"description":"Order accepted by the panel and charged.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"Pass this to the poll, cancel and refill calls."},"status":{"type":"string","description":"As last reported by the panel: Pending, In progress, Processing, Completed, Partial or Canceled."},"server":{"type":"string","enum":["server-1","server-2"]},"service_id":{"type":"integer"},"service_name":{"type":["string","null"]},"category":{"type":["string","null"]},"link":{"type":"string"},"quantity":{"type":"integer","description":"Units ordered. For list-driven services this is the number of lines you sent, not a value you chose."},"charge":{"type":"number","description":"NGN debited when the order was placed."},"refunded":{"type":"number","description":"NGN credited back so far for undelivered units. charge − refunded is what the order actually cost."},"currency":{"type":"string","enum":["NGN"]},"start_count":{"type":["integer","null"],"description":"The counter's value when the panel started, once it reports one."},"remains":{"type":["integer","null"],"description":"Units still undelivered, as last reported."},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":["string","null"],"format":"date-time"},"poll_after_ms":{"type":["integer","null"],"description":"Milliseconds to wait before reading this resource again, or null once nothing further can change."}},"required":["id","status","quantity","charge","currency"]}}}},"400":{"description":"Malformed request, a missing type-specific field, a quantity outside the service's min/max, an unknown server, insufficient balance, or the panel refused the order. Nothing was charged — a debit taken before a panel refusal is reversed in full.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"401":{"description":"Missing, malformed, revoked or unknown API key.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"404":{"description":"No such service_id on this server.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"409":{"description":"A request with this Idempotency-Key is still in flight. Retry shortly to read its result.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"422":{"description":"This Idempotency-Key was already used with a different request body.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"429":{"description":"Per-key rate limit exceeded.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"500":{"description":"The order is live at the panel but could not be recorded. Contact support with the Idempotency-Key rather than retrying.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"502":{"description":"Upstream provider failed. You were not charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"503":{"description":"The panel is unreachable. Nothing was charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}},"get":{"tags":["Boost"],"operationId":"listBoostOrders","summary":"List boost orders","description":"Your recent boost orders, newest first — the recovery path for an order whose response was lost. Statuses are whatever the panel last reported; this read does not poll upstream, so read one order to refresh it. Free to call.","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"description":"How many orders to return. Clamped to 100."},{"name":"status","in":"query","required":false,"schema":{"type":"string"},"description":"Exact status match, e.g. 'Completed', 'In progress', 'Partial', 'Canceled'."}],"responses":{"200":{"description":"Recent orders.","content":{"application/json":{"schema":{"type":"object","properties":{"orders":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Pass this to the poll, cancel and refill calls."},"status":{"type":"string","description":"As last reported by the panel: Pending, In progress, Processing, Completed, Partial or Canceled."},"server":{"type":"string","enum":["server-1","server-2"]},"service_id":{"type":"integer"},"service_name":{"type":["string","null"]},"category":{"type":["string","null"]},"link":{"type":"string"},"quantity":{"type":"integer","description":"Units ordered. For list-driven services this is the number of lines you sent, not a value you chose."},"charge":{"type":"number","description":"NGN debited when the order was placed."},"refunded":{"type":"number","description":"NGN credited back so far for undelivered units. charge − refunded is what the order actually cost."},"currency":{"type":"string","enum":["NGN"]},"start_count":{"type":["integer","null"],"description":"The counter's value when the panel started, once it reports one."},"remains":{"type":["integer","null"],"description":"Units still undelivered, as last reported."},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":["string","null"],"format":"date-time"},"poll_after_ms":{"type":["integer","null"],"description":"Milliseconds to wait before reading this resource again, or null once nothing further can change."}},"required":["id","status","quantity","charge","currency"]}}},"required":["orders"]}}}},"400":{"description":"limit failed validation.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"401":{"description":"Missing, malformed, revoked or unknown API key.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"429":{"description":"Per-key rate limit exceeded.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"502":{"description":"Upstream provider failed. You were not charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}}},"/boost/orders/{id}":{"get":{"tags":["Boost"],"operationId":"getBoostOrder","summary":"Poll a boost order","description":"Pulls the live status from the panel, stores it, and settles any refund the order is owed — so polling is what puts money back in the wallet when an order is cancelled or ends Partial. Safe to call repeatedly; a refund can never be issued twice. Free to call.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"The Onedex id returned when the order was placed."}],"responses":{"200":{"description":"The order, with its live status.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"Pass this to the poll, cancel and refill calls."},"status":{"type":"string","description":"As last reported by the panel: Pending, In progress, Processing, Completed, Partial or Canceled."},"server":{"type":"string","enum":["server-1","server-2"]},"service_id":{"type":"integer"},"service_name":{"type":["string","null"]},"category":{"type":["string","null"]},"link":{"type":"string"},"quantity":{"type":"integer","description":"Units ordered. For list-driven services this is the number of lines you sent, not a value you chose."},"charge":{"type":"number","description":"NGN debited when the order was placed."},"refunded":{"type":"number","description":"NGN credited back so far for undelivered units. charge − refunded is what the order actually cost."},"currency":{"type":"string","enum":["NGN"]},"start_count":{"type":["integer","null"],"description":"The counter's value when the panel started, once it reports one."},"remains":{"type":["integer","null"],"description":"Units still undelivered, as last reported."},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":["string","null"],"format":"date-time"},"poll_after_ms":{"type":["integer","null"],"description":"Milliseconds to wait before reading this resource again, or null once nothing further can change."}},"required":["id","status","quantity","charge","currency"]}}}},"400":{"description":"This order was never accepted by the panel.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"401":{"description":"Missing, malformed, revoked or unknown API key.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"404":{"description":"No such order on this account.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"429":{"description":"Per-key rate limit exceeded.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"502":{"description":"Upstream provider failed. You were not charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}}},"/boost/orders/{id}/cancel":{"post":{"tags":["Boost"],"operationId":"cancelBoostOrder","summary":"Cancel a boost order","description":"Asks the panel to cancel. Cancellation is the panel's call: a 409 means it refused (already in progress, or a non-cancellable service) and the order keeps running with nothing refunded. When accepted, the refund for undelivered units is issued as soon as the panel reports the order Canceled or Partial — refund_issued says whether that happened here; if it is false, keep polling the order.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"The Onedex id returned when the order was placed."}],"responses":{"200":{"description":"The panel accepted the cancellation.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string"},"refund_issued":{"type":"boolean"},"refund_amount":{"type":"number","description":"NGN credited back by this call."},"currency":{"type":"string","enum":["NGN"]}},"required":["id","status","refund_issued"]}}}},"401":{"description":"Missing, malformed, revoked or unknown API key.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"404":{"description":"No such order on this account.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"409":{"description":"The panel refused to cancel. The order is unchanged and nothing was refunded.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"429":{"description":"Per-key rate limit exceeded.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"502":{"description":"Upstream provider failed. You were not charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}}},"/boost/orders/{id}/refill":{"post":{"tags":["Boost"],"operationId":"refillBoostOrder","summary":"Request a refill","description":"Asks the panel to top a delivered order back up after drops. Free — no wallet movement either way. Only some services offer refills, and only inside their window, so a 409 with the panel's reason is a normal outcome.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"The Onedex id returned when the order was placed."}],"responses":{"200":{"description":"Refill requested.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"refill_id":{"type":["integer","null"],"description":"The panel's refill id, when it returns one."},"status":{"type":"string","enum":["requested"]}},"required":["id","status"]}}}},"401":{"description":"Missing, malformed, revoked or unknown API key.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"404":{"description":"No such order on this account.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"409":{"description":"The panel refused the refill — not offered for this service, or outside its window.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"429":{"description":"Per-key rate limit exceeded.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"502":{"description":"Upstream provider failed. You were not charged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}}}}}