Public Client API v1

Client API

REST JSON endpoints for short-term SMS verification rentals, authenticated with user-generated SMSINBOX API keys.

Base URL

https://smsinbox.net/api/client/v1

Auth

Authorization: Bearer <api_key>

Scope

Short-term rentals only

Envelope

{ data, error } for every response

API Key

Client API requests use a user-generated key from your SMSINBOX account. Keep it private and send it asAuthorization: Bearer smsi_your_key on every request.

Open API Dashboard

Sign in, open the API Dashboard, and use Key management to generate your client API key.

Copy the new key

The full key is shown only once. Store it before closing the panel; later the dashboard only shows a masked key.

Rotate when needed

Each account has one active key. Generating a new key immediately revokes the current active key.

Where
Dashboard -> API Dashboard.
Active keys
One active key per account.
Regeneration
Generating a new key revokes the current active key.
Expiry
Optional. If set, expiry must be at least 30 days from now.
Revocation
Use Revoke in the API Dashboard if a key is no longer needed or may be exposed.
History
The dashboard records creation, last use, expiry, and revocation events.

Safe Retries

Send Idempotency-Key on POST requests that buy or replace a rental. If your first request reaches SMSINBOX but your client gets a timeout, retrying with the same key lets the API treat it as the same operation instead of creating a duplicate one.

Source
Client-generated, usually as a UUID. It is not your API key and it is not copied from the dashboard.
New operation
Use a new key for each new purchase or replacement attempt.
Retry after timeout
Reuse the same key with the same request body.
GET requests
Do not send it; GET requests do not create or replace rentals.
Limit
128 characters or fewer.
Example
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000

Rate Limits

Limits are applied per account (not per API key or per IP), so provisioning more keys does not raise them. Each request is checked against both the account-wide umbrella and the per-endpoint limit below; the stricter one applies.

All endpoints (umbrella)
1200 requests / min
Catalog (services, countries)
120 requests / min
Price quote
60 requests / min
Purchase a number
30 requests / min
Rental status (list & detail)
600 requests / min
Fetch SMS
600 requests / min
Actions (finish, cancel, resend, replace)
30 requests / min
Live status/SMS refresh
At most one upstream refresh per rental every 5s

Every response includes X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers for the primary limiter applied to that endpoint. Other limiters (per-rental cancel-like budgets, idempotency replay) are not surfaced. Use these headers to back off before hitting 429 RATE_LIMITED.

X-RateLimit-Limit
Maximum requests allowed in the current window for the primary limiter applied to this endpoint.
X-RateLimit-Remaining
Requests remaining in the current window. Clients can use this to throttle proactively before hitting 429.
X-RateLimit-Reset
Seconds until the current rate-limit window resets.
Retry-After
Present only on 429 RATE_LIMITED. Seconds to wait before retrying the same request.

For high throughput, size your client by aggregate request rate rather than by thread count: put a shared limiter in front of all workers, read the rate-limit headers on every response, and sleep for Retry-After seconds when you receive a 429. Rental status and SMS reads are served from SMSINBOX, so polling every few seconds per rental is fine. Cancel and replace also enforce a per-rental guard, so repeated attempts on the same rental within a few seconds can be limited separately.

Field Conventions

