API Reference

The JoltSMS REST API lets you manage phone numbers, read SMS messages, send constrained replies to eligible inbound SMS, control billing, configure notifications, and collaborate with team members. All requests use the base URL https://api.joltsms.com/v1 and require an Authorization: Bearer jolt_sk_xxx header or the same key in the X-API-Key header.

OpenAPI Specification

Download the machine-readable OpenAPI spec to auto-generate API clients, create Custom GPT Actions, or build LangChain toolkits.

https://joltsms.com/openapi.json

Common Patterns

Cursor Pagination

All list endpoints return paginated results with the same envelope. Pass the cursor value from the previous response to fetch the next page. limit defaults to 20 (capped at 10 for API key authentication).

{
  "data": [ ... ],
  "meta": {
    "hasMore": true,
    "nextCursor": "MjAyNS0wNi0xNVQxMjowMDowMC4wMDBafGFiY2QxMjM0",
    "total": 42,
    "limit": 20
  }
}

Error Format

Errors follow a consistent JSON structure across all endpoints.

{
  "error": "NOT_FOUND",
  "message": "Number not found or you do not have access"
}

API Key Scopes

API keys can be scoped to personal/team numbers, selected numbers, or one enterprise contract. Scoped keys filter GET /v1/numbers and GET /v1/messages. Existing keys created before scoped keys behave as personal keys.

{
  "scopeType": "ENTERPRISE_CONTRACT",
  "enterpriseContractId": "contract_uuid_here"
}

API Key Capabilities

Sensitive write capabilities are opt-in at API key creation. SMS replies require the sms:reply capability in addition to the key's normal number scope. Existing keys do not receive this capability automatically.

{
  "capabilities": ["sms:reply"]
}

Rate Limit Headers

Every response includes rate limit headers. API key requests are limited to 120 requests per minute.

HeaderDescription
X-RateLimit-LimitMaximum requests allowed per window (120 for API keys)
X-RateLimit-RemainingRequests remaining in the current window
X-RateLimit-ResetSeconds remaining until the rate limit window resets

API Key Management

Create and revoke API keys from a logged-in browser session. API keys are shown once at creation time and can be scoped to personal/team numbers, selected numbers, or an enterprise contract.

API key management is session-only. Calling these endpoints with an API key or OAuth bearer token returns SESSION_REQUIRED.

GET/v1/api-keys

List API keys for the authenticated user, including scope metadata.

POST/v1/api-keys

Create an API key. The raw key is returned once.

ParameterTypeDescription
name*stringHuman-readable key name.
expiresAtstringOptional ISO 8601 expiration datetime.
scopeTypestringPERSONAL, ENTERPRISE_CONTRACT, or NUMBER_SET. Defaults from provided fields.
enterpriseContractIdstringRequired for ENTERPRISE_CONTRACT keys.
numberIdsstring[]Required for NUMBER_SET keys. Maximum 1000 number IDs.
capabilitiesstring[]Optional sensitive write capabilities. Use ["sms:reply"] to allow replies to eligible inbound SMS.
DELETE/v1/api-keys/:id

Revoke an API key. This cannot be undone.

Create an enterprise contract key

curl -X POST "https://api.joltsms.com/v1/api-keys" \
  -H "Content-Type: application/json" \
  -H "Cookie: joltsms_session=..." \
  -d '{
    "name": "Enterprise contract automation",
    "scopeType": "ENTERPRISE_CONTRACT",
    "enterpriseContractId": "contract_uuid_here"
  }'

Response

{
  "key": "jolt_sk_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6",
  "id": "api_key_uuid",
  "name": "Enterprise contract automation",
  "prefix": "jolt_sk_a1b2c3d4",
  "scopeType": "ENTERPRISE_CONTRACT",
  "enterpriseContractId": "contract_uuid_here",
  "enterpriseContractName": "Example Enterprise",
  "numberScopeCount": 0,
  "numberScopes": [],
  "capabilities": [],
  "expiresAt": null,
  "createdAt": "2026-06-17T18:00:00.000Z"
}

