API reference
Developer docs
Request, response, status code, error, webhook, and rate-limit references for hosted menu links and partner integrations.
Public partner reviewUpdated Jul 13, 2026
Authentication
Every partner request authenticates with a bearer access token. Mutating requests additionally require an idempotency key so retried writes never duplicate.
Every requestAuthorization: Bearer <partner_access_token>
Tbltap-API-Version: 2026-07-13
Idempotency-Key: partner-generated-stable-key
Accept: application/json
Orders
POST/v1/table-sessions/{session_id}/orders
Create order handoff
Creates a retry-safe order handoff tied to a table session, restaurant service state, and staff review rules.
Partner-scoped write30 requests/minute per app + session
Request schema
external_order_idrequired
stringExample: pos_9b2fPartner-generated stable order reference used for reconciliation and support.
items[].menu_item_idrequired
stringExample: mi_crispy_riceApproved menu item identifier from the menu catalog response.
items[].quantityrequired
integerExample: 2Quantity of the item, must be at least 1.
metadata
objectOptional partner-owned reconciliation metadata. Do not include secrets or payment data.
Errors
POST/v1/table-sessions/{session_id}/orders
Response samples
application/json200 OKAccepted or idempotently replayed
{
"object": "order_handoff",
"id": "ordh_123",
"table_session_id": "tbs_123",
"restaurant_id": "rst_123",
"status": "pending_staff_review",
"idempotency_status": "created",
"items_received": 1,
"created_at": "2026-07-13T16:03:12Z",
"request_id": "req_order_01j2x9r9k1"
}
400 Bad RequestValidation failed
{
"error": {
"code": "invalid_request",
"message": "items[0].quantity must be at least 1.",
"type": "invalid_request_error",
"field": "items[0].quantity"
},
"request_id": "req_order_validation",
"docs_url": "https://tblt.app/docs/developers#orders-create"
}
409 ConflictSession cannot accept the mutation
{
"error": {
"code": "table_session_closed",
"message": "This table session is closed and cannot accept new orders.",
"type": "conflict_error"
},
"request_id": "req_order_conflict",
"docs_url": "https://tblt.app/docs/developers#orders-create"
}
GET/v1/table-sessions/{session_id}/orders/{order_id}
Get order handoff
Reads current staff-review status, item-level state, and any rejection reason for a submitted order handoff.
Partner-scoped read60 requests/minute per app + session
Request schema
order_idrequired
stringExample: ordh_123Order handoff identifier returned from the create call.
Errors
GET/v1/table-sessions/{session_id}/orders/{order_id}
Response samples
application/json200 OKOrder handoff returned
{
"object": "order_handoff",
"id": "ordh_123",
"status": "accepted",
"items": [
{ "menu_item_id": "mi_crispy_rice", "quantity": 2, "state": "fired" }
],
"request_id": "req_order_get_01j2x9rd2m"
}
401 UnauthorizedMissing or invalid credential
{
"error": {
"code": "invalid_api_key",
"message": "Use a valid partner access token.",
"type": "authentication_error"
},
"request_id": "req_unauthorized",
"docs_url": "https://tblt.app/docs/developers#authentication"
}
404 Not FoundOrder handoff is outside scope
{
"error": {
"code": "order_handoff_not_found",
"message": "No order handoff was found for this id and credential scope.",
"type": "invalid_request_error"
},
"request_id": "req_order_get_missing",
"docs_url": "https://tblt.app/docs/developers#orders-get"
}
PUT/v1/table-sessions/{session_id}/orders/{order_id}/cancel
Cancel order handoff
Cancels a pending order handoff before staff acceptance. Fired or accepted items cannot be canceled through this route.
Partner-scoped write30 requests/minute per app + session
Request schema
order_idrequired
stringOrder handoff identifier to cancel.
reason
stringOptional partner-supplied cancellation reason for support traceability.
Errors
PUT/v1/table-sessions/{session_id}/orders/{order_id}/cancel
Response samples
application/json200 OKOrder handoff canceled
{
"object": "order_handoff",
"id": "ordh_123",
"status": "canceled",
"request_id": "req_order_cancel_01j2x9re9v"
}
409 ConflictOrder has already been accepted
{
"error": {
"code": "order_already_accepted",
"message": "This order handoff has already been accepted by staff and cannot be canceled.",
"type": "conflict_error"
},
"request_id": "req_order_cancel_conflict",
"docs_url": "https://tblt.app/docs/developers#orders-cancel"
}
404 Not FoundOrder handoff is outside scope
{
"error": {
"code": "order_handoff_not_found",
"message": "No order handoff was found for this id and credential scope.",
"type": "invalid_request_error"
},
"request_id": "req_order_cancel_missing",
"docs_url": "https://tblt.app/docs/developers#orders-cancel"
}
Payments
GET/v1/table-sessions/{session_id}/bill
Get bill state
Reads bill readiness, split state, and payment status without treating client timeouts as payment truth.
Partner-scoped read60 requests/minute per app + session
Request schema
table_session_idrequired
stringTable session being read. The credential must be scoped to the restaurant and session.
bill_ready
booleanWhether staff/server state says the bill can be presented for payment.
payment_status
enumExample: openCurrent payment status: open, partially_paid, or paid.
Errors
GET/v1/table-sessions/{session_id}/bill
Response samples
application/json200 OKCurrent bill snapshot
{
"object": "table_bill",
"table_session_id": "tbs_123",
"restaurant_id": "rst_123",
"bill_ready": true,
"currency": "USD",
"subtotal_minor": 5200,
"tax_minor": 468,
"service_charge_minor": 260,
"tip_minor": 1040,
"total_minor": 6968,
"amount_paid_minor": 0,
"payment_status": "open",
"split_mode": "none",
"updated_at": "2026-07-13T16:05:00Z",
"request_id": "req_bill_01j2x9r9pz"
}
403 ForbiddenCredential lacks required scope
{
"error": {
"code": "scope_denied",
"message": "The credential does not include table_sessions.bill.read.",
"type": "authorization_error",
"required_scope": "table_sessions.bill.read"
},
"request_id": "req_bill_forbidden",
"docs_url": "https://tblt.app/docs/developers#payments-bill"
}
503 Service UnavailablePayment state is being reconciled
{
"error": {
"code": "provider_state_unavailable",
"message": "Payment state is being reconciled. Retry with backoff or wait for webhook confirmation.",
"type": "api_error",
"retry_after_seconds": 30
},
"request_id": "req_bill_provider_unavailable",
"docs_url": "https://tblt.app/docs/developers#payments-bill"
}
POST/v1/table-sessions/{session_id}/payment-intents
Create payment intent
Creates a payment intent for a full or split bill amount ahead of guest checkout.
Partner-scoped write30 requests/minute per app + session
Request schema
amount_minorrequired
integerAmount to collect, in minor currency units. Must not exceed the remaining bill total.
split_group_id
stringOptional identifier grouping guests paying the same bill together.
Errors
POST/v1/table-sessions/{session_id}/payment-intents
Response samples
application/json200 OKPayment intent created
{
"object": "payment_intent",
"id": "pi_123",
"amount_minor": 3484,
"status": "requires_confirmation",
"request_id": "req_pi_01j2x9rf3x"
}
400 Bad RequestAmount exceeds payable state
{
"error": {
"code": "invalid_request",
"message": "amount_minor exceeds the remaining bill total.",
"type": "invalid_request_error",
"field": "amount_minor"
},
"request_id": "req_pi_validation",
"docs_url": "https://tblt.app/docs/developers#payments-intent"
}
409 ConflictBill is locked
{
"error": {
"code": "bill_locked",
"message": "This bill is locked while another payment is in progress.",
"type": "conflict_error"
},
"request_id": "req_pi_conflict",
"docs_url": "https://tblt.app/docs/developers#payments-intent"
}
POST/v1/payment-intents/{payment_intent_id}/confirm
Confirm payment
Confirms a payment intent once the provider has authorized funds. tbltap reconciles authoritative state before marking a bill paid.
Partner-scoped write30 requests/minute per app + session
Request schema
payment_intent_idrequired
stringPayment intent identifier returned from the create call.
provider_charge_idrequired
stringCharge or authorization identifier from the payment provider.
Errors
POST/v1/payment-intents/{payment_intent_id}/confirm
Response samples
application/json200 OKPayment confirmed
{
"object": "payment_intent",
"id": "pi_123",
"status": "succeeded",
"confirmed_at": "2026-07-13T16:11:00Z",
"request_id": "req_pi_confirm_01j2x9rga1"
}
409 ConflictPayment intent is finalized
{
"error": {
"code": "payment_intent_finalized",
"message": "This payment intent has already been confirmed or canceled.",
"type": "conflict_error"
},
"request_id": "req_pi_confirm_conflict",
"docs_url": "https://tblt.app/docs/developers#payments-confirm"
}
503 Service UnavailableProvider confirmation is pending
{
"error": {
"code": "provider_state_unavailable",
"message": "Provider confirmation is pending. Retry with backoff or wait for webhook confirmation.",
"type": "api_error",
"retry_after_seconds": 20
},
"request_id": "req_pi_confirm_unavailable",
"docs_url": "https://tblt.app/docs/developers#payments-confirm"
}
Webhooks
POST/v1/webhook-endpoints
Create webhook endpoint
Registers a signed event destination for approved order, payment, table, POS, or delivery events.
Partner-scoped write10 requests/minute per app
Request schema
urlrequired
https urlExample: https://partner.example.com/tbltap/webhooksPartner destination that receives signed tbltap event payloads.
event_types[]required
array<string>Example: payment.succeededApproved event types for this partner credential and environment.
signing_secret
stringReturned only at creation time. Store it securely and never send it to support.
Errors
POST/v1/webhook-endpoints
Response samples
application/json200 OKWebhook endpoint registered
{
"object": "webhook_endpoint",
"id": "we_123",
"url": "https://partner.example.com/tbltap/webhooks",
"enabled": true,
"event_types": [
"order_handoff.created",
"table_session.bill_ready",
"payment.succeeded"
],
"signing_secret": "whsec_test_visible_once",
"created_at": "2026-07-13T16:08:00Z",
"request_id": "req_webhook_01j2x9ra2f"
}
409 ConflictDuplicate endpoint
{
"error": {
"code": "webhook_endpoint_exists",
"message": "A webhook endpoint already exists for this URL and partner app.",
"type": "conflict_error"
},
"request_id": "req_webhook_duplicate",
"docs_url": "https://tblt.app/docs/developers#webhooks-create"
}
500 Internal Server ErrorUnexpected tbltap error
{
"error": {
"code": "internal_error",
"message": "The request could not be completed. Retry safely with the same idempotency key.",
"type": "api_error"
},
"request_id": "req_webhook_internal",
"docs_url": "https://tblt.app/docs/developers#errors"
}
GET/v1/webhook-endpoints
List webhook endpoints
Lists all webhook endpoints registered for the partner app, including enabled state and subscribed event types.
Partner-scoped read60 requests/minute per app
Request schema
limit
integerMaximum number of endpoints to return, default 20, max 100.
Errors
GET/v1/webhook-endpoints
Response samples
application/json200 OKWebhook endpoint list returned
{
"object": "list",
"data": [
{
"id": "we_123",
"url": "https://partner.example.com/tbltap/webhooks",
"enabled": true
}
],
"request_id": "req_webhook_list_01j2x9rh6e"
}
401 UnauthorizedMissing or invalid credential
{
"error": {
"code": "invalid_api_key",
"message": "Use a valid partner access token.",
"type": "authentication_error"
},
"request_id": "req_unauthorized",
"docs_url": "https://tblt.app/docs/developers#authentication"
}
PUT/v1/webhook-endpoints/{webhook_endpoint_id}/disable
Disable webhook endpoint
Disables a webhook endpoint without deleting its history. Disabled endpoints stop receiving new events immediately.
Partner-scoped write10 requests/minute per app
Request schema
webhook_endpoint_idrequired
stringWebhook endpoint identifier to disable.
Errors
PUT/v1/webhook-endpoints/{webhook_endpoint_id}/disable
Response samples
application/json200 OKWebhook endpoint disabled
{
"object": "webhook_endpoint",
"id": "we_123",
"enabled": false,
"request_id": "req_webhook_disable_01j2x9ri9r"
}
404 Not FoundWebhook endpoint is outside scope
{
"error": {
"code": "webhook_endpoint_not_found",
"message": "No webhook endpoint was found for this id and credential scope.",
"type": "invalid_request_error"
},
"request_id": "req_webhook_disable_missing",
"docs_url": "https://tblt.app/docs/developers#webhooks-disable"
}
Status codes
200 OKRequest succeeded. Mutating endpoints return the same object on idempotent replay.
400 Bad RequestJSON, required field, enum, amount, URL, or schema validation failed.
401 UnauthorizedMissing, expired, or invalid credential.
403 ForbiddenCredential is valid but lacks restaurant, environment, or scope access.
404 Not FoundResource does not exist or is outside the credential scope.
409 ConflictState conflict such as closed table session, duplicate endpoint, locked bill, or replay mismatch.
429 Too Many RequestsRate limit exceeded. Use Retry-After and X-RateLimit-Reset.
500 Internal Server ErrorUnexpected tbltap error. Retry only when the operation is idempotent.
503 Service UnavailableDependency or provider state is unavailable. Back off or wait for webhook reconciliation.
Rate limits
Public hosted linksNo partner API quotaBrowser traffic is protected by edge caching, abuse controls, and route-specific safeguards.
Sandbox partner API60 reads/minute, 30 writes/minuteCounts are per partner app plus restaurant or table session. Lower limits can apply to webhook-adjacent routes.
Webhook management10 writes/minuteRegistering or updating webhook endpoints is limited separately from read/write traffic to reduce accidental fan-out.
Response headersHTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1783987260
Retry-After: 42
Content-Type: application/json
Error envelope
Clients should branch on error.code, not prose. Every failure includes a support-traceable request ID.
Shared 4xx / 5xx shape{
"error": {
"code": "rate_limited",
"message": "Too many requests for this restaurant and partner app.",
"type": "rate_limit_error",
"retry_after_seconds": 42
},
"request_id": "req_01j2x9r8d7a9",
"docs_url": "https://tblt.app/docs/developers#errors"
}
LLM extraction
Read the machine-readable JSON script tag first, then use the visible operation sections for examples.
Extraction selectordocument.querySelector('#tbltap-developer-api-spec')?.textContent
Safety rules
- Never send API keys, webhook secrets, cookies, card numbers, one-time codes, or private staff credentials to support.
- Do not store more customer, order, payment, or table data than the integration needs.
- Do not scrape private owner, staff, or payment pages as an API substitute.
- Use tbltap-approved static media URLs for public menu media. Do not emit signed, original-only, third-party, or Supabase render URLs.
- Do not claim order, delivery, or payment success until the authoritative tbltap and provider states agree.
Next steps
- Describe the restaurant use case, data needed, write operations, and webhook events.
- Request access with a technical contact, company name, callback URL, and desired sandbox timeline.
- Build against sandbox credentials and document retry, idempotency, logging, and rollback behavior.
- Complete production certification before live restaurant traffic.