Timestamps
ISO 8601 UTC strings (e.g. 2026-05-16T20:38:00.000Z).
Prices
Integer microcents (1 USD = 1,000,000) unless a field is explicitly named min_price — that field is a USD float.
Phone numbers
Digits-only, no leading + (e.g. 447529522368). Treat as an E.164 number minus the plus sign and prepend + on your side if needed.
SMS text
sms_text and sms_messages[].text are decoded UTF-8 strings (HTML entities like &#39; are decoded back to ').
IDs
All identifiers (rentals, SMS messages, quotes) are version-4 UUIDs.
Error envelope
Failures return { "data": null, "error": { "code": "...", "message": "..." } } with the HTTP status documented per endpoint.

Endpoints List

Endpoint Contracts

GET/catalog/services

List visible services available for short-term rentals.

Request

Auth

  • Authorization: Bearer smsi_your_key

Body

  • None.

Success Response

200 OK

Returns visible services with display name, minimum price in USD, and total available count. min_price and total_count are always present; either can be null when upstream stats are unavailable. min_price is an approximate lowest price from the upstream catalog and may differ slightly from the cheapest offer surfaced by /catalog/price.

Errors

Error responses use the same envelope with data set to null and an error code/message payload.

401 AUTH_UNAUTHORIZED429 RATE_LIMITED500 INTERNAL_ERROR
Request Example
curl \
  -H "Authorization: Bearer smsi_your_key" \
  "https://smsinbox.net/api/client/v1/catalog/services"
Response Example
{
  "data": [
    {
      "slug": "wa",
      "name": "WhatsApp",
      "min_price": 0.135,
      "total_count": 42
    }
  ],
  "error": null
}
GET/catalog/countries

List countries where a service currently has visible inventory.

Request

Auth

  • Authorization: Bearer smsi_your_key

Query

  • service_slug is required.

Body

  • None.

Success Response

200 OK

Returns countries for the requested service with minimum price in USD and total available count. min_price and total_count are always present; either can be null when upstream stats are unavailable. min_price is an approximate lowest price from the upstream catalog and may differ slightly from the cheapest offer surfaced by /catalog/price.

Errors

Error responses use the same envelope with data set to null and an error code/message payload.

400 VALIDATION_ERROR401 AUTH_UNAUTHORIZED429 RATE_LIMITED500 INTERNAL_ERROR
Request Example
curl \
  -H "Authorization: Bearer smsi_your_key" \
  "https://smsinbox.net/api/client/v1/catalog/countries?service_slug=wa"
Response Example
{
  "data": [
    {
      "code": "16",
      "name": "United Kingdom",
      "min_price": 0.135,
      "total_count": 18
    }
  ],
  "error": null
}
GET/catalog/price

Get price options and optionally create a short-lived quote for purchase.

Request

Auth

  • Authorization: Bearer smsi_your_key

Query

  • service_slug and country_code are required.
  • quote=1 returns price_quote_id and quote_expires_at; without it those two fields are omitted from the response.

Body

  • None.

Success Response

200 OK

Returns current price options. Price fields are integer microcents unless a field is explicitly named min_price. operators[].name is any for the aggregate option or a carrier slug supplied by the upstream catalog (e.g. o2, ee, vodafone); the set of carriers varies per country/service. The response below shows the shape when quote=1 is supplied; without quote=1 the price_quote_id and quote_expires_at fields are omitted.

Errors

Error responses use the same envelope with data set to null and an error code/message payload.

400 VALIDATION_ERROR400 RENTAL_OUT_OF_STOCK401 AUTH_UNAUTHORIZED429 RATE_LIMITED500 INTERNAL_ERROR
Request Example
curl \
  -H "Authorization: Bearer smsi_your_key" \
  "https://smsinbox.net/api/client/v1/catalog/price?service_slug=wa&country_code=16&quote=1"
Response Example
{
  "data": {
    "as_of": "2026-05-16T20:30:00.000Z",
    "is_stale": false,
    "rental_purchase_enabled": true,
    "price_quote_id": "00000000-0000-4000-8000-000000000000",
    "quote_expires_at": "2026-05-16T20:31:15.000Z",
    "default_price": {
      "charged_price": 1350000,
      "count": 18
    },
    "operators": [
      {
        "name": "any",
        "charged_price": 1350000,
        "count": 18
      },
      {
        "name": "o2",
        "charged_price": 1350000,
        "count": 6
      },
      {
        "name": "vodafone",
        "charged_price": 1400000,
        "count": 5
      }
    ],
    "rentals": [
      {
        "hours": 2,
        "charged_price": 1350000,
        "count": 18
      }
    ],
    "operator_rentals": {
      "any": [
        {
          "hours": 2,
          "charged_price": 1350000,
          "count": 18
        }
      ]
    },
    "offers": [
      {
        "charged_price": 1350000,
        "count": 18
      }
    ]
  },
  "error": null
}
POST/rentals

Buy one or more short-term numbers.

Request

Auth

  • Authorization: Bearer smsi_your_key

Headers

  • Content-Type: application/json
  • Idempotency-Key is optional and recommended for safe retries.

Body

  • service_slug and country_code are required.
  • quantity accepts 1..10 and defaults to 1.
  • duration_minutes accepts 20..720 and defaults to 20.
  • operator, max_price, and price_quote_id are optional.
  • max_price uses integer microcents.
  • Unknown body fields are rejected with VALIDATION_ERROR (strict schema).

Success Response

201 Created

Creates rentals and returns the purchased rental records plus the requested quantity.

Errors

Error responses use the same envelope with data set to null and an error code/message payload.

400 VALIDATION_ERROR400 INVALID_OPERATOR400 RENTAL_OUT_OF_STOCK401 AUTH_UNAUTHORIZED402 BALANCE_INSUFFICIENT403 FEATURE_DISABLED_BY_ADMIN409 IDEMPOTENCY_KEY_CONFLICT409 PRICE_CHANGED409 QUOTE_NOT_FOUND429 RATE_LIMITED500 INTERNAL_ERROR
Request Example
curl -X POST "https://smsinbox.net/api/client/v1/rentals" \
  -H "Authorization: Bearer smsi_your_key" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \
  -d '{
    "service_slug": "wa",
    "country_code": "16",
    "quantity": 1,
    "duration_minutes": 20,
    "price_quote_id": "00000000-0000-4000-8000-000000000000"
  }'
