# VoicePro Plus API v3 > REST API for VoicePro Plus business accounts. Base URL: https://api.voicepro.plus/v3. Auth: Authorization: Bearer . JSON, snake_case, public ids, money in minor units with its currency. Lists take limit and cursor and return next_cursor. Writes take an Idempotency-Key header. A test key (vpkey_test_...) answers every call with these examples and is never charged. Spec: https://voicepro.plus/developers/openapi.json Postman: https://voicepro.plus/developers/voicepro-api-v3.postman_collection.json Docs: https://voicepro.plus/developers MCP server for AI tools: https://api.voicepro.plus/mcp (Streamable HTTP, Authorization: Bearer ) ## Account ### GET /account The workspace this key belongs to, the services on it and the key's own scopes. Needs scope: read ```bash curl -X GET "https://api.voicepro.plus/v3/account" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "account", "id": "acct_AB12CD", "name": "Acme Logistics", "legal_name": "Acme Logistics Ltd", "status": "active", "country": "GB", "timezone": "Europe/London", "currency": "GBP", "parent_account_id": null, "created_at": "2026-10-01T09:00:00Z", "services": { "mobile_sims": { "enabled": true, "count": 12, "active_count": 11 }, "numbers": { "enabled": true, "count": 3 }, "voice_trunk": { "enabled": true }, "sms_route": { "enabled": false }, "iot": { "enabled": true } }, "spending_limit": { "limit": { "amount": 250000, "currency": "GBP" }, "alert_percentages": [ 80, 100 ] }, "sso": { "domain": "example.com", "providers": [ "microsoft" ], "required": false }, "open_invoice_count": 1, "authenticated_as": { "type": "api_key", "key_id": "key_1A2B3C4D", "mode": "live", "scopes": [ "read", "billing:read" ] } } ``` ### GET /sub_accounts Sub-accounts, each with its counts of SIMs, numbers and active members, and whether it has a voice trunk. Needs scope: read ```bash curl -X GET "https://api.voicepro.plus/v3/sub_accounts" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "list", "data": [ { "object": "sub_account", "id": "acct_EF34GH", "name": "Acme Logistics North", "status": "active", "sim_count": 4, "number_count": 1, "voice_trunk": false, "member_count": 5 } ], "has_more": false, "next_cursor": null } ``` ### GET /incidents Open incidents and planned maintenance (next 3 days) affecting this account's services. Needs scope: read ```bash curl -X GET "https://api.voicepro.plus/v3/incidents" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "list", "data": [ { "object": "incident", "id": "inc_20261021a", "title": "Delayed usage figures", "kind": "incident", "impact": "minor", "components": [ "usage" ], "started_at": "2026-10-21T07:40:00Z", "resolved_at": "2026-10-21T08:25:00Z", "status_page_url": "https://status.voicepro.plus" } ], "has_more": false, "next_cursor": null } ``` ## SIMs ### GET /sims Mobile SIMs with this month's usage. Needs scope: read ```bash curl -X GET "https://api.voicepro.plus/v3/sims?status=active" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "list", "data": [ { "object": "sim", "id": "sim_K7M2Q9", "label": "Warehouse van 3", "plan_name": "Business+ Essentials", "add_ons": [ "EU Roaming" ], "iccid": "8944500102345678901", "phone_number": "+447700900123", "country": "GB", "status": "active", "holder_name": "Sam Taylor", "data_cap_gb": 30, "created_at": "2026-10-02T09:14:00Z", "activated_at": "2026-10-02T11:40:00Z", "month_to_date": { "data_bytes": 4831838208, "roaming_bytes": 214748364, "calls": 42, "sms": 17, "countries": [ "GB", "FR" ] }, "data_as_of": "2026-10-28T08:55:00Z" } ], "has_more": false, "next_cursor": null } ``` ### POST /sims Add a business mobile SIM line. Needs scope: sims:write ```bash curl -X POST "https://api.voicepro.plus/v3/sims" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" \ -H "Content-Type: application/json" -H "Idempotency-Key: " \ -d '{"label":"Field ops, Berlin lead","plan":"elite","add_ons":["travel_data"]}' ``` Response: ```json { "object": "sim", "id": "sim_N4P8R2", "label": "Field ops, Berlin lead", "plan_name": "Business+ Elite", "add_ons": [ "Travel data add-on" ], "iccid": null, "phone_number": null, "country": "GB", "status": "active", "holder_name": null, "data_cap_gb": null, "created_at": "2026-10-29T11:00:00Z", "activated_at": "2026-10-29T11:00:00Z", "month_to_date": { "data_bytes": 0, "roaming_bytes": 0, "calls": 0, "sms": 0, "countries": [] }, "data_as_of": null } ``` ### GET /sims/{id} One mobile SIM. Needs scope: read ```bash curl -X GET "https://api.voicepro.plus/v3/sims/sim_K7M2Q9" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "sim", "id": "sim_K7M2Q9", "label": "Warehouse van 3", "plan_name": "Business+ Essentials", "add_ons": [ "EU Roaming" ], "iccid": "8944500102345678901", "phone_number": "+447700900123", "country": "GB", "status": "active", "holder_name": "Sam Taylor", "data_cap_gb": 30, "created_at": "2026-10-02T09:14:00Z", "activated_at": "2026-10-02T11:40:00Z", "month_to_date": { "data_bytes": 4831838208, "roaming_bytes": 214748364, "calls": 42, "sms": 17, "countries": [ "GB", "FR" ] }, "data_as_of": "2026-10-28T08:55:00Z" } ``` ### GET /sims/{id}/usage Usage for a time range (at most 400 days). Needs scope: read ```bash curl -X GET "https://api.voicepro.plus/v3/sims/sim_K7M2Q9/usage?from=2026-10-01T00%3A00%3A00Z&to=2026-10-28T00%3A00%3A00Z&step=1d" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "sim_usage", "sim_id": "sim_K7M2Q9", "range": { "from": "2026-10-01T00:00:00Z", "to": "2026-10-28T00:00:00Z", "step": "1d", "timezone": "Europe/London" }, "totals": { "data_bytes": 4831838208, "roaming_bytes": 214748364, "calls": 42, "call_seconds": 5210, "sms": 17 }, "previous": { "data_bytes": 3951369912, "roaming_bytes": 0, "calls": 38, "call_seconds": 4480, "sms": 21 }, "series": [ { "t": "2026-10-26T00:00:00Z", "data_bytes": 187695104, "calls": 3, "sms": 1 }, { "t": "2026-10-27T00:00:00Z", "data_bytes": 201326592, "calls": 2, "sms": 0 } ], "by_country": [ { "country": "GB", "data_bytes": 4617089843 }, { "country": "FR", "data_bytes": 214748365 } ], "data_as_of": "2026-10-28T08:55:00Z" } ``` ### POST /sims/{id}/suspend Suspend a SIM on the network: no calls, texts or data until it is reactivated. Needs scope: sims:write ```bash curl -X POST "https://api.voicepro.plus/v3/sims/sim_K7M2Q9/suspend" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "sim_state", "sim_id": "sim_K7M2Q9", "status": "suspended" } ``` ### POST /sims/{id}/reactivate Reactivate a suspended SIM. Needs scope: sims:write ```bash curl -X POST "https://api.voicepro.plus/v3/sims/sim_K7M2Q9/reactivate" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "sim_state", "sim_id": "sim_K7M2Q9", "status": "active" } ``` ## IoT SIMs ### GET /iot/sims IoT SIMs. 404 service_not_enabled without IoT. Needs scope: read ```bash curl -X GET "https://api.voicepro.plus/v3/iot/sims" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "list", "data": [ { "object": "iot_sim", "id": "sim_7k2mqqxw4hd3nvbc5rtfz6ya", "iccid": "8944501234567890123", "label": "Trailer tracker 12", "activated": true, "online": true, "network": { "name": "Network GB", "country": "GB", "mcc": "234", "mnc": "10" }, "network_type": "4G", "last_seen_at": "2026-10-28T08:52:11Z", "imei_lock": null, "data_limit": { "total_bytes": 524288000, "period": "monthly", "alert_bytes": 419430400 }, "month_bytes": 73400320, "data_as_of": "2026-10-28T08:55:00Z" } ], "has_more": false, "next_cursor": null } ``` ### GET /iot/sims/{id} One IoT SIM with this month's data. Needs scope: read ```bash curl -X GET "https://api.voicepro.plus/v3/iot/sims/sim_7k2mqqxw4hd3nvbc5rtfz6ya" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "iot_sim", "id": "sim_7k2mqqxw4hd3nvbc5rtfz6ya", "iccid": "8944501234567890123", "label": "Trailer tracker 12", "activated": true, "online": true, "network": { "name": "Network GB", "country": "GB", "mcc": "234", "mnc": "10" }, "network_type": "4G", "last_seen_at": "2026-10-28T08:52:11Z", "imei_lock": null, "data_limit": { "total_bytes": 524288000, "period": "monthly", "alert_bytes": 419430400 }, "month_bytes": 73400320, "data_as_of": "2026-10-28T08:55:00Z" } ``` ### PATCH /iot/sims/{id} Change one SIM: its name, on or off, IMEI lock, data limit or radio technologies. Checked in full before anything is sent; the answer is the SIM afterwards. Needs scope: sims:write ```bash curl -X PATCH "https://api.voicepro.plus/v3/iot/sims/sim_7k2mqqxw4hd3nvbc5rtfz6ya" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" \ -H "Content-Type: application/json" -H "Idempotency-Key: " \ -d '{"label":"Trailer tracker 12 (depot)"}' ``` Response: ```json { "object": "iot_sim", "id": "sim_7k2mqqxw4hd3nvbc5rtfz6ya", "iccid": "8944501234567890123", "label": "Trailer tracker 12 (depot)", "activated": true, "online": true, "network": { "name": "Network GB", "country": "GB", "mcc": "234", "mnc": "10" }, "network_type": "4G", "last_seen_at": "2026-10-28T08:52:11Z", "imei_lock": null, "data_limit": { "total_bytes": 524288000, "period": "monthly", "alert_bytes": 419430400 }, "data_as_of": "2026-10-28T09:01:00Z" } ``` ### GET /iot/sims/{id}/events The network log of one IoT SIM over a time range, newest first: authentication results (allowed or refused, with the network's reason), attaches, data sessions starting, detaches with the session's bytes, and location updates. Default range: the last 7 days; at most 31 days. truncated is true when the range held more than 5,000 network rows (narrow the range). Reads are limited to 10 a minute per account. Needs scope: read ```bash curl -X GET "https://api.voicepro.plus/v3/iot/sims/sim_7k2mqqxw4hd3nvbc5rtfz6ya/events?from=2026-10-27T00%3A00%3A00Z&to=2026-10-28T00%3A00%3A00Z" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "list", "data": [ { "object": "iot_event", "time": "2026-10-28T08:52:11Z", "type": "data_session_start", "outcome": "allowed", "reason": null, "message": null, "network": { "name": "Network GB", "country": "GB", "mcc": "234", "mnc": "10" }, "network_type": "4G", "imei": "356938035643809", "ip": "198.51.100.24", "session_id": "sess_9f2k7m", "upload_bytes": null, "download_bytes": null, "bytes": null, "location": { "cell_id": 52011, "area_code": 1203, "accuracy_m": 350, "lat": 51.5072, "lng": -0.1276 } } ], "has_more": true, "next_cursor": "eyJrIjoiMjAyNi0xMC0yOFQwODo1MjoxMVoifQ" } ``` ### POST /iot/bulk_jobs One change for up to 5,000 of the account's IoT SIMs, run in the background. Needs scope: sims:write ```bash curl -X POST "https://api.voicepro.plus/v3/iot/bulk_jobs" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" \ -H "Content-Type: application/json" -H "Idempotency-Key: " \ -d '{"sim_ids":["sim_7k2mqqxw4hd3nvbc5rtfz6ya","sim_b4nq7zx2kw5rm3dh6ctvfypa"],"change":{"data_limit":{"total_bytes":1073741824,"period":"monthly","alert_bytes":858993459}}}' ``` Response: ```json { "object": "iot_bulk_job", "id": "bulk_3f9a1c7e5b2d4a6c8e0f1a2b", "status": "done", "change": { "data_limit": { "total_bytes": 1073741824, "period": "monthly", "alert_bytes": 858993459 } }, "total": 2, "processed": 2, "succeeded": 2, "failed": 0, "created_at": "2026-10-28T09:10:00Z", "finished_at": "2026-10-28T09:10:04Z" } ``` ### GET /iot/bulk_jobs/{id} One bulk job with its progress. Needs scope: read ```bash curl -X GET "https://api.voicepro.plus/v3/iot/bulk_jobs/bulk_3f9a1c7e5b2d4a6c8e0f1a2b" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "iot_bulk_job", "id": "bulk_3f9a1c7e5b2d4a6c8e0f1a2b", "status": "done", "change": { "data_limit": { "total_bytes": 1073741824, "period": "monthly", "alert_bytes": 858993459 } }, "total": 2, "processed": 2, "succeeded": 2, "failed": 0, "created_at": "2026-10-28T09:10:00Z", "finished_at": "2026-10-28T09:10:04Z" } ``` ### GET /iot/bulk_jobs/{id}/results Each SIM's result, in the order asked: ok, failed with a reason, or pending. CSV with Accept: text/csv. Needs scope: read ```bash curl -X GET "https://api.voicepro.plus/v3/iot/bulk_jobs/bulk_3f9a1c7e5b2d4a6c8e0f1a2b/results" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "list", "data": [ { "object": "iot_bulk_result", "sim_id": "sim_7k2mqqxw4hd3nvbc5rtfz6ya", "iccid": "8944501234567890123", "status": "ok", "reason": null } ], "has_more": false, "next_cursor": null } ``` ### GET /iot/sims/{id}/esim The SIM's eSIM profile state (for example RELEASED, DOWNLOADED, ENABLED); null for a physical SIM. Needs scope: read ```bash curl -X GET "https://api.voicepro.plus/v3/iot/sims/sim_7k2mqqxw4hd3nvbc5rtfz6ya/esim" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "iot_esim", "sim_id": "sim_7k2mqqxw4hd3nvbc5rtfz6ya", "profile_status": null, "data_as_of": "2026-10-28T09:01:00Z" } ``` ### GET /iot/sims/{id}/sms The SIM's last 100 SMS, newest first: time, direction and status. Message text is not kept here; it arrives by the iot.sms webhook. Needs scope: read ```bash curl -X GET "https://api.voicepro.plus/v3/iot/sims/sim_7k2mqqxw4hd3nvbc5rtfz6ya/sms" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "list", "data": [ { "object": "iot_sms", "sim_id": "sim_7k2mqqxw4hd3nvbc5rtfz6ya", "at": "2026-10-28T08:40:12Z", "direction": "to_device", "status": null }, { "object": "iot_sms", "sim_id": "sim_7k2mqqxw4hd3nvbc5rtfz6ya", "at": "2026-10-27T17:02:45Z", "direction": "from_device", "status": null } ], "has_more": false, "next_cursor": null } ``` ### POST /iot/sims/{id}/sms Send a text SMS to the device on an IoT SIM (configuration, wake-up). Needs scope: sms:send ```bash curl -X POST "https://api.voicepro.plus/v3/iot/sims/sim_7k2mqqxw4hd3nvbc5rtfz6ya/sms" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" \ -H "Content-Type: application/json" -H "Idempotency-Key: " \ -d '{"text":"APN=iot.example"}' ``` Response: ```json { "object": "iot_sms", "sim_id": "sim_7k2mqqxw4hd3nvbc5rtfz6ya", "direction": "to_device", "text": "APN=iot.example", "status": "accepted", "accepted_at": "2026-10-29T09:30:00Z" } ``` ### PATCH /iot/sims/{id}/network_list Restrict a SIM to one of your account's network lists, or lift the restriction (name null). Needs scope: sims:write ```bash curl -X PATCH "https://api.voicepro.plus/v3/iot/sims/sim_7k2mqqxw4hd3nvbc5rtfz6ya/network_list" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" \ -H "Content-Type: application/json" -H "Idempotency-Key: " \ -d '{"name":"uk-only"}' ``` Response: ```json { "object": "iot_sim_network_list", "sim_id": "sim_7k2mqqxw4hd3nvbc5rtfz6ya", "network_list": "uk-only" } ``` ### GET /iot/network_lists Your account's network lists: the mobile networks (MCC and MNC) a SIM on the list may use. Lists are set up with our IoT team. Needs scope: read ```bash curl -X GET "https://api.voicepro.plus/v3/iot/network_lists" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "list", "data": [ { "object": "iot_network_list", "name": "uk-only", "networks": [ { "mcc": "234", "mnc": "10" }, { "mcc": "234", "mnc": "15" }, { "mcc": "234", "mnc": "20" }, { "mcc": "234", "mnc": "30" } ] } ], "has_more": false, "next_cursor": null } ``` ## IoT connectors ### PATCH /iot/sims/{id}/connector Send one IoT SIM's traffic through one of your connectors, or through none (connector null). Needs scope: iot:write ```bash curl -X PATCH "https://api.voicepro.plus/v3/iot/sims/sim_7k2mqqxw4hd3nvbc5rtfz6ya/connector" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" \ -H "Content-Type: application/json" -H "Idempotency-Key: " \ -d '{"connector":"acme-ingest"}' ``` Response: ```json { "object": "iot_sim_connector", "sim_id": "sim_7k2mqqxw4hd3nvbc5rtfz6ya", "connector": "acme-ingest" } ``` ### GET /iot/connectors The account's IoT cloud connectors, and the connector types on offer (types). Needs scope: read ```bash curl -X GET "https://api.voicepro.plus/v3/iot/connectors" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "list", "data": [ { "object": "iot_connector", "name": "acme-ingest", "type": "https", "settings": { "url": "https://ingest.example.com/iot" }, "secrets": {}, "passthrough": [ { "protocol": "tcp", "ip": "203.0.113.10", "port": 8883 } ], "sim_count": 12 } ], "has_more": false, "next_cursor": null, "types": [ "https", "tls", "azure_iot_hub", "aws_iot_core" ] } ``` ### POST /iot/connectors Create a cloud connector: device traffic delivered to your HTTPS endpoint, TLS server or Azure IoT Hub, with TLS added in the network. Needs scope: iot:write ```bash curl -X POST "https://api.voicepro.plus/v3/iot/connectors" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" \ -H "Content-Type: application/json" -H "Idempotency-Key: " \ -d '{"name":"acme-ingest","type":"https","settings":{"url":"https://ingest.example.com/iot"},"passthrough":[{"protocol":"tcp","ip":"203.0.113.10","port":8883}]}' ``` Response: ```json { "object": "iot_connector", "name": "acme-ingest", "type": "https", "settings": { "url": "https://ingest.example.com/iot" }, "secrets": {}, "passthrough": [ { "protocol": "tcp", "ip": "203.0.113.10", "port": 8883 } ], "sim_count": 0 } ``` ### GET /iot/connectors/{name} One cloud connector. Needs scope: read ```bash curl -X GET "https://api.voicepro.plus/v3/iot/connectors/acme-ingest" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "iot_connector", "name": "acme-ingest", "type": "https", "settings": { "url": "https://ingest.example.com/iot" }, "secrets": {}, "passthrough": [ { "protocol": "tcp", "ip": "203.0.113.10", "port": 8883 } ], "sim_count": 12 } ``` ### PATCH /iot/connectors/{name} Change a connector's settings, replace a secret or set its passthrough rules. A secret left out is kept. The type and name cannot change. Needs scope: iot:write ```bash curl -X PATCH "https://api.voicepro.plus/v3/iot/connectors/acme-ingest" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" \ -H "Content-Type: application/json" -H "Idempotency-Key: " \ -d '{"settings":{"url":"https://ingest2.example.com/iot"}}' ``` Response: ```json { "object": "iot_connector", "name": "acme-ingest", "type": "https", "settings": { "url": "https://ingest2.example.com/iot" }, "secrets": {}, "passthrough": [ { "protocol": "tcp", "ip": "203.0.113.10", "port": 8883 } ], "sim_count": 12 } ``` ### DELETE /iot/connectors/{name} Delete a connector. Refused (409 state_conflict) while any SIM still uses it. Needs scope: iot:write ```bash curl -X DELETE "https://api.voicepro.plus/v3/iot/connectors/acme-ingest" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "iot_connector", "name": "acme-ingest", "deleted": true } ``` ### POST /iot/connectors/{name}/test Test a connector: an HTTPS connector gets a labelled test POST from our platform; every type shows its recent delivery errors from the network. Needs scope: iot:write ```bash curl -X POST "https://api.voicepro.plus/v3/iot/connectors/acme-ingest/test" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "iot_connector_test", "name": "acme-ingest", "delivered": true, "status": 200, "detail": "Test message delivered.", "recent_errors": [] } ``` ## Numbers ### GET /numbers Phone numbers and their routing. Needs scope: numbers:read ```bash curl -X GET "https://api.voicepro.plus/v3/numbers" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "list", "data": [ { "object": "number", "id": "num_q4zr7mxkp2wd6hnc3tbvfy5a", "phone_number": "+442079460123", "holder_name": "Acme Logistics Ltd", "status": "active", "provisioned_at": "2026-10-05T10:00:00Z", "routing": { "mode": "forward", "forward_to": "+447700900456" } } ], "has_more": false, "next_cursor": null } ``` ### GET /numbers/{id} One number. Needs scope: numbers:read ```bash curl -X GET "https://api.voicepro.plus/v3/numbers/num_q4zr7mxkp2wd6hnc3tbvfy5a" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "number", "id": "num_q4zr7mxkp2wd6hnc3tbvfy5a", "phone_number": "+442079460123", "holder_name": "Acme Logistics Ltd", "status": "active", "provisioned_at": "2026-10-05T10:00:00Z", "routing": { "mode": "forward", "forward_to": "+447700900456" } } ``` ### PATCH /numbers/{id} Change a number's routing: ring the app, or forward to another number. Needs scope: numbers:write ```bash curl -X PATCH "https://api.voicepro.plus/v3/numbers/num_q4zr7mxkp2wd6hnc3tbvfy5a" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" \ -H "Content-Type: application/json" -H "Idempotency-Key: " \ -d '{"routing":{"mode":"forward","forward_to":"+447700900456"}}' ``` Response: ```json { "object": "number_routing", "number_id": "num_q4zr7mxkp2wd6hnc3tbvfy5a", "mode": "forward", "forward_to": "+447700900456", "state": "active", "note": null } ``` ### GET /numbers/{id}/usage Calls and SMS for a time range. Needs scope: numbers:read ```bash curl -X GET "https://api.voicepro.plus/v3/numbers/num_q4zr7mxkp2wd6hnc3tbvfy5a/usage?from=2026-10-01T00%3A00%3A00Z&to=2026-10-28T00%3A00%3A00Z&step=1d" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "number_usage", "number_id": "num_q4zr7mxkp2wd6hnc3tbvfy5a", "range": { "from": "2026-10-01T00:00:00Z", "to": "2026-10-28T00:00:00Z", "step": "1d", "timezone": "Europe/London" }, "totals": { "inbound_calls": 96, "outbound_calls": 41, "answered_calls": 118, "minutes": 402.5, "sms": 0 }, "previous": { "inbound_calls": 88, "outbound_calls": 37, "answered_calls": 109, "minutes": 371, "sms": 0 }, "series": [ { "t": "2026-10-26T00:00:00Z", "calls": 6, "sms": 0 }, { "t": "2026-10-27T00:00:00Z", "calls": 9, "sms": 0 } ] } ``` ### GET /number_offers Numbers you can order in a country, with their prepaid price in the currency you choose. Needs scope: read ```bash curl -X GET "https://api.voicepro.plus/v3/number_offers?country=GB&category=landline" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "list", "data": [ { "object": "number_offer", "id": "nof_m3xk7q2zrw4pdn6hc5tbvfya", "country": "GB", "prefix": "4420", "area_name": "London", "category": "landline", "channels_included": 2, "monthly_price": { "amount": 150, "currency": "USD" }, "setup_price": { "amount": 0, "currency": "USD" }, "first_payment": { "amount": 150, "currency": "USD" }, "data_as_of": "2026-10-28T06:00:00Z" } ], "has_more": false, "next_cursor": null } ``` ### POST /number_orders Order a number. Prepaid from your account balance. Needs scope: orders:write ```bash curl -X POST "https://api.voicepro.plus/v3/number_orders" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" \ -H "Content-Type: application/json" -H "Idempotency-Key: " \ -d '{"offer_id":"nof_m3xk7q2zrw4pdn6hc5tbvfya"}' ``` Response: ```json { "object": "number_order", "id": "nord_p6wz2kq7mx4rd3nh5cbtvfya", "status": "completed", "offer_id": "nof_m3xk7q2zrw4pdn6hc5tbvfya", "phone_number": "+442079460188", "number_id": "num_r5kx2wq7mz4pd3nh6cbtvfya", "charged": { "amount": 150, "currency": "USD" }, "balance_after": { "amount": 4850, "currency": "USD" }, "created_at": "2026-10-28T09:30:00Z" } ``` ### GET /port_requests Requests to transfer numbers in. Needs scope: read ```bash curl -X GET "https://api.voicepro.plus/v3/port_requests" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "list", "data": [ { "object": "port_request", "id": "port_4F9K2A", "numbers": [ "+442079460188" ], "current_provider": "Previous provider plc", "account_reference": "ACC-558120", "authorised_name": "Jordan Lee", "status": "accepted", "transfer_date": "2026-10-30", "action_needed": null, "history": [ { "at": "2026-10-20T09:00:00Z", "status": "submitted", "note": null }, { "at": "2026-10-23T14:12:00Z", "status": "accepted", "note": "Transfer date confirmed." } ], "created_at": "2026-10-20T09:00:00Z" } ], "has_more": false, "next_cursor": null } ``` ### POST /port_requests Ask to transfer numbers to VoicePro from another provider. Needs scope: porting:write ```bash curl -X POST "https://api.voicepro.plus/v3/port_requests" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" \ -H "Content-Type: application/json" -H "Idempotency-Key: " \ -d '{"numbers":["+442079460188"],"current_provider":"Previous provider plc","account_reference":"ACC-558120","authorised_name":"Jordan Lee"}' ``` Response: ```json { "object": "port_request", "id": "port_4F9K2A", "numbers": [ "+442079460188" ], "current_provider": "Previous provider plc", "account_reference": "ACC-558120", "authorised_name": "Jordan Lee", "status": "submitted", "transfer_date": null, "action_needed": null, "history": [ { "at": "2026-10-20T09:00:00Z", "status": "submitted", "note": null } ], "created_at": "2026-10-20T09:00:00Z" } ``` ### GET /port_requests/{id} One transfer request with its history. Needs scope: read ```bash curl -X GET "https://api.voicepro.plus/v3/port_requests/port_4F9K2A" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "port_request", "id": "port_4F9K2A", "numbers": [ "+442079460188" ], "current_provider": "Previous provider plc", "account_reference": "ACC-558120", "authorised_name": "Jordan Lee", "status": "accepted", "transfer_date": "2026-10-30", "action_needed": null, "history": [ { "at": "2026-10-20T09:00:00Z", "status": "submitted", "note": null }, { "at": "2026-10-23T14:12:00Z", "status": "accepted", "note": "Transfer date confirmed." } ], "created_at": "2026-10-20T09:00:00Z" } ``` ### GET /number_requirements What you must supply, per country and number type, before a number goes live: personal, business and address documents, and notes. Leave out country for every country. Needs scope: read ```bash curl -X GET "https://api.voicepro.plus/v3/number_requirements?country=DE" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "list", "data": [ { "object": "number_requirement", "country": "DE", "country_name": "Germany", "region": "Europe", "documentation_required": true, "number_types": [ { "category": "landline", "personal": [ "Name, last name", "Contact phone number", "German passport or ID copy" ], "business": [ "Name, last name", "Contact phone number", "Company name", "German company incorporation certificate copy" ], "address": [ "Address matching: the DID area code, address in the certificate/ID (street, building number, postal code, city and country)", "A copy of a utility bill (less than 6 months old)" ], "notes": [ "We reserve the right in our sole discretion to request additional information at any stage of the registration process." ] }, { "category": "tollfree", "personal": [ "Name, last name", "Contact phone number", "Proof of allocation (Zuteilungsbescheid) from the German national regulator (BNetzA)" ], "business": [ "Name, last name", "Contact phone number", "Company name", "Proof of allocation (Zuteilungsbescheid) from the German national regulator (BNetzA)" ], "address": [ "Address in Germany (street, building number, postal code, city and country)" ], "notes": [ "We reserve the right in our sole discretion to request additional information at any stage of the registration process." ] } ] } ], "has_more": false, "next_cursor": null } ``` ### POST /numbers/{id}/cancel Cancel a number: no further charges; it keeps working to the end of the month already paid, then is released. Needs scope: numbers:write ```bash curl -X POST "https://api.voicepro.plus/v3/numbers/num_8d2f5a1c/cancel" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "number_cancellation", "number_id": "num_8d2f5a1c", "phone_number": "+442079460123", "ends_at": "2026-11-14T10:00:00.000Z", "further_charges": false } ``` ## Voice trunk ### GET /trunks Trunk settings. 404 service_not_enabled without a voice trunk. Needs scope: read ```bash curl -X GET "https://api.voicepro.plus/v3/trunks" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "list", "data": [ { "object": "trunk", "name": "acme-main", "active": true, "call_limit": 30, "cps_limit": 5, "max_call_seconds": 7200, "allowed_ips": [ "203.0.113.20" ], "data_as_of": "2026-10-28T08:55:00Z" } ], "has_more": false, "next_cursor": null } ``` ### GET /rates Current and scheduled rates. Needs scope: read ```bash curl -X GET "https://api.voicepro.plus/v3/rates?destination=France" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "list", "data": [ { "object": "rate", "destination": "France - Fixed", "rate": { "amount": "0.0060", "currency": "USD" }, "billing_increment": "60/60", "effective_from": "2026-10-01T00:00:00Z", "effective_until": null } ], "has_more": false, "next_cursor": null } ``` ### GET /calls Call records, newest first, for a range of at most 92 days (default: the last 24 hours). Needs scope: read ```bash curl -X GET "https://api.voicepro.plus/v3/calls?result=answered" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "list", "data": [ { "object": "call", "id": "call_mfrgg5dbgaztemrqgu", "started_at": "2026-10-27T14:03:22Z", "from": "+442079460123", "to": "+33155550123", "country": "FR", "seconds": 184, "result": "answered", "charge": { "amount": "0.0184", "currency": "USD" }, "data_as_of": "2026-10-28T08:55:00Z", "sip_call_id": "a1b2c3d4e5@203.0.113.20" } ], "has_more": true, "next_cursor": "eyJrIjoiMjAyNi0xMC0yN1QxNDowMzoyMloifQ" } ``` ### GET /calls/{id} One call record by id, within the last 92 days. Needs scope: read ```bash curl -X GET "https://api.voicepro.plus/v3/calls/call_mfrgg5dbgaztemrqgu" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "call", "id": "call_mfrgg5dbgaztemrqgu", "started_at": "2026-10-27T14:03:22Z", "from": "+442079460123", "to": "+33155550123", "country": "FR", "seconds": 184, "result": "answered", "charge": { "amount": "0.0184", "currency": "USD" }, "data_as_of": "2026-10-28T08:55:00Z", "sip_call_id": "a1b2c3d4e5@203.0.113.20" } ``` ### GET /traffic Totals and series for a time range. Needs scope: read ```bash curl -X GET "https://api.voicepro.plus/v3/traffic?from=2026-10-01T00%3A00%3A00Z&to=2026-10-28T00%3A00%3A00Z&step=1d" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "traffic", "range": { "from": "2026-10-01T00:00:00Z", "to": "2026-10-28T00:00:00Z", "step": "1d", "timezone": "Europe/London" }, "totals": { "calls": 1240, "answered": 868, "asr": 0.7, "acd_seconds": 142.5, "minutes": 2061.5, "spend": { "amount": "103.08", "currency": "USD" }, "pdd_seconds": 2.1, "sdr": 0.012 }, "previous": { "calls": 1105, "answered": 762, "asr": 0.69, "acd_seconds": 142.5, "minutes": 1810, "spend": { "amount": "90.50", "currency": "USD" }, "pdd_seconds": 2.1, "sdr": 0.012 }, "series": [ { "t": "2026-10-27T00:00:00Z", "calls": 52, "answered": 37, "minutes": 88.5, "spend": { "amount": "4.43", "currency": "USD" } } ], "data_as_of": "2026-10-28T08:55:00Z" } ``` ### GET /traffic/destinations Traffic by destination country for a time range. Needs scope: read ```bash curl -X GET "https://api.voicepro.plus/v3/traffic/destinations" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "list", "data": [ { "object": "traffic_destination", "country": "FR", "calls": 410, "answered": 295, "asr": 0.72, "minutes": 701.2, "spend": { "amount": "35.06", "currency": "USD" } } ], "has_more": false, "next_cursor": null } ``` ### GET /trunks/channels Channels in use per trunk, now and at peak, against each trunk's limit, with a series. Needs scope: read ```bash curl -X GET "https://api.voicepro.plus/v3/trunks/channels?range=24h" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "trunk_channels", "range": "24h", "bucket_seconds": 900, "history_through": "2026-10-28T21:45:00Z", "unavailable": [], "trunks": [ { "name": "ACME_SIP_GW1", "limit": 120, "now": 38, "now_at": "2026-10-28T21:59:30Z", "peak": 96, "peak_at": "2026-10-28T18:15:00Z", "series": [ { "at": "2026-10-28T21:15:00Z", "channels": 41 }, { "at": "2026-10-28T21:30:00Z", "channels": 36 } ] } ], "data_as_of": "2026-10-28T21:45:00Z" } ``` ### GET /fraud/incidents Fraud incidents and losses our fraud engine raised on this account's traffic, against the previous period. Needs scope: read ```bash curl -X GET "https://api.voicepro.plus/v3/fraud/incidents?window=7d" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "fraud_incidents", "window": "7d", "totals": { "incidents": 3, "incidents_previous_period": 5, "ranges": 2, "territories": 2, "origins": 1, "loss": { "amount": "4.12", "currency": "USD" } }, "by_signal": [ { "signal": "irsf", "label": "IRSF / high-risk destination", "incidents": 2 }, { "signal": "wangiri", "label": "Wangiri / short-call abuse", "incidents": 1 } ], "unavailable": [], "data_as_of": "2026-10-28T21:40:00Z" } ``` ## Activity ### GET /activity Calls, SMS and data across SIMs, numbers and the voice trunk, newest first. Each source gives at most 5000 records per window; has_more then pages into older records. Voice trunk records cover at most the last 92 days. Needs scope: read ```bash curl -X GET "https://api.voicepro.plus/v3/activity?kind=call" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "list", "data": [ { "object": "activity", "id": "act_5mq2k7xw", "at": "2026-10-27T14:03:22Z", "kind": "call", "direction": "out", "via": { "type": "sim", "id": "sim_K7M2Q9", "label": "Warehouse van 3" }, "from": "+447700900123", "to": "+442079460555", "country": "GB", "roaming_country": null, "seconds": 95, "bytes": null, "result": "answered", "ok": true, "charge": null } ], "has_more": false, "next_cursor": null } ``` ## Billing ### GET /invoices VoicePro invoices, newest first. Needs scope: billing:read ```bash curl -X GET "https://api.voicepro.plus/v3/invoices?status=paid" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "list", "data": [ { "object": "invoice", "id": "inv_2610AB12", "period": "2026-09", "status": "paid", "subtotal": { "amount": 42000, "currency": "GBP" }, "vat": { "amount": 8400, "currency": "GBP" }, "total": { "amount": 50400, "currency": "GBP" }, "issued_at": "2026-10-01T06:00:00Z", "due_at": "2026-10-15T23:59:59Z", "paid_at": "2026-10-08T10:21:00Z", "line_count": 2 } ], "has_more": false, "next_cursor": null } ``` ### GET /invoices/{id} One invoice with its lines. Needs scope: billing:read ```bash curl -X GET "https://api.voicepro.plus/v3/invoices/inv_2610AB12" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "invoice", "id": "inv_2610AB12", "period": "2026-09", "status": "paid", "subtotal": { "amount": 42000, "currency": "GBP" }, "vat": { "amount": 8400, "currency": "GBP" }, "total": { "amount": 50400, "currency": "GBP" }, "issued_at": "2026-10-01T06:00:00Z", "due_at": "2026-10-15T23:59:59Z", "paid_at": "2026-10-08T10:21:00Z", "line_count": 2, "lines": [ { "description": "Business+ Essentials, 12 SIMs", "quantity": 12, "unit_price": { "amount": 3000, "currency": "GBP" }, "total": { "amount": 36000, "currency": "GBP" }, "kind": "plan" }, { "description": "EU Roaming add-on", "quantity": 12, "unit_price": { "amount": 500, "currency": "GBP" }, "total": { "amount": 6000, "currency": "GBP" }, "kind": "add_on" } ], "notes": null } ``` ### GET /invoices/{id}/pdf The invoice as a VAT invoice PDF. Needs scope: billing:read ```bash curl -X GET "https://api.voicepro.plus/v3/invoices/inv_2610AB12/pdf" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` ### GET /wholesale/invoices Wholesale voice invoices. Needs scope: billing:read ```bash curl -X GET "https://api.voicepro.plus/v3/wholesale/invoices" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "list", "data": [ { "object": "wholesale_invoice", "number": "W-2026-0931", "period_start": "2026-09-01", "period_end": "2026-09-30", "issued_at": "2026-10-01T06:00:00Z", "due_at": "2026-10-15T23:59:59Z", "total": { "amount": 9050, "currency": "USD" }, "status": "paid" } ], "has_more": false, "next_cursor": null } ``` ### GET /wholesale/payments Payments received for wholesale voice. Needs scope: billing:read ```bash curl -X GET "https://api.voicepro.plus/v3/wholesale/payments" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "list", "data": [ { "object": "wholesale_payment", "date": "2026-10-08", "amount": { "amount": 9050, "currency": "USD" }, "reference": "ACME-OCT-01" } ], "has_more": false, "next_cursor": null } ``` ### GET /balance Wholesale balance and prepaid dip balance. Needs scope: billing:read ```bash curl -X GET "https://api.voicepro.plus/v3/balance" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "balance", "wholesale": [ { "amount": 4850, "currency": "USD" } ], "prepaid": [ { "amount": 2500, "currency": "GBP" }, { "amount": 12000, "currency": "USD" } ], "default_currency": "GBP", "data_as_of": "2026-10-28T09:00:00Z" } ``` ### GET /spend This month's spend by service, the projection and the spending limit. Needs scope: billing:read ```bash curl -X GET "https://api.voicepro.plus/v3/spend" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "spend", "period": "2026-10", "days_elapsed": 27.4, "days_in_month": 31, "lines": [ { "service": "Mobile SIMs", "kind": "fixed", "month_to_date": { "amount": 42000, "currency": "GBP" }, "today": null, "projected": { "amount": 42000, "currency": "GBP" }, "note": null }, { "service": "Voice trunk", "kind": "usage", "month_to_date": { "amount": 10308, "currency": "USD" }, "today": { "amount": 443, "currency": "USD" }, "projected": { "amount": 11660, "currency": "USD" }, "note": null } ], "totals": [ { "month_to_date": { "amount": 42000, "currency": "GBP" }, "projected": { "amount": 42000, "currency": "GBP" } }, { "month_to_date": { "amount": 10308, "currency": "USD" }, "projected": { "amount": 11660, "currency": "USD" } } ], "limit": { "limit": { "amount": 250000, "currency": "GBP" }, "used": { "amount": 42000, "currency": "GBP" }, "projected": { "amount": 42000, "currency": "GBP" } } } ``` ### POST /invoices/{id}/payment_link A secure payment link for an open invoice, to pay it or send it on. Needs scope: billing:write ```bash curl -X POST "https://api.voicepro.plus/v3/invoices/inv_2610AB12/payment_link" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "invoice_payment_link", "invoice_id": "inv_2610AB12", "url": "https://pay.example.com/c/cs_example", "amount": { "amount": 50400, "currency": "GBP" } } ``` ## Dips ### GET /dips/products Dip products you can buy, with live prices. Needs scope: read ```bash curl -X GET "https://api.voicepro.plus/v3/dips/products" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "list", "data": [ { "object": "dip_product", "code": "nrv", "name": "VPX-NRV", "price": { "amount": "0.0050", "currency": "USD" } }, { "object": "dip_product", "code": "last_port", "name": "Last Port", "price": { "amount": "0.0030", "currency": "USD" } } ], "has_more": false, "next_cursor": null } ``` ### GET /dips Past single dips, newest first: the most recent 200, each kept for 90 days. Needs scope: read ```bash curl -X GET "https://api.voicepro.plus/v3/dips" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "list", "data": [ { "object": "dip", "id": "dip_x7k2m9qwp4zr", "number": "447700900123", "country": "GB", "products": [ "nrv", "last_port" ], "risk": "low", "score": 12, "validity": "valid", "network": "Mobile network GB", "status": "active", "created_at": "2026-10-27T16:45:10Z" } ], "has_more": false, "next_cursor": null } ``` ### POST /dips Dip one number: the chosen products, answered now. Needs scope: dips:write ```bash curl -X POST "https://api.voicepro.plus/v3/dips" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" \ -H "Content-Type: application/json" -H "Idempotency-Key: " \ -d '{"number":"+447700900123","products":["nrv","last_port"],"currency":"GBP"}' ``` Response: ```json { "object": "dip", "id": "dip_x7k2m9qwp4zr", "number": "447700900123", "country": "GB", "products": [ "nrv", "last_port" ], "results": { "nrv": { "tn": "447700900123", "cc": "GB", "valid": true, "source": "local", "line_type": "mobile", "range_holder": "Example Mobile Ltd", "ms": 12 }, "last_port": { "tn": "447700900123", "valid": "Y", "lastPorted": "00/00/0000" } }, "charge": { "amount": "0.0080", "currency": "USD" }, "created_at": "2026-10-27T16:45:10Z" } ``` ### GET /dips/{id} One past dip. Needs scope: read ```bash curl -X GET "https://api.voicepro.plus/v3/dips/dip_x7k2m9qwp4zr" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "dip", "id": "dip_x7k2m9qwp4zr", "number": "447700900123", "country": "GB", "products": [ "nrv", "last_port" ], "risk": "low", "score": 12, "validity": "valid", "network": "Mobile network GB", "status": "active", "created_at": "2026-10-27T16:45:10Z" } ``` ### GET /dips/usage Dips this month by product. Needs scope: read ```bash curl -X GET "https://api.voicepro.plus/v3/dips/usage" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "dip_usage", "month": "2026-10", "total": 1840, "by_product": { "nrv": 1500, "last_port": 340 } } ``` ### GET /dip_batches Dip batches, newest first. Needs scope: read ```bash curl -X GET "https://api.voicepro.plus/v3/dip_batches" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "list", "data": [ { "object": "dip_batch", "id": "dipb_8KQ2M7", "name": "October lead list", "total": 500, "done": 500, "products": [ "nrv" ], "state": "done", "created_at": "2026-10-26T09:00:00Z", "finished_at": "2026-10-26T09:04:31Z" } ], "has_more": false, "next_cursor": null } ``` ### POST /dip_batches Check a file of up to 20,000 numbers in the background. Needs scope: dips:write ```bash curl -X POST "https://api.voicepro.plus/v3/dip_batches" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" \ -H "Content-Type: application/json" -H "Idempotency-Key: " \ -d '{"numbers":["+447700900001","+447700900002"],"products":["nrv"],"name":"October list"}' ``` Response: ```json { "object": "dip_batch", "id": "dipb_8KQ2M7", "name": "October list", "total": 2, "done": 0, "products": [ "nrv" ], "state": "running", "created_at": "2026-10-26T09:00:00Z", "finished_at": null, "charge": { "amount": "0.0004", "currency": "USD" } } ``` ### GET /dip_batches/{id} One batch with its progress. Needs scope: read ```bash curl -X GET "https://api.voicepro.plus/v3/dip_batches/dipb_8KQ2M7" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "dip_batch", "id": "dipb_8KQ2M7", "name": "October lead list", "total": 500, "done": 500, "products": [ "nrv" ], "state": "done", "created_at": "2026-10-26T09:00:00Z", "finished_at": "2026-10-26T09:04:31Z" } ``` ### GET /dip_batches/{id}/results Batch results; 409 state_conflict while running unless partial=true. CSV with Accept: text/csv. Needs scope: read ```bash curl -X GET "https://api.voicepro.plus/v3/dip_batches/dipb_8KQ2M7/results" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "list", "data": [ { "object": "dip_result", "number": "447700900123", "product": "nrv", "result_code": "ok", "result": { "tn": "447700900123", "cc": "GB", "valid": true, "source": "local", "line_type": "mobile", "range_holder": "Example Mobile Ltd", "ms": 12 } } ], "has_more": true, "next_cursor": "eyJrIjoiNDQ3NzAwOTAwMTIzIn0" } ``` ### GET /risk_ranges Search the high-risk and premium-rate number ranges our network screens against. total and truncated say when a search matched more than one answer holds (500). Needs scope: read ```bash curl -X GET "https://api.voicepro.plus/v3/risk_ranges?q=Albania" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "list", "data": [ { "object": "risk_range", "prefix": "355900", "label": "Albania (Republic of) - Shared Revenue Services (premium-rate only per national plan data)", "kind": "premium_rate_international" } ], "has_more": false, "next_cursor": null, "total": 1, "truncated": false } ``` ### GET /number_watches The account's number watches, newest first. Needs scope: read ```bash curl -X GET "https://api.voicepro.plus/v3/number_watches" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "list", "data": [ { "object": "number_watch", "id": "nw_6f1c2a9e0b7d4c3e8a5f1b2c3d4e5f60", "phone_number": "+447700900123", "label": "Supplier hotline", "products": [ "nrv", "last_port" ], "created_at": "2026-10-29T09:12:44Z", "last_checked_at": "2026-10-30T05:13:20Z", "last_change_at": null, "current": { "validity": "valid", "ported": "false", "range_holder": "Example Mobile" }, "currency": "GBP" } ], "has_more": false, "next_cursor": null } ``` ### POST /number_watches Watch a number: re-checked daily, with every change recorded and sent to your webhooks. Needs scope: dips:write ```bash curl -X POST "https://api.voicepro.plus/v3/number_watches" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" \ -H "Content-Type: application/json" -H "Idempotency-Key: " \ -d '{"number":"+447700900123","products":["nrv","last_port"],"label":"Supplier hotline"}' ``` Response: ```json { "object": "number_watch", "id": "nw_6f1c2a9e0b7d4c3e8a5f1b2c3d4e5f60", "phone_number": "+447700900123", "label": "Supplier hotline", "products": [ "nrv", "last_port" ], "created_at": "2026-10-29T09:12:44Z", "last_checked_at": null, "last_change_at": null, "current": null, "currency": "GBP" } ``` ### GET /number_watches/{id} One number watch, with the number's answer at the last check. Needs scope: read ```bash curl -X GET "https://api.voicepro.plus/v3/number_watches/nw_6f1c2a9e0b7d4c3e8a5f1b2c3d4e5f60" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "number_watch", "id": "nw_6f1c2a9e0b7d4c3e8a5f1b2c3d4e5f60", "phone_number": "+447700900123", "label": "Supplier hotline", "products": [ "nrv", "last_port" ], "created_at": "2026-10-29T09:12:44Z", "last_checked_at": "2026-10-30T05:13:20Z", "last_change_at": null, "current": { "validity": "valid", "ported": "false", "range_holder": "Example Mobile" }, "currency": "GBP" } ``` ### DELETE /number_watches/{id} Stop watching a number. Its change history goes with it. Needs scope: dips:write ```bash curl -X DELETE "https://api.voicepro.plus/v3/number_watches/nw_6f1c2a9e0b7d4c3e8a5f1b2c3d4e5f60" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "number_watch", "id": "nw_6f1c2a9e0b7d4c3e8a5f1b2c3d4e5f60", "deleted": true } ``` ### GET /number_watches/{id}/events A watch's changes, newest first (the last 50). Needs scope: read ```bash curl -X GET "https://api.voicepro.plus/v3/number_watches/nw_6f1c2a9e0b7d4c3e8a5f1b2c3d4e5f60/events" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "list", "data": [ { "object": "number_watch_event", "watch_id": "nw_6f1c2a9e0b7d4c3e8a5f1b2c3d4e5f60", "at": "2026-11-02T05:13:41Z", "changes": { "ported": { "from": "false", "to": "true" }, "serving_network": { "from": null, "to": "Example Mobile 2" } } } ], "has_more": false, "next_cursor": null } ``` ## Webhooks ### GET /webhook_events The events you can subscribe a webhook to. Needs scope: read ```bash curl -X GET "https://api.voicepro.plus/v3/webhook_events" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "list", "data": [ { "object": "webhook_event", "code": "invoice.issued", "description": "A new invoice was issued" }, { "object": "webhook_event", "code": "porting.updated", "description": "A number transfer changed status" } ], "has_more": false, "next_cursor": null } ``` ### GET /webhooks Your account's webhooks, newest first. The signing secret is never shown here, only its last 4 characters. Needs scope: read ```bash curl -X GET "https://api.voicepro.plus/v3/webhooks" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "list", "data": [ { "object": "webhook", "id": "wh_4c1e9a07", "event": "invoice.issued", "description": "A new invoice was issued", "url": "https://example.com/hooks/voicepro", "status": "active", "created_at": "2026-10-28T21:15:02Z", "last_delivery_at": "2026-10-28T21:16:40Z", "last_response_code": 200, "failing_since": null, "secret_last4": "a1b2", "events": [ "invoice.issued" ] } ], "has_more": false, "next_cursor": null } ``` ### POST /webhooks Subscribe an HTTPS endpoint to an event. The answer carries the signing secret, the only time it is shown: keep it to check X-VoicePro-Signature (HMAC-SHA256 of the raw body). Needs scope: webhooks:write ```bash curl -X POST "https://api.voicepro.plus/v3/webhooks" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" \ -H "Content-Type: application/json" -H "Idempotency-Key: " \ -d '{"event":"invoice.issued","url":"https://example.com/hooks/voicepro"}' ``` Response: ```json { "object": "webhook", "id": "wh_4c1e9a07", "event": "invoice.issued", "description": "A new invoice was issued", "url": "https://example.com/hooks/voicepro", "status": "active", "created_at": "2026-10-28T21:15:02Z", "last_delivery_at": null, "last_response_code": null, "failing_since": null, "secret_last4": "a1b2", "secret": "whsec_example0000000000000000000a1b2", "events": [ "invoice.issued" ] } ``` ### GET /webhooks/{id} One webhook. Needs scope: read ```bash curl -X GET "https://api.voicepro.plus/v3/webhooks/wh_4c1e9a07" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "webhook", "id": "wh_4c1e9a07", "event": "invoice.issued", "description": "A new invoice was issued", "url": "https://example.com/hooks/voicepro", "status": "active", "created_at": "2026-10-28T21:15:02Z", "last_delivery_at": "2026-10-28T21:16:40Z", "last_response_code": 200, "failing_since": null, "secret_last4": "a1b2", "events": [ "invoice.issued" ] } ``` ### PATCH /webhooks/{id} Change the URL, or pause and resume deliveries. A refused URL changes nothing. Needs scope: webhooks:write ```bash curl -X PATCH "https://api.voicepro.plus/v3/webhooks/wh_4c1e9a07" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" \ -H "Content-Type: application/json" -H "Idempotency-Key: " \ -d '{"status":"paused"}' ``` Response: ```json { "object": "webhook", "id": "wh_4c1e9a07", "event": "invoice.issued", "description": "A new invoice was issued", "url": "https://example.com/hooks/voicepro", "status": "paused", "created_at": "2026-10-28T21:15:02Z", "last_delivery_at": "2026-10-28T21:16:40Z", "last_response_code": 200, "failing_since": null, "secret_last4": "a1b2", "events": [ "invoice.issued" ] } ``` ### DELETE /webhooks/{id} Delete a webhook. Deliveries stop at once. Needs scope: webhooks:write ```bash curl -X DELETE "https://api.voicepro.plus/v3/webhooks/wh_4c1e9a07" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "webhook", "id": "wh_4c1e9a07", "deleted": true } ``` ### POST /webhooks/{id}/test Send a signed test delivery (type "test", header X-VoicePro-Test: true) and see how your endpoint answered. At most 10 an hour per webhook and 30 per account. Needs scope: webhooks:write ```bash curl -X POST "https://api.voicepro.plus/v3/webhooks/wh_4c1e9a07/test" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "webhook_delivery", "id": "whd_8f2b61d0c4", "webhook_id": "wh_4c1e9a07", "event": "invoice.issued", "test": true, "attempted_at": "2026-10-28T21:16:40Z", "duration_ms": 212, "ok": true, "response_code": 200, "response_excerpt": "{\"received\":true}", "event_id": null, "attempt": 1 } ``` ### GET /webhooks/{id}/deliveries The last 50 deliveries to a webhook, newest first, with how your endpoint answered. Needs scope: read ```bash curl -X GET "https://api.voicepro.plus/v3/webhooks/wh_4c1e9a07/deliveries" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "list", "data": [ { "object": "webhook_delivery", "id": "whd_8f2b61d0c4", "webhook_id": "wh_4c1e9a07", "event": "invoice.issued", "test": true, "attempted_at": "2026-10-28T21:16:40Z", "duration_ms": 212, "ok": true, "response_code": 200, "response_excerpt": "{\"received\":true}", "event_id": null, "attempt": 1 } ], "has_more": false, "next_cursor": null } ``` ### GET /events Your account's events from the last 30 days, newest first, as sent to your webhooks. Needs scope: read ```bash curl -X GET "https://api.voicepro.plus/v3/events" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "list", "data": [ { "object": "event", "id": "evt_3f9c2a71b8e04d6a9c1e5b27", "type": "invoice.issued", "occurred_at": "2026-10-29T09:00:00Z", "data": { "id": "INV-26-10AB12", "period": "2026-10", "totalGbp": 42, "dueAt": "2026-11-12T00:00:00.000Z" } } ], "has_more": false, "next_cursor": null } ``` ### GET /events/{id} One event from the last 30 days. Needs scope: read ```bash curl -X GET "https://api.voicepro.plus/v3/events/evt_3f9c2a71b8e04d6a9c1e5b27" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" ``` Response: ```json { "object": "event", "id": "evt_3f9c2a71b8e04d6a9c1e5b27", "type": "invoice.issued", "occurred_at": "2026-10-29T09:00:00Z", "data": { "id": "INV-26-10AB12", "period": "2026-10", "totalGbp": 42, "dueAt": "2026-11-12T00:00:00.000Z" } } ``` ### POST /events/{id}/resend Send an event again: to every webhook that receives its type, or to one. Needs scope: webhooks:write ```bash curl -X POST "https://api.voicepro.plus/v3/events/evt_3f9c2a71b8e04d6a9c1e5b27/resend" \ -H "Authorization: Bearer $VOICEPRO_API_KEY" \ -H "Content-Type: application/json" -H "Idempotency-Key: " \ -d '{"webhook_id":"wh_4c1e9a07"}' ``` Response: ```json { "object": "event_resend", "event_id": "evt_3f9c2a71b8e04d6a9c1e5b27", "webhooks": 1 } ```