HTTP API
Complete workflows with the Phonekit API
The API owns authorization, entitlements, provisioning and durable delivery. Your caller owns SMS polling, matching, deadlines and cancellation. The SDK wraps these same HTTP operations.
Authenticate deliberately
Create a credential in Settings → Automation. Select permissions and exact line grants separately for message reads and management. Existing credentials retain messages:read only. No credential administration API is required.
Send Authorization: Bearer $PHONEKIT_API_KEY over HTTPS. GET /api/v1/me returns the organization, connection identity, permissions, readable numbers and managedNumberIds. A number visible to a person is not automatically readable through a credential.
Download the OpenAPI specification for complete request and response schemas.
Discover before acting
| Method and path | Purpose |
|---|---|
GET /api/v1/me | Connection identity, permissions and explicit scopes |
GET /api/v1/number-types | Supported types and actual receive/send/voice capabilities |
GET /api/v1/allowance | Plan, usage and remaining capacity; requires numbers:manage |
GET /api/v1/numbers | Readable lines |
GET /api/v1/numbers/{numberRef} | Exact authorized line metadata and readiness |
GET /api/v1/members | Eligible member IDs/names/roles for assignment/sharing; requires numbers:manage |
GET /api/v1/inventory?areaCode=415 | Supported available lines; requires numbers:manage |
Scroll horizontally to see all columns.
Starter, Team and Scale include programmatic surfaces, authorized number management and webhooks, with 30-day default message retention. See pricing for included Standard/Mobile numbers, members, separate monthly SMS pools and overage rates. Workspace overrides replace plan defaults; purchased number additions extend capacity and the matching SMS pool. Membership limits apply to people who have joined, including owners and administrators. API keys and agents do not consume member places. subscription reports USD customer fees and monthly SMS capacity. sms reports the billing-period boundaries, per-class usage and estimated overage; exceeding the pool does not block delivery. Mobile capacity is reported as mobileNumbers. Supplier-cost limits are separate provisioning controls; nullable supplier-cost fields do not mean customer pricing is free.
Use number-type capabilities and inventory to choose a supported number for the workflow. Number acceptance by a target service is not guaranteed. readiness.canReceive requires active status; local fixtures are identified as simulated.
Acquire, configure and release
POST /api/v1/numbers requires numbers:manage, a UUID requestId (or matching Idempotency-Key header), explicit sharing, memberIds, and grantReadAccess choice:
{
"requestId": "90af27b0-275b-4c82-9f10-69d55f61203d",
"phoneNumber": "+14155550101",
"label": "QA account",
"sharing": "restricted",
"memberIds": [],
"grantReadAccess": true,
"purpose": "Invitation acceptance"
}Save the UUID before sending. Retry with the same UUID and identical input; a changed body returns idempotency_conflict. A successful response contains operationId, numberId and statusUrl. It records an acquisition; it does not claim activation has completed. GET /api/v1/operations/{operationId} returns pending/completed/failed status, readiness and retry timing. POST /api/v1/numbers/{numberRef}/recheck reconciles a pending acquisition without repurchasing.
Capacity is reserved atomically for pending purchases. Ambiguous provider outcomes keep their reservation until reconciled. Optional maxSetupCostMinor and maxMonthlyCostMinor are explicit price ceilings; an unavailable quote cannot satisfy a ceiling.
PATCH /api/v1/numbers/{numberRef} accepts label, purpose, assignedToUserId, or access: {sharing, memberIds}. Assignment is metadata; sharing governs human access. Owners and admins retain access. Management grants do not grant message reads.
DELETE /api/v1/numbers/{numberRef} saves an authorized release intent for an active selected line and attempts provider release. It returns {ok:true,numberId,status} where status is released or release_pending. Follow GET /api/v1/numbers/{numberRef} for release.status, release.requestedAt and a safe retry detail. A pending release retains capacity until the provider confirms it. Phonekit retries durable intent even if the original connection is subsequently revoked. Retained messages keep their original receipt-based expiry. New write requests still check current permissions and creator membership.
Read fresh receipts immediately
Mark before your application requests SMS:
curl --silent --show-error --fail-with-body \
--header "Authorization: Bearer ${PHONEKIT_API_KEY}" \
"https://www.phonekit.io/api/v1/numbers/${PHONEKIT_NUMBER_ID}/cursor"Then call GET /api/v1/numbers/{numberRef}/messages/after?after={cursor}&limit=25. Reads return promptly in ascending receipt order:
{"data": [], "cursor": "c_djE6MTAw", "hasMore": false}Nonempty data contains messages with id, numberId, sender, body, otp, links and receivedAt. The cursor advances past the last returned receipt; an empty read leaves it unchanged. hasMore indicates another page existed at read time. Limits are 1–100. Preserve opaque cursors unchanged.
The caller decides matching, interval, deadline, cancellation, resends and parallel work. Inspect unrelated receipts deliberately and save progress. SDK/CLI convenience waits repeat immediate reads locally. MCP tools return promptly. Phonekit has no customer wait sessions, concurrency packaging or test scheduler. Normal API rate limits are operational controls.
Retained messages and selected subscriptions
GET /api/v1/messages?numberId=…&limit=10&cursor=… returns newest-first retained pages {data,nextCursor}. GET /api/v1/messages/{messageId} reads the exact retained receipt, including the ID from a webhook event. Scope and retention apply equally to full content and OTP extraction.
| Method and path | Permission |
|---|---|
GET /api/v1/webhooks and GET /api/v1/webhooks/{id} | webhooks:manage |
POST /api/v1/webhooks with {url,numberIds} | webhooks:manage |
PATCH /api/v1/webhooks/{id} with URL or replacement number IDs | webhooks:manage |
DELETE /api/v1/webhooks/{id} | webhooks:manage |
GET /api/v1/deliveries and GET /api/v1/deliveries/{id} | diagnostics:read |
POST /api/v1/deliveries/{id}/retry | webhooks:manage |
Scroll horizontally to see all columns.
Subscribe explicit management-scoped line IDs to a public HTTPS endpoint. Creation returns the signing secret once. A subscription must be wholly within the connection's selected scope. Legacy subscriptions need an explicit line selection before delivery resumes.
Events use stable IDs and may duplicate. Deduplicate durably; read exact message IDs, and recover gaps with saved inbox cursors. Diagnostics expose sanitized attempt status/categories and retry timing. They omit message text, credentials and destination response bodies. See webhook verification.
Distinguish failures
Errors contain code, safe message, requestId, and applicable retryAfterSeconds. Responses include X-Request-Id; rate-limit responses use Retry-After. No result is evidence that the target service accepted a verification code.
| Failure | Meaning |
|---|---|
401 | Missing, expired or revoked authentication |
403 / permission_required | Explicit permission or current membership is missing |
404 | Resource outside scope or retention |
409 / allowance_exhausted | Active and pending acquisitions consume the line allowance |
409 / idempotency_conflict | Same UUID with a different acquisition body |
409 / pricing_unavailable | An explicit spend ceiling cannot be evaluated |
429 | Operational rate limit; honor retry timing |
5xx | Service failure; bounded retries for safe/idempotent operations |
Scroll horizontally to see all columns.
An empty immediate read is successful. SDK timeout, no_match, missing_otp/extraction_failed, ambiguous and cancelled describe caller-side outcomes. Keep message contents and bearer credentials out of shared logs.