Payments
A payment is a single charge attempt against an order. An order can have multiple payment attempts (e.g. card declined then re-tried).
Initiate a card payment
POST /pos/v1/orders/{order_id}/paymentsRequired scopes: tilt/payments:create
Request body
{ "method": "card", "amount_cents": 5000, "level3": { }}| Field | Type | Required | Description |
|---|---|---|---|
method | string | Yes | "card" (ACH and virtual payment form are separate flows) |
amount_cents | integer | Yes | Amount to charge. Must be ≤ order total remaining. |
level3 | object | No | Level 3 line-item data. May also be set on the order; payment-level takes precedence. |
Response
{ "payment_id": "uuid", "order_id": "uuid", "status": "pending", "amount_cents": 5000, "method": "card", "created_at": "2024-01-15T10:30:45Z"}Card payments are processed asynchronously. The initial status is pending. Subscribe to webhooks to receive payment.approved or payment.failed events, or poll /pos/v1/orders/{order_id} to check the final status.
Get a payment
GET /pos/v1/orders/{order_id}/payments/{payment_id}Required scopes: tilt/payments:read
Response
{ "payment_id": "uuid", "order_id": "uuid", "status": "approved", "amount_cents": 5000, "method": "card", "processor_reference": "valor-txn-ref", "created_at": "2024-01-15T10:30:45Z", "updated_at": "2024-01-15T10:30:47Z"}Void a payment
Voids a payment that is in pending or approved (pre-settlement) status.
POST /pos/v1/orders/{order_id}/payments/{payment_id}/voidRequired scopes: tilt/payments:create
No request body required.
Response
{ "payment_id": "uuid", "status": "voided", "voided_at": "2024-01-15T10:35:00Z"}Payment statuses
| Status | Description |
|---|---|
pending | Submitted to processor, awaiting response |
approved | Processor approved; not yet settled |
settled | Settled in processor batch |
declined | Processor declined the card |
failed | Processing error (network, timeout, etc.) |
voided | Voided before settlement |
refunded | Refunded (post-settlement) |
cancelled | Cancelled by operator before processor submission |
expired | Payment link expired without completion |
Polling vs. webhooks
Polling is acceptable for low-volume integrations. For high-volume or latency-sensitive flows, use webhooks.
Recommended polling interval: every 3 seconds, up to 60 seconds total. After 60 seconds a pending payment that has not transitioned should be investigated — contact support with the payment_id.