Numbers

Manage your dedicated phone numbers. Each number is a real-SIM U.S. number that receives inbound SMS. API-key requests are filtered by the key's scope.

GET/v1/numbers

List your phone numbers with optional status and scope filtering.

ParameterTypeDescription
scopestringFilter by ownership: "all" (default), "owned", or "shared".
statusstringFilter by status: active, provisioning, releasing, released, failed, suspended, cancelled.
cursorstringPagination cursor from a previous response.
limitnumberResults per page. Default 20, max 10 for API keys.
POST/v1/numbers/rent

Provision a new phone number. This creates a Stripe subscription and begins the provisioning process.

ParameterTypeDescription
areaCodestringPreferred 3-digit U.S. area code (e.g., "609"). Optional -- omit for any available number.
preferredAreaCodebooleanIf true, falls back to any available number when the requested area code is unavailable. Default false.
autoRenewbooleanEnable auto-renewal at end of billing cycle. Default true.
GET/v1/numbers/:id

Retrieve a single number by ID, including message counts, subscription details, and team access info.

PUT/v1/numbers/:id

Update a number's notes or tags. Requires browser session authentication.

ParameterTypeDescription
notesstringFree-text notes about this number.
tagsstring[]Array of tag strings for categorization.

Example

curl -X GET "https://api.joltsms.com/v1/numbers?scope=owned&status=active" \
  -H "Authorization: Bearer jolt_sk_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"

Response:

{
  "data": [
    {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "phoneNumber": "+16094130666",
      "status": "ACTIVE",
      "serviceName": "Any Service",
      "tags": ["primary", "otp"],
      "notes": "Used for PayPal verification",
      "createdAt": "2025-06-15T12:00:00.000Z",
      "rentedAt": "2025-06-15T12:05:00.000Z",
      "expiresAt": "2025-07-15T12:05:00.000Z",
      "messageCount": 23,
      "unreadCount": 2,
      "lastMessageAt": "2025-06-20T08:30:00.000Z",
      "isShared": false,
      "accessRole": "OWNER"
    }
  ],
  "meta": {
    "hasMore": false,
    "total": 1,
    "limit": 20
  }
}

Messages

Read inbound SMS messages across all your numbers (owned and shared), and reply to eligible inbound SMS conversations. API-key requests are filtered by the key's scope. Messages from vendor systems are automatically filtered out.

GET/v1/messages

List SMS messages with optional filtering by number, sender, recipient, or date.

ParameterTypeDescription
numberIdstringFilter to messages for a specific number (UUID).
fromstringFilter by sender phone number.
tostringFilter by recipient phone number.
sincestringISO 8601 datetime -- only return messages after this time.
cursorstringPagination cursor from a previous response.
limitnumberResults per page. Default 20, max 10 for API keys.
GET/v1/messages/search

Full-text search across message bodies. Supports all the same filters as the list endpoint.

ParameterTypeDescription
q*stringSearch query (1-100 characters).
numberIdstringLimit search to a specific number.
cursorstringPagination cursor.
limitnumberResults per page. Default 20, max 50.
GET/v1/messages/:id

Retrieve a single message by ID.

POST/v1/messages/:id/reply

Reply to a specific inbound SMS. The destination is resolved server-side from the original message.

ParameterTypeDescription
content*stringReply body, 1-15 characters. Destination fields are not accepted.

API keys must be created with the sms:reply capability. The authenticated user still needs Manager or Owner access to the number, and the message must have a provider SMS ID that TextVerified can reply to. Use the optional X-Idempotency-Key header to safely retry a reply attempt.

PUT/v1/messages/:id/read

Mark a single message as read.

PUT/v1/messages/mark-all-read

Mark all messages as read, optionally scoped to a single number.

ParameterTypeDescription
numberIdstringIf provided, only mark messages for this number as read.

Example