Response Example
{
  "data": {
    "rentals": [
      {
        "id": "00000000-0000-4000-8000-000000000000",
        "phone_number": "15551234567",
        "service_slug": "wa",
        "service_name": "WhatsApp",
        "country_code": "16",
        "country_name": "United Kingdom",
        "charged_price": 1350000,
        "status": "active",
        "sms_code": null,
        "sms_text": null,
        "sms_messages": [],
        "selected_operator": null,
        "selected_duration_min": 20,
        "selected_max_price": null,
        "replaced_from_rental_id": null,
        "can_cancel_after": "2026-05-16T20:35:00.000Z",
        "sms_resend_available_at": null,
        "expires_at": "2026-05-16T20:55:00.000Z",
        "created_at": "2026-05-16T20:30:00.000Z",
        "updated_at": "2026-05-16T20:30:00.000Z"
      }
    ],
    "quantity": 1
  },
  "error": null
}
GET/rentals

List the caller's short-term rentals.

Request

Auth

  • Authorization: Bearer smsi_your_key

Query

  • page defaults to 1.
  • page_size accepts 1..100 and defaults to 20.

Body

  • None.

Success Response

200 OK

Returns the caller's rentals with pagination metadata.

Errors

Error responses use the same envelope with data set to null and an error code/message payload.

400 VALIDATION_ERROR401 AUTH_UNAUTHORIZED429 RATE_LIMITED500 INTERNAL_ERROR
Request Example
curl \
  -H "Authorization: Bearer smsi_your_key" \
  "https://smsinbox.net/api/client/v1/rentals?page=1&page_size=20"
Response Example
{
  "data": {
    "rentals": [
      {
        "id": "00000000-0000-4000-8000-000000000000",
        "phone_number": "15551234567",
        "service_slug": "wa",
        "service_name": "WhatsApp",
        "country_code": "16",
        "country_name": "United Kingdom",
        "charged_price": 1350000,
        "status": "active",
        "sms_code": null,
        "sms_text": null,
        "sms_messages": [],
        "selected_operator": null,
        "selected_duration_min": 20,
        "selected_max_price": null,
        "replaced_from_rental_id": null,
        "can_cancel_after": "2026-05-16T20:35:00.000Z",
        "sms_resend_available_at": null,
        "expires_at": "2026-05-16T20:55:00.000Z",
        "created_at": "2026-05-16T20:30:00.000Z",
        "updated_at": "2026-05-16T20:30:00.000Z"
      }
    ],
    "total": 1,
    "page": 1,
    "page_size": 20
  },
  "error": null
}
GET/rentals/{id}

Get current stored status and details for one rental.

Request

Auth

  • Authorization: Bearer smsi_your_key

Path

  • id must be a rental UUID owned by the API key user.

Body

  • None.

Success Response

200 OK

Returns one rental object with client-safe fields only.

Errors

Error responses use the same envelope with data set to null and an error code/message payload.

