# Submit a payment for an order Attaches a payment to an order. Supports credit cards, debit cards, gift cards, loyalty points, and digital wallets. Idempotency: This endpoint requires the Idempotency-Key header. If a request with the same key is received within 24 hours, the server returns the cached response without re-processing the payment. Error responses are NOT cached. Split payments: To pay with multiple tenders, submit separate payment requests for each tender. Each request must use a different Idempotency-Key. Ordering rules: Submit tenders in this order: loyalty points first, then gift cards, then credit/debit cards. This maximizes non-cash tender redemption. Sequential submission: Wait for each payment to reach a terminal state (COMPLETED or FAILED) before submitting the next. Concurrent submissions on the same order may produce undefined behavior. Failure handling for split payments: If a payment fails mid-sequence, previous successful payments remain. You must either: (a) retry the failed tender with the same Idempotency-Key, (b) submit a different tender for the remaining balance, or (c) cancel the order (which triggers void/refund of all successful payments). Endpoint: POST /orders/{order_id}/payments Version: 1.0.0 Security: oauth2 ## Path parameters: - `order_id` (string, required) Unique identifier for the order. ## Header parameters: - `Idempotency-Key` (string, required) A unique key (UUID v4) to ensure idempotent request processing. Required on all POST, PUT, and DELETE requests. If a request is retried with the same key within 24 hours, the server returns the cached success response without re-processing. Error responses are NOT cached -- retrying after an error with the same key will re-execute the request. Generate a new UUID v4 for each unique operation. Reuse the same key only when retrying a failed or timed-out request. Example: "d7a8fbb3-07d4-4e3c-b5f2-9a6c8b1e0f23" ## Request fields (application/json): - `payment_method` (string, required) The payment method used. These are the API-facing values; the server maps them to internal payment processing types. - CREDIT_CARD: Visa, Mastercard, Amex, Discover credit cards - DEBIT_CARD: Debit cards with PIN or signature - CASH: Customer pays cash at the pickup counter. Only meaningful for PICKUP and DINE_IN handoff modes. The order is submitted online but payment is collected in-store. - GIFT_CARD: Store gift cards or third-party gift cards - LOYALTY_POINTS: Loyalty program points redeemed as payment - DIGITAL_WALLET: Apple Pay, Google Pay, or other digital wallets - EBT: SNAP/EBT card. Item eligibility applies -- only SNAP-eligible items (generally food items, excluding hot prepared foods and tobacco) can be paid with EBT. Check allowed_tenders on each menu item. Tolerant Reader: New payment method values may be added in future API versions. Your integration should handle unknown enum values gracefully (e.g., log a warning and skip) rather than failing. Enum: "CREDIT_CARD", "DEBIT_CARD", "CASH", "GIFT_CARD", "LOYALTY_POINTS", "DIGITAL_WALLET", "EBT" - `amount` (object, required) Amount to charge for this tender. For a single payment, this equals the order total. For split payments, this is the portion covered by this tender. The sum of all successful payment amounts must equal the order total. - `amount.amount` (integer, required) Monetary value in the smallest currency unit (cents for USD). Example: 1299 = $12.99. Example: 1299 - `amount.currency` (string, required) ISO 4217 currency code. Example: "USD" - `tip_amount` (any) Optional tip amount. Typically included on the final tender in a split payment sequence. Null or omit if no tip. - `payment_details` (object,null) Method-specific payment details. Required fields vary by payment_method: CREDIT_CARD / DEBIT_CARD: json { "token": "tok_visa_4242" } Use a tokenized card reference from your payment form. Never send raw card numbers through this API. GIFT_CARD: json { "card_number": "6789012345678901", "pin": "1234" } LOYALTY_POINTS: json { "loyalty_account_id": "LOY-123456" } DIGITAL_WALLET: json { "wallet_token": "dw_applepay_abc123", "wallet_type": "apple_pay" } ## Response 201 fields (application/json): - `id` (string, required) Unique identifier for the payment. - `order_id` (string, required) The order this payment is attached to. - `status` (string, required) Payment processing status. The typical online ordering flow is: PENDING -> COMPLETED (immediate capture). For pre-authorization flows: PENDING -> AUTHORIZED -> CAPTURED -> COMPLETED. Terminal states: COMPLETED, VOIDED, REFUNDED, FAILED. State transitions: - PENDING -> AUTHORIZED, COMPLETED, FAILED - AUTHORIZED -> CAPTURED, VOIDED, FAILED - CAPTURED -> COMPLETED, REFUNDED, PARTIALLY_REFUNDED - COMPLETED -> REFUNDED, PARTIALLY_REFUNDED - VOIDED, REFUNDED, FAILED are terminal (no further transitions) - PARTIALLY_REFUNDED -> REFUNDED (when remaining amount is refunded) Enum: "PENDING", "AUTHORIZED", "CAPTURED", "COMPLETED", "VOIDED", "REFUNDED", "PARTIALLY_REFUNDED", "FAILED" - `payment_method` (string, required) The payment method used. These are the API-facing values; the server maps them to internal payment processing types. - CREDIT_CARD: Visa, Mastercard, Amex, Discover credit cards - DEBIT_CARD: Debit cards with PIN or signature - CASH: Customer pays cash at the pickup counter. Only meaningful for PICKUP and DINE_IN handoff modes. The order is submitted online but payment is collected in-store. - GIFT_CARD: Store gift cards or third-party gift cards - LOYALTY_POINTS: Loyalty program points redeemed as payment - DIGITAL_WALLET: Apple Pay, Google Pay, or other digital wallets - EBT: SNAP/EBT card. Item eligibility applies -- only SNAP-eligible items (generally food items, excluding hot prepared foods and tobacco) can be paid with EBT. Check allowed_tenders on each menu item. Tolerant Reader: New payment method values may be added in future API versions. Your integration should handle unknown enum values gracefully (e.g., log a warning and skip) rather than failing. Enum: "CREDIT_CARD", "DEBIT_CARD", "CASH", "GIFT_CARD", "LOYALTY_POINTS", "DIGITAL_WALLET", "EBT" - `amount` (object, required) The payment amount in cents. - `amount.amount` (integer, required) Monetary value in the smallest currency unit (cents for USD). Example: 1299 = $12.99. Example: 1299 - `amount.currency` (string, required) ISO 4217 currency code. Example: "USD" - `tip_amount` (any) Tip amount included in this payment, if any. Null if no tip. - `payment_details` (object,null) Method-specific details. Shape varies by payment_method: - CREDIT_CARD / DEBIT_CARD: { "last_four": "4242", "brand": "visa", "exp_month": 12, "exp_year": 2027 } - GIFT_CARD: { "last_four": "7890", "balance_remaining": { "amount": 1500, "currency": "USD" } } - LOYALTY_POINTS: { "points_used": 500, "points_remaining": 1200 } - DIGITAL_WALLET: { "wallet_type": "apple_pay" } - `idempotency_key` (string) The idempotency key used when this payment was submitted. - `created_at` (string, required) When the payment was created. - `updated_at` (string, required) When the payment status was last updated. ## Response 400 fields (application/json): - `error` (object, required) - `error.code` (string, required) Machine-readable error category. Use this field for programmatic error handling (e.g., retry on RATE_LIMIT_ERROR, re-authenticate on AUTHENTICATION_ERROR). Enum: "AUTHENTICATION_ERROR", "INVALID_REQUEST_ERROR", "RATE_LIMIT_ERROR", "NOT_FOUND_ERROR", "CONFLICT_ERROR", "INTERNAL_ERROR" - `error.message` (string, required) Human-readable error description. Safe to display to developers in logs or debugging tools. Do not display to end users. - `error.detail` (string) Additional context about the error, including suggestions for resolution. May include specific field values or limits that were exceeded. - `error.request_id` (string, required) Unique identifier for this request. Include this value when contacting Tote Developer Support for troubleshooting. - `error.field` (string,null) JSON pointer to the field that caused the error. Null if the error is not field-specific. Example: "items[0].modifier_groups[1].modifiers" - `error.change_reasons` (array) Machine-readable reasons why the resource state changed, causing the conflict. Present on checkout 409 responses when expected_total does not match the current total. Clients should re-fetch the cart and call POST /carts/{cart_id}/calculate to get the updated total before retrying checkout. Enum: "PROMO_EXPIRED", "DISCOUNT_CHANGED", "ITEM_PRICE_CHANGED", "ITEM_UNAVAILABLE", "FEE_CHANGED" ## Response 401 fields (application/json): - `error` (object, required) - `error.code` (string, required) Machine-readable error category. Use this field for programmatic error handling (e.g., retry on RATE_LIMIT_ERROR, re-authenticate on AUTHENTICATION_ERROR). Enum: "AUTHENTICATION_ERROR", "INVALID_REQUEST_ERROR", "RATE_LIMIT_ERROR", "NOT_FOUND_ERROR", "CONFLICT_ERROR", "INTERNAL_ERROR" - `error.message` (string, required) Human-readable error description. Safe to display to developers in logs or debugging tools. Do not display to end users. - `error.detail` (string) Additional context about the error, including suggestions for resolution. May include specific field values or limits that were exceeded. - `error.request_id` (string, required) Unique identifier for this request. Include this value when contacting Tote Developer Support for troubleshooting. - `error.field` (string,null) JSON pointer to the field that caused the error. Null if the error is not field-specific. Example: "items[0].modifier_groups[1].modifiers" - `error.change_reasons` (array) Machine-readable reasons why the resource state changed, causing the conflict. Present on checkout 409 responses when expected_total does not match the current total. Clients should re-fetch the cart and call POST /carts/{cart_id}/calculate to get the updated total before retrying checkout. Enum: "PROMO_EXPIRED", "DISCOUNT_CHANGED", "ITEM_PRICE_CHANGED", "ITEM_UNAVAILABLE", "FEE_CHANGED" ## Response 402 fields (application/json): - `error` (object, required) - `error.code` (string, required) Machine-readable error category. Use this field for programmatic error handling (e.g., retry on RATE_LIMIT_ERROR, re-authenticate on AUTHENTICATION_ERROR). Enum: "AUTHENTICATION_ERROR", "INVALID_REQUEST_ERROR", "RATE_LIMIT_ERROR", "NOT_FOUND_ERROR", "CONFLICT_ERROR", "INTERNAL_ERROR" - `error.message` (string, required) Human-readable error description. Safe to display to developers in logs or debugging tools. Do not display to end users. - `error.detail` (string) Additional context about the error, including suggestions for resolution. May include specific field values or limits that were exceeded. - `error.request_id` (string, required) Unique identifier for this request. Include this value when contacting Tote Developer Support for troubleshooting. - `error.field` (string,null) JSON pointer to the field that caused the error. Null if the error is not field-specific. Example: "items[0].modifier_groups[1].modifiers" - `error.change_reasons` (array) Machine-readable reasons why the resource state changed, causing the conflict. Present on checkout 409 responses when expected_total does not match the current total. Clients should re-fetch the cart and call POST /carts/{cart_id}/calculate to get the updated total before retrying checkout. Enum: "PROMO_EXPIRED", "DISCOUNT_CHANGED", "ITEM_PRICE_CHANGED", "ITEM_UNAVAILABLE", "FEE_CHANGED" ## Response 404 fields (application/json): - `error` (object, required) - `error.code` (string, required) Machine-readable error category. Use this field for programmatic error handling (e.g., retry on RATE_LIMIT_ERROR, re-authenticate on AUTHENTICATION_ERROR). Enum: "AUTHENTICATION_ERROR", "INVALID_REQUEST_ERROR", "RATE_LIMIT_ERROR", "NOT_FOUND_ERROR", "CONFLICT_ERROR", "INTERNAL_ERROR" - `error.message` (string, required) Human-readable error description. Safe to display to developers in logs or debugging tools. Do not display to end users. - `error.detail` (string) Additional context about the error, including suggestions for resolution. May include specific field values or limits that were exceeded. - `error.request_id` (string, required) Unique identifier for this request. Include this value when contacting Tote Developer Support for troubleshooting. - `error.field` (string,null) JSON pointer to the field that caused the error. Null if the error is not field-specific. Example: "items[0].modifier_groups[1].modifiers" - `error.change_reasons` (array) Machine-readable reasons why the resource state changed, causing the conflict. Present on checkout 409 responses when expected_total does not match the current total. Clients should re-fetch the cart and call POST /carts/{cart_id}/calculate to get the updated total before retrying checkout. Enum: "PROMO_EXPIRED", "DISCOUNT_CHANGED", "ITEM_PRICE_CHANGED", "ITEM_UNAVAILABLE", "FEE_CHANGED" ## Response 409 fields (application/json): - `error` (object, required) - `error.code` (string, required) Machine-readable error category. Use this field for programmatic error handling (e.g., retry on RATE_LIMIT_ERROR, re-authenticate on AUTHENTICATION_ERROR). Enum: "AUTHENTICATION_ERROR", "INVALID_REQUEST_ERROR", "RATE_LIMIT_ERROR", "NOT_FOUND_ERROR", "CONFLICT_ERROR", "INTERNAL_ERROR" - `error.message` (string, required) Human-readable error description. Safe to display to developers in logs or debugging tools. Do not display to end users. - `error.detail` (string) Additional context about the error, including suggestions for resolution. May include specific field values or limits that were exceeded. - `error.request_id` (string, required) Unique identifier for this request. Include this value when contacting Tote Developer Support for troubleshooting. - `error.field` (string,null) JSON pointer to the field that caused the error. Null if the error is not field-specific. Example: "items[0].modifier_groups[1].modifiers" - `error.change_reasons` (array) Machine-readable reasons why the resource state changed, causing the conflict. Present on checkout 409 responses when expected_total does not match the current total. Clients should re-fetch the cart and call POST /carts/{cart_id}/calculate to get the updated total before retrying checkout. Enum: "PROMO_EXPIRED", "DISCOUNT_CHANGED", "ITEM_PRICE_CHANGED", "ITEM_UNAVAILABLE", "FEE_CHANGED" ## Response 422 fields (application/json): - `error` (object, required) - `error.code` (string, required) Machine-readable error category. Use this field for programmatic error handling (e.g., retry on RATE_LIMIT_ERROR, re-authenticate on AUTHENTICATION_ERROR). Enum: "AUTHENTICATION_ERROR", "INVALID_REQUEST_ERROR", "RATE_LIMIT_ERROR", "NOT_FOUND_ERROR", "CONFLICT_ERROR", "INTERNAL_ERROR" - `error.message` (string, required) Human-readable error description. Safe to display to developers in logs or debugging tools. Do not display to end users. - `error.detail` (string) Additional context about the error, including suggestions for resolution. May include specific field values or limits that were exceeded. - `error.request_id` (string, required) Unique identifier for this request. Include this value when contacting Tote Developer Support for troubleshooting. - `error.field` (string,null) JSON pointer to the field that caused the error. Null if the error is not field-specific. Example: "items[0].modifier_groups[1].modifiers" - `error.change_reasons` (array) Machine-readable reasons why the resource state changed, causing the conflict. Present on checkout 409 responses when expected_total does not match the current total. Clients should re-fetch the cart and call POST /carts/{cart_id}/calculate to get the updated total before retrying checkout. Enum: "PROMO_EXPIRED", "DISCOUNT_CHANGED", "ITEM_PRICE_CHANGED", "ITEM_UNAVAILABLE", "FEE_CHANGED" ## Response 429 fields (application/json): - `error` (object, required) - `error.code` (string, required) Machine-readable error category. Use this field for programmatic error handling (e.g., retry on RATE_LIMIT_ERROR, re-authenticate on AUTHENTICATION_ERROR). Enum: "AUTHENTICATION_ERROR", "INVALID_REQUEST_ERROR", "RATE_LIMIT_ERROR", "NOT_FOUND_ERROR", "CONFLICT_ERROR", "INTERNAL_ERROR" - `error.message` (string, required) Human-readable error description. Safe to display to developers in logs or debugging tools. Do not display to end users. - `error.detail` (string) Additional context about the error, including suggestions for resolution. May include specific field values or limits that were exceeded. - `error.request_id` (string, required) Unique identifier for this request. Include this value when contacting Tote Developer Support for troubleshooting. - `error.field` (string,null) JSON pointer to the field that caused the error. Null if the error is not field-specific. Example: "items[0].modifier_groups[1].modifiers" - `error.change_reasons` (array) Machine-readable reasons why the resource state changed, causing the conflict. Present on checkout 409 responses when expected_total does not match the current total. Clients should re-fetch the cart and call POST /carts/{cart_id}/calculate to get the updated total before retrying checkout. Enum: "PROMO_EXPIRED", "DISCOUNT_CHANGED", "ITEM_PRICE_CHANGED", "ITEM_UNAVAILABLE", "FEE_CHANGED" ## Response 500 fields (application/json): - `error` (object, required) - `error.code` (string, required) Machine-readable error category. Use this field for programmatic error handling (e.g., retry on RATE_LIMIT_ERROR, re-authenticate on AUTHENTICATION_ERROR). Enum: "AUTHENTICATION_ERROR", "INVALID_REQUEST_ERROR", "RATE_LIMIT_ERROR", "NOT_FOUND_ERROR", "CONFLICT_ERROR", "INTERNAL_ERROR" - `error.message` (string, required) Human-readable error description. Safe to display to developers in logs or debugging tools. Do not display to end users. - `error.detail` (string) Additional context about the error, including suggestions for resolution. May include specific field values or limits that were exceeded. - `error.request_id` (string, required) Unique identifier for this request. Include this value when contacting Tote Developer Support for troubleshooting. - `error.field` (string,null) JSON pointer to the field that caused the error. Null if the error is not field-specific. Example: "items[0].modifier_groups[1].modifiers" - `error.change_reasons` (array) Machine-readable reasons why the resource state changed, causing the conflict. Present on checkout 409 responses when expected_total does not match the current total. Clients should re-fetch the cart and call POST /carts/{cart_id}/calculate to get the updated total before retrying checkout. Enum: "PROMO_EXPIRED", "DISCOUNT_CHANGED", "ITEM_PRICE_CHANGED", "ITEM_UNAVAILABLE", "FEE_CHANGED"