API v3
POST /dip_batches
Check a file of up to 20,000 numbers in the background.
The whole file is charged before it starts from your prepaid balance in the currency the request names (else your account's own), at the GET /dips/products prices converted at today's rate: 402 insufficient_balance when it does not cover it. A batch that does not start is refunded in full, and any numbers the service did not accept are refunded. Needs an Idempotency-Key; one key can never pay twice. Follow it with GET /dip_batches/{id}, and read the answers with GET /dip_batches/{id}/results. A locked account gets 423 account_locked.
Addresshttps://api.voicepro.plus/v3/dip_batches
Key permissiondips:write
Idempotency-KeyRequired. A retry with the same key and body replays the first answer, so it never acts twice.
ChargesPaid from your account balance before it runs; a short balance is 402 and nothing runs.
Fields
| Name | In | Type | |
|---|---|---|---|
| Idempotency-Key * | header | string | Required on every POST. 8-128 characters: letters, digits, dot, colon, hyphen or underscore. The first response is stored for 24 hours and replayed for any retry with the same key and the same body. Two rules, set per operation by x-charged. Charged or partner-side operations (x-charged true: dips, dip batches, orders, SMS, porting) never re-run while a first attempt is unfinished: a retry answers 409 idempotency_key_in_use (outcome pending) until the first outcome is stored, and the key is also given to the partner as its own reference, so one key never causes more than one order, charge or message, even across failures. A charged operation that fails part-way stores that failure as the key's answer; only a refusal before anything ran (400, 401, 402, 403, 404, 429) frees the key for a retry. Operations with no outside effect (x-charged false) hold their key for at most 2 minutes; after that a retry runs fresh. Missing: 400 missing_parameter (param Idempotency-Key). Malformed: 400 invalid_parameter. Same key, different body: 409 idempotency_key_reused. First request still running: 409 idempotency_key_in_use. |
| numbers * | body | array of string | 1 to 20,000 numbers in international format, such as +447700900123. |
| products | body | array of string | Dip product codes from GET /dips/products; all products on sale when left out. |
| name | body | string | |
| currency | body | string | The currency this is paid in: GBP, EUR, USD, JPY, AUD, CAD, CHF, HKD, SGD, INR, AED, KRW or SAR. Paid from your prepaid balance in that currency; left out, your account's own currency. Prices are converted from our USD price list at today's rate. Balances are never converted into one another: a short balance in this currency is 402 insufficient_balance, whatever you hold in others. |
* required
Example
curl -X POST "https://api.voicepro.plus/v3/dip_batches" \
-H "Authorization: Bearer vpkey_YOUR_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"numbers":["+447700900001","+447700900002"],"products":["nrv"],"name":"October list"}'Response
{
"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"
}
}Errors
Every error has the same shape: { "error": { "type", "code", "message", "param", "request_id" } }.
missing_api_key401: No Authorization header, or not a Bearer key.
invalid_api_key401: The key is not recognised.
api_key_revoked401: The key was revoked in the portal.
api_key_expired401: The key passed the expiry date set on it.
missing_scope403: The key lacks the scope this endpoint needs; param names the scope.
ip_not_allowed403: The key has an IP allowlist and this request came from elsewhere.
account_not_active403: The workspace is suspended or closed.
invalid_parameter400: A query parameter or body field has a bad value; param names it.
missing_parameter400: A required parameter or field is missing; param names it.
unknown_parameter400: A parameter or field that this endpoint does not accept; param names it.
invalid_json400: The body is not valid JSON.
invalid_cursor400: The cursor is malformed, expired or from a different list.
invalid_time_range400: from or to is not an ISO 8601 date-time, or to is not after from.
range_too_long400: The time range is longer than this endpoint allows (stated in the endpoint).
idempotency_key_reused409: This Idempotency-Key was used within 24 hours with a different request.
idempotency_key_in_use409: A request with this Idempotency-Key is still running, or its outcome at a partner is not yet known (message: outcome pending); retry shortly with the same key. If a charged request never finished, the message says so: check your balance and orders before sending it again with a new key.
state_conflict409: The object is not in a state that allows this action (for example resuming an active SIM).
insufficient_balance402: Prepaid funds or the account's order limit do not cover this charged action (a dip, an SMS or an order).
rate_limited429: Too many requests for this key or for the whole account (the message says which); wait Retry-After seconds.
upstream_unavailable503: A network partner or data service behind this endpoint is unavailable.
network_action_unavailable503: This network action is not switched on for the account yet (for example SIM suspend).
internal_error500: Our fault. Quote the request_id to support.
service_unavailable503: API v3 itself is briefly unavailable (for example a configuration problem on our side); the rest of VoicePro is unaffected. Retry later.
account_locked423: The account is locked pending a Trust & Safety review; writes, including charged actions, are refused until it is cleared. Reads still work.