400 VALIDATION_ERROR401 AUTH_UNAUTHORIZED404 RENTAL_NOT_FOUND429 RATE_LIMITED500 INTERNAL_ERROR
Request Example
curl \
  -H "Authorization: Bearer smsi_your_key" \
  "https://smsinbox.net/api/client/v1/rentals/00000000-0000-4000-8000-000000000000"
Response Example
{
  "data": {
    "id": "00000000-0000-4000-8000-000000000000",
    "phone_number": "15551234567",
    "service_slug": "wa",
    "service_name": "WhatsApp",
    "country_code": "16",
    "country_name": "United Kingdom",
    "charged_price": 1350000,
    "status": "active",
    "sms_code": null,
    "sms_text": null,
    "sms_messages": [],
    "selected_operator": null,
    "selected_duration_min": 20,
    "selected_max_price": null,
    "replaced_from_rental_id": null,
    "can_cancel_after": "2026-05-16T20:35:00.000Z",
    "sms_resend_available_at": null,
    "expires_at": "2026-05-16T20:55:00.000Z",
    "created_at": "2026-05-16T20:30:00.000Z",
    "updated_at": "2026-05-16T20:30:00.000Z"
  },
  "error": null
}
GET/rentals/{id}/sms

Read SMS code, text, all SMS messages, and rental status.

Request

Auth

  • Authorization: Bearer smsi_your_key

Path

  • id must be a rental UUID owned by the API key user.

Body

  • None.

Success Response

200 OK

Returns the latest SMS fields, all stored SMS messages, and the current rental status.

Errors

Error responses use the same envelope with data set to null and an error code/message payload.

400 VALIDATION_ERROR401 AUTH_UNAUTHORIZED404 RENTAL_NOT_FOUND429 RATE_LIMITED500 INTERNAL_ERROR
Request Example
curl \
  -H "Authorization: Bearer smsi_your_key" \
  "https://smsinbox.net/api/client/v1/rentals/00000000-0000-4000-8000-000000000000/sms"
Response Example
{
  "data": {
    "sms_code": "123456",
    "sms_text": "Your verification code is 123456.",
    "sms_messages": [
      {
        "id": "22222222-2222-4222-8222-222222222222",
        "code": "123456",
        "text": "Your verification code is 123456.",
        "received_at": "2026-05-16T20:38:00.000Z"
      }
    ],
    "status": "sms_received"
  },
  "error": null
}
POST/rentals/{id}/cancel

Cancel an unused rental and refund when cancellation is still allowed.

Request

Auth

  • Authorization: Bearer smsi_your_key

Path

  • id must be a rental UUID owned by the API key user.

Body

  • None.

Success Response

200 OK

Confirms that the rental was cancelled and refunded. Repeated cancel attempts against the same rental within a short window may return 429 RATE_LIMITED (with Retry-After) before the per-rental status check runs; do not retry on 429 — the prior cancel either already succeeded (idempotent) or the rental is no longer active.

Errors

Error responses use the same envelope with data set to null and an error code/message payload.

400 VALIDATION_ERROR401 AUTH_UNAUTHORIZED403 RENTAL_CANCEL_LOCKED404 RENTAL_NOT_FOUND409 RENTAL_ACTION_UNAVAILABLE409 RENTAL_CANCEL_NOT_ALLOWED409 RENTAL_NOT_ACTIVE429 RATE_LIMITED502 RENTAL_CANCEL_FAILED
Request Example
curl -X POST \
  -H "Authorization: Bearer smsi_your_key" \
  "https://smsinbox.net/api/client/v1/rentals/00000000-0000-4000-8000-000000000000/cancel"
Response Example
{
  "data": {
    "message": "rental cancelled and refunded"
  },
  "error": null
}
POST/rentals/{id}/resend

Request another SMS for a rental after an SMS has already arrived.

Request

Auth

  • Authorization: Bearer smsi_your_key

Path

  • id must be a rental UUID owned by the API key user.

Body

  • None.

Success Response

200 OK

Confirms the resend request and returns the next resend availability timestamp.

Errors

Error responses use the same envelope with data set to null and an error code/message payload.

