Authentication
All requests must include an Authorization header with a Bearer token. Generate keys in Settings → API keys. Keys are shown only once at creation; if you lose one, revoke it and create a new one.
Authorization: Bearer pck_eXaMpLe_DO_not_use_this_one
Keys are scoped to a single organization and a single set of permissions (default: verifications:write). Each request touches last_used_at on the key.
/api/v1/verificationsCreate a verification
Creates an order, sends a single SMS to the assigned driver with a unique check-in link, and returns a verification record. Idempotent on (source, external_order_id, location_id) — re-sending the same identifier returns 409 Conflict.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
| external_order_id | string | Yes | Your order identifier. Unique per location. |
| customer_name | string | Yes | End-customer name. Truncated to first + last initial on the counter display. |
| driver_phone | string | Yes | E.164 format (e.g. +15035551234). |
| driver_name | string | No | Display name. Defaults to the existing driver record if known. |
| location_id | uuid | No | Defaults to the org's first location if omitted. |
Example — curl
curl -X POST https://pickcounter.io/api/v1/verifications \
-H "Authorization: Bearer pck_..." \
-H "Content-Type: application/json" \
-d '{
"external_order_id": "4421",
"customer_name": "Thomas Johnson",
"driver_phone": "+15035550101",
"driver_name": "Sarah M."
}'Example — Node
const res = await fetch("https://pickcounter.io/api/v1/verifications", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.HANDOFF_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
external_order_id: "4421",
customer_name: "Thomas Johnson",
driver_phone: "+15035550101",
driver_name: "Sarah M.",
}),
});
const verification = await res.json();Response — 201 Created
{
"object": "verification",
"id": "f3a1c2b8-0c10-4b3a-9d3a-58a4c0b8e7c2",
"order_id": "5b9d2c00-9e1c-44d2-9f2e-77ac0c9e1d11",
"status": "notified",
"sms_sent": true,
"sms_sid": "SM5b9d2c..."
}/api/v1/verifications/{id}Retrieve a verification
Returns current status and timestamps for a verification.
Response — 200 OK
{
"object": "verification",
"id": "f3a1c2b8-0c10-4b3a-9d3a-58a4c0b8e7c2",
"order_id": "5b9d2c00-9e1c-44d2-9f2e-77ac0c9e1d11",
"external_order_id": "4421",
"customer_name": "Thomas Johnson",
"driver_name": "Sarah M.",
"status": "checked_in",
"notified_at": "2026-04-19T22:41:08Z",
"checked_in_at": "2026-04-19T22:48:55Z",
"handed_off_at": null,
"checkin_method": "qr",
"failure_reason": null
}Errors
Errors return JSON with a single error field and a standard HTTP status. Common cases:
| Status | Meaning |
|---|---|
| 400 | Bad request — body failed validation. |
| 401 | Missing or invalid Bearer token. |
| 403 | Key valid but lacks the required scope. |
| 409 | Order with that external_order_id already exists. |
| 429 | Rate limited. Retry after a short backoff. |
| 503 | Service temporarily unavailable. |
Rate limits
Each API key is limited to 120 requests per minute on the verifications endpoint. Limits exist primarily to keep SMS spend predictable; if you have a legitimate higher-volume use case, email hello@pickcounter.io.
Webhooks (coming soon)
Subscribe to verification lifecycle events (order.notified, order.checked_in, order.handed_off). HMAC-signed POST callbacks. We'll publish the schema once the first integration partner is live.