curl -X GET "https://api.joltsms.com/v1/messages?numberId=a1b2c3d4-e5f6-7890-abcd-ef1234567890&limit=5" \
  -H "Authorization: Bearer jolt_sk_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"

Reply example

curl -X POST "https://api.joltsms.com/v1/messages/f1e2d3c4-b5a6-7890-1234-567890abcdef/reply" \
  -H "Authorization: Bearer jolt_sk_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6" \
  -H "Content-Type: application/json" \
  -H "X-Idempotency-Key: reply-f1e2d3c4-001" \
  -d '{"content":"Thanks, received."}'

Reply response:

{
  "success": true,
  "replyId": "0f5c6a5b-5b8f-45f4-9d2f-491a5d00f093",
  "messageId": "f1e2d3c4-b5a6-7890-1234-567890abcdef",
  "status": "SENT",
  "sentAt": "2026-06-19T18:30:00.000Z",
  "correlationId": "req_abc123",
  "message": "Reply sent."
}

Reply failures are intentionally generalized. JoltSMS does not expose raw TextVerified error payloads to users or API clients; responses use messages like "This SMS cannot be replied to" or "Reply could not be sent right now."

Response:

{
  "data": [
    {
      "id": "f1e2d3c4-b5a6-7890-1234-567890abcdef",
      "numberId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "number": {
        "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
        "phoneNumber": "+16094130666"
      },
      "from": "+18005551234",
      "to": "+16094130666",
      "body": "Your verification code is 847293. Do not share this with anyone.",
      "parsedCode": "847293",
      "isRead": false,
      "receivedAt": "2025-06-20T08:30:00.000Z",
      "ingestedAt": "2025-06-20T08:30:01.000Z"
    }
  ],
  "meta": {
    "hasMore": false,
    "nextCursor": null,
    "total": 1,
    "limit": 5,
    "filters": {
      "numberId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
    }
  }
}

Billing

Inspect subscriptions, invoices, and payment methods. Billing is handled through Stripe with 30-day cycles aligned to your SMS provider.

GET/v1/billing/subscriptions

List all subscriptions for your account, including billing health status.

POST/v1/billing/subscriptions/:id/auto-renew

Toggle auto-renewal for a subscription. Disabling auto-renew schedules cancellation at the end of the current billing period.

ParameterTypeDescription
enabled*booleanSet to true to enable auto-renew, false to cancel at period end.
GET/v1/billing/invoices

List invoices for your account. Includes amount, status, and PDF download links. Uses Stripe-style pagination (not cursor-based).

ParameterTypeDescription
startingAfterstringStripe invoice ID to paginate after (e.g., "in_xxx"). Fetch the next page by passing the last invoice ID from the previous response.
statusstringFilter by invoice status: "draft", "open", "paid", "void", or "uncollectible".
limitnumberResults per page. Default 20, max 100.
GET/v1/billing/payment-methods

List saved payment methods. Returns last-4 digits, brand, and expiration.

Example

curl -X POST "https://api.joltsms.com/v1/billing/subscriptions/a1b2c3d4-e5f6-7890-abcd-ef1234567890/auto-renew" \
  -H "Authorization: Bearer jolt_sk_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6" \
  -H "Content-Type: application/json" \
  -d '{ "enabled": false }'

Response:

{
  "success": true
}

Billing health states

Subscriptions include a billingHealth field that summarizes the payment state: healthy, payment_failing, suspended, ending, canceled, or setup_required. SMS reception is active for healthy, payment_failing, and ending.

Notifications

Configure multi-channel notification delivery for SMS events, billing alerts, and number lifecycle changes. Supported channels: Slack, Discord, Email, Telegram, and custom Webhooks (HMAC-SHA256 signed).

Endpoints

GET/v1/notifications/endpoints

List all notification endpoints for your account. Optionally filter by number or endpoint type.

ParameterTypeDescription
numberIdstringFilter endpoints associated with a specific number.
typestringFilter by type: slack, discord, email, telegram, webhook.
POST/v1/notifications/endpoints