400 VALIDATION_ERROR401 AUTH_UNAUTHORIZED404 RENTAL_NOT_FOUND409 RENTAL_ACTION_UNAVAILABLE409 RENTAL_NOT_ACTIVE409 RENTAL_SMS_CODE_REQUIRED429 RENTAL_RESEND_LOCKED429 RATE_LIMITED500 INTERNAL_ERROR
Request Example
curl -X POST \
  -H "Authorization: Bearer smsi_your_key" \
  "https://smsinbox.net/api/client/v1/rentals/00000000-0000-4000-8000-000000000000/resend"
Response Example
{
  "data": {
    "message": "sms resend requested",
    "resend_available_at": "2026-05-16T20:40:00.000Z"
  },
  "error": null
}
POST/rentals/{id}/finish

Mark a rental finished after SMS has arrived.

Request

Auth

  • Authorization: Bearer smsi_your_key

Path

  • id must be a rental UUID owned by the API key user.

Body

  • None.

Success Response

200 OK

Confirms that the rental was finished.

Errors

Error responses use the same envelope with data set to null and an error code/message payload.

400 VALIDATION_ERROR401 AUTH_UNAUTHORIZED404 RENTAL_NOT_FOUND409 RENTAL_NOT_ACTIVE409 RENTAL_SMS_CODE_REQUIRED429 RATE_LIMITED500 INTERNAL_ERROR
Request Example
curl -X POST \
  -H "Authorization: Bearer smsi_your_key" \
  "https://smsinbox.net/api/client/v1/rentals/00000000-0000-4000-8000-000000000000/finish"
Response Example
{
  "data": {
    "message": "rental finished"
  },
  "error": null
}
POST/rentals/{id}/replace

Replace a still-unused active rental when replacement is allowed.

Request

Auth

  • Authorization: Bearer smsi_your_key

Path

  • id must be a rental UUID owned by the API key user.

Headers

  • Idempotency-Key is optional and recommended for safe retries.

Body

  • None.

Success Response

200 OK

Returns the newly purchased replacement rental. The source rental's status becomes 'cancelled' (the API does not use a separate 'replaced' state); to distinguish a replace from a user-initiated cancel, read the new rental's replaced_from_rental_id field. Repeated replace attempts against the same rental within a short window may return 429 RATE_LIMITED (with Retry-After) before the per-rental status check runs.

Errors

Error responses use the same envelope with data set to null and an error code/message payload.

400 VALIDATION_ERROR400 RENTAL_OUT_OF_STOCK401 AUTH_UNAUTHORIZED403 FEATURE_DISABLED_BY_ADMIN404 RENTAL_NOT_FOUND409 IDEMPOTENCY_KEY_CONFLICT409 RENTAL_ACTION_UNAVAILABLE409 RENTAL_NOT_ACTIVE409 RENTAL_REPLACE_NOT_ALLOWED429 RENTAL_REPLACE_LOCKED429 RATE_LIMITED500 RENTAL_REPLACE_FAILED502 RENTAL_REPLACE_FAILED
Request Example
curl -X POST \
  -H "Authorization: Bearer smsi_your_key" \
  -H "Idempotency-Key: 9b3a2c0d-6d7f-4a11-9c6a-2a4f1d9e5c21" \
  "https://smsinbox.net/api/client/v1/rentals/00000000-0000-4000-8000-000000000000/replace"
Response Example
{
  "data": {
    "id": "11111111-1111-4111-8111-111111111111",
    "phone_number": "15557654321",
    "service_slug": "wa",
    "service_name": "WhatsApp",
    "country_code": "16",
    "country_name": "United Kingdom",
    "charged_price": 1350000,
    "status": "active",
    "sms_code": null,
    "sms_text": null,
    "sms_messages": [],
    "selected_operator": null,
    "selected_duration_min": 20,
    "selected_max_price": null,
    "replaced_from_rental_id": "00000000-0000-4000-8000-000000000000",
    "can_cancel_after": "2026-05-16T20:42:00.000Z",
    "sms_resend_available_at": null,
    "expires_at": "2026-05-16T21:02:00.000Z",
    "created_at": "2026-05-16T20:37:00.000Z",
    "updated_at": "2026-05-16T20:37:00.000Z"
  },
  "error": null
}