---
title: "Create a verification"
method: POST
path: "/verifications"
tags: ["Verifications"]
---

# Create a verification

`POST /verifications`

## Request

- Base URL: `https://dashboard.voidmob.com/api/v1`
- URL: `https://dashboard.voidmob.com/api/v1/verifications`
- Auth: HTTP bearer

Rents a phone number for one inbound SMS. Idempotent by
`Idempotency-Key`.

## Caps

SMS pricing drifts. Set `max_price_cents` to opt into "always get a
number" behaviour: any drift up to your cap charges silently and the
actual amount appears as `charged_price_cents` on the response. Omit
`max_price_cents` to lock in exactly the price you saw on
`GET /v1/services`.

## Price over cap

If the lowest available price is above your `max_price_cents`, the API
returns **`409 PRICE_OVER_CAP`** with both values in the error details:

```json
{
  "success": false,
  "error": {
    "code": "PRICE_OVER_CAP",
    "details": {
      "max_price_cents": 35,
      "available_price_cents": 42
    }
  }
}
```

No partial state is created and no funds are touched. Decide locally
whether to retry with a higher cap or surface the price to the user.

## Headers

- `Idempotency-Key` string, required

## Request body

- CreateVerificationRequest
  - `service_id` string, required: Opaque public service identifier.
  - `country` string
  - `max_price_cents` integer: Optional ceiling. If omitted, the API caps at the current `quoted_price_cents` reported by `GET /v1/services`. Setting this above the quote opts into "always get a number" mode - price drift within the cap charges the new market price; drift above the cap returns `409 PRICE_OVER_CAP` with the current available price in the error details so callers can decide whether to retry with a higher cap.
  - `webhook_endpoint_id` string: Webhook endpoint identifier.

## Response `201`

Verification created. `status` is always `waiting_for_code` at this point.

- object
  - `success` true, required
  - `data` object, required
    - `verification` Verification, required
      - `id` string, required: Opaque verification (SMS rental) identifier.
      - `display_id` string, nullable: Human-readable order identifier for display in dashboards and receipts (e.g. `SMS7K4P2N`). Null for legacy rentals created before this field was introduced.
      - `status` 'waiting_for_code' | 'code_received' | 'cancelled' | 'expired' | 'failed', required: `waiting_for_code` - number is live (up to 15 minutes, see `expires_at`), no SMS yet. `code_received` - at least one SMS arrived. `cancelled` - the price was refunded, either because you cancelled or because the window closed with no SMS (automatic refund). `expired` - the window closed with no SMS and no automatic refund (services marked non-refundable, or rare cases where the refund could not be applied automatically). `failed` is reserved and not emitted.
      - `phone_number` string, required: E.164 phone number (with leading +).
      - `service_id` string: Opaque public service identifier.
      - `service_name` string, required
      - `charged_price_cents` integer, required: Actual amount deducted from the wallet for this verification.
      - `pricing_source` 'regular' | 'category' | 'override' | 'promo': Attribution for the charged price. Omitted for legacy rentals. "promo" means a redeemed service-discount code priced this purchase.
      - `expires_at` string, date-time, required
      - `can_cancel` boolean, required: Whether the rental is currently cancellable. Becomes false once a code arrives or the cancel window closes.
      - `created_at` string, date-time, required
      - `code` string: The received SMS code. Present only when `status = code_received`.
      - `code_received_at` string, date-time: When the code arrived. Present only when `status = code_received`.
      - `reuse_counter` integer, required: Number of user-initiated reuses (free or paid) on this number. Starts at 0. Automatic reuses are not counted.
      - `allow_reuse` boolean, required: Free reuse is currently available.
      - `allow_paid_reuse` boolean, required: Paid reuse is currently available. STR rentals only.
      - `paid_reuse_price_cents` integer, required: Fixed price for one paid reuse.
      - `charged_reuse_cents` integer: Set on the response of a successful POST /reuse/paid. Not present otherwise.
      - `refunded_cents` integer: Set on the response of a successful POST /cancel. Not present otherwise.

## Other responses

- `400`: 400 - Request failed validation.
- `401`: 401 - Authentication required.
- `402`: 402 - Your wallet balance is too low for this purchase.
- `403`: 403 - Your account cannot perform this action.
- `404`: 404 - Unknown service id.
- `409`: Conflicts. Body discriminates by `error.code`: - `IDEMPOTENCY_CONFLICT` - same key, different body - `IDEMPOTENCY_REPLAY_IN_FLIGHT` - duplicate while original processes - `PRICE_OVER_CAP` - lowest available price exceeds `max_price_cents`; see `PriceOverCapError`
- `429`: 429 - Rate limit exceeded. Retry after the indicated interval.
- `500`: 500 - An unexpected error occurred. Please try again.
- `503`: 503 - This service is temporarily unavailable. Please try again shortly.

---

[API](https://skmtc.dev/voidmob/apis/voidmob-public-api.md) · [All operations](https://skmtc.dev/voidmob/apis/voidmob-public-api/llms.txt) · [OpenAPI document](https://skmtc.dev/voidmob/apis/voidmob-public-api/revisions/066023313ebe?raw)