Create a new notification endpoint. Webhook URLs are validated against SSRF.

ParameterTypeDescription
type*stringEndpoint type: slack, discord, email, telegram, or webhook.
name*stringDisplay name for the endpoint.
config*objectChannel-specific configuration (e.g., webhookUrl for Slack, email address for email).
PATCH/v1/notifications/endpoints/:id

Update an existing notification endpoint's name, config, or active status.

DELETE/v1/notifications/endpoints/:id

Delete a notification endpoint. System-managed endpoints (auto-created email) cannot be deleted.

Rules

Rules bind events to endpoints. You can create account-level defaults or per-number overrides. Limits: 15 endpoints per user, 10 rules per number.

GET/v1/notifications/rules

List notification rules. Filter by number, event type, or endpoint.

ParameterTypeDescription
numberIdstringFilter rules for a specific number.
eventstringFilter by event type (e.g., SMS_RECEIVED, NUMBER_EXPIRING_7D).
endpointIdstringFilter rules for a specific endpoint.
enabledbooleanFilter by enabled/disabled status.
POST/v1/notifications/rules

Create a notification rule linking an event to an endpoint. Omit numberId for account-level defaults.

ParameterTypeDescription
endpointId*stringThe endpoint to deliver notifications to.
event*stringEvent type: SMS_RECEIVED, NUMBER_EXPIRING_7D, NUMBER_EXPIRING_1D, BILLING_ISSUE.
numberIdstringScope rule to a specific number. Omit for account-level default.
enabledbooleanWhether the rule is active. Default true.
PATCH/v1/notifications/rules/:id

Update a rule's enabled status or event binding.

DELETE/v1/notifications/rules/:id

Delete a notification rule.

Delivery Logs

GET/v1/notifications/attempts

View delivery attempt history. Useful for debugging failed notifications.

ParameterTypeDescription
endpointIdstringFilter attempts for a specific endpoint.
eventstringFilter by event type.
statusstringFilter by delivery status: success, failed, pending.
cursorstringPagination cursor.
limitnumberResults per page.

Team

Share number access with other JoltSMS users. Invite team members with VIEWER (read-only) or MANAGER (configuration and team management) roles. Invitations expire after 7 days.

Team endpoints require the caller to be the owner of the number (except for accepting/declining invitations). Both session and API key authentication are supported.

POST/v1/team/invite

Invite a user to access a number. Sends an email invitation with a 7-day expiry.

ParameterTypeDescription
numberId*stringUUID of the number to share access to.
email*stringEmail address of the user to invite.
rolestringRole to assign: "VIEWER" (default) or "MANAGER".
GET/v1/team/:numberId/members

List all team members for a number, including pending invitations.

PATCH/v1/team/:numberId/members/:userId/role

Update a team member's role.

ParameterTypeDescription
role*string"VIEWER" or "MANAGER".
DELETE/v1/team/:numberId/members/:userId

Remove a team member's access to a number.

Example

curl -X POST "https://api.joltsms.com/v1/team/invite" \
  -H "Cookie: better-auth.session_token=..." \
  -H "Content-Type: application/json" \
  -d '{ "numberId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "email": "[email protected]", "role": "VIEWER" }'

Response:

{
  "success": true,
  "invitationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "message": "Invitation sent successfully"
}

HTTP Status Codes

The API uses standard HTTP status codes to indicate the outcome of each request.

CodeMeaning
200Request succeeded.
201Resource created (e.g., new subscription, new endpoint).
400Bad request -- invalid parameters or request body.
401Unauthorized -- missing, invalid, expired, or revoked API key.
402Payment required -- subscription creation needs valid payment or 3DS confirmation.
403Forbidden -- insufficient permissions or API key used on session-only route.
404Resource not found or you do not have access.
409Conflict -- duplicate idempotency key or resource already exists.
429Too many requests -- rate limit exceeded (120/min for API keys).
500Internal server error. If persistent, contact support.