openapi: 3.2.0 info: title: Bilt Checkout SDK Headless payments API version: 0.2.0-draft description: '# Introduction External backend contract for integrators using the Bilt Checkout SDK.' servers: - url: https://partnerapi.biltrewards.com description: Production — partner (third-party) gateway - url: https://staging.partnerapi.biltrewards.com description: Staging — partner (third-party) gateway security: - checkoutPartnerOAuth: [] tags: - name: Headless payments description: 'Charge a customer''s current default Bilt payment method with no Bilt UI, for subscriptions, autopay, or other off-session payments. The outcome arrives as a `payment.*` webhook.' paths: /partner/checkout/v1/headless-payments: post: tags: - Headless payments summary: Create a headless payment operationId: createHeadlessPayment description: 'Charges the customer''s **current default Bilt payment method** for the supplied line items, with no Bilt UI. Bilt resolves `integratorCustomerId` to the linked Bilt member, reads their default payment method at charge time, applies eligible credits automatically, and charges the remainder to the card. There is deliberately no payment-method field in this request. The customer chooses and maintains their default payment method in the Bilt app; if they replace the card, the next payment uses the new one with no change on your side. A request containing an unknown field (including a `paymentMethodId`) is rejected with `400 INVALID_REQUEST`. `202` means Bilt accepted the request and is processing the charge. Use `/partner/checkout/v1/headless-payments/sync` when you need the outcome in the request cycle; it can also return `202` if its processing budget is exhausted. The final outcome — settled amounts, or a decline — arrives as a `payment.succeeded` or `payment.failed` webhook. Until then the payment is `PROCESSING`; `amounts.creditsAppliedCents` in the `202` body is a placeholder of `0` and the final credit split is in the webhook. **Always send an `Idempotency-Key`** so that a retry after a timeout cannot charge the customer twice. Validation: all `lineItems` must share one `currency` (currently only `USD`), `integratorSkuId` values must be unique within a request, and `quantity` must be at least 1. `unitPriceCents` may be `0` for a bundled or promotional line but never negative.' parameters: - $ref: '#/components/parameters/IdempotencyKey' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreatePaymentRequest' example: integratorCustomerId: acme_customer_sandbox_123 orderId: acme_subscription_invoice_sandbox_2026_08 lineItems: - integratorSkuId: acme_membership_monthly lineItemType: PRODUCT quantity: 1 unitPriceCents: 4900 amountCents: 4900 currency: USD metadata: subscriptionId: acme_subscription_sandbox_456 responses: '202': description: Payment accepted for processing content: application/json: schema: $ref: '#/components/schemas/HeadlessPaymentEnvelope' example: data: sessionId: checkout_session_sandbox_headless_123 mode: headless status: PROCESSING orderId: acme_subscription_invoice_sandbox_2026_08 amounts: subtotalCents: 4900 creditsAppliedCents: 0 chargedAmountCents: 4900 currency: USD '400': $ref: '#/components/responses/InvalidRequest' '401': $ref: '#/components/responses/Unauthenticated' '404': $ref: '#/components/responses/HeadlessNotFound' '409': $ref: '#/components/responses/Conflict' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' callbacks: paymentSucceeded: https://acme.example.invalid/webhooks/bilt: post: tags: - Payment webhooks summary: payment.succeeded operationId: onPaymentSucceeded security: [] parameters: - $ref: '#/components/parameters/WebhookId' - $ref: '#/components/parameters/WebhookTimestamp' - $ref: '#/components/parameters/WebhookSignature' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/PaymentWebhookEvent' example: type: payment.succeeded timestamp: '2026-08-24T22:15:12.344Z' data: sessionId: checkout_session_sandbox_headless_123 mode: headless orderId: acme_subscription_invoice_sandbox_2026_08 integratorCustomerId: acme_customer_sandbox_123 status: SUCCEEDED paymentId: payment_sandbox_790 amounts: subtotalCents: 4900 creditsAppliedCents: 500 chargedAmountCents: 4400 currency: USD responses: 2xx: description: Event acknowledged; Bilt will not redeliver it. paymentFailed: https://acme.example.invalid/webhooks/bilt: post: tags: - Payment webhooks summary: payment.failed operationId: onPaymentFailed security: [] parameters: - $ref: '#/components/parameters/WebhookId' - $ref: '#/components/parameters/WebhookTimestamp' - $ref: '#/components/parameters/WebhookSignature' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/PaymentWebhookEvent' example: type: payment.failed timestamp: '2026-08-24T22:15:12.344Z' data: sessionId: checkout_session_sandbox_headless_124 mode: headless orderId: acme_subscription_invoice_sandbox_2026_09 integratorCustomerId: acme_customer_sandbox_123 status: FAILED failure: code: CARD_DECLINED message: The card issuer declined the charge retryable: true responses: 2xx: description: Event acknowledged; Bilt will not redeliver it. /partner/checkout/v1/headless-payments/sync: post: tags: - Headless payments summary: Create a headless payment and wait for the outcome operationId: createHeadlessPaymentSync description: 'Charges the customer''s **current default Bilt payment method** and waits for the processor before responding. A settled charge or decline is returned in the response instead of being delivered only by webhook. Use this endpoint when you need the answer in the request cycle, such as checkout-time add-ons or retries driven by a customer action. Use the async endpoint for batch or subscription runs. The request is held while the processor answers, so this endpoint has a lower rate limit than the async endpoint and clients must allow a longer timeout. [CHECK: sync rate limit and processing budget (proposed 30 s) to be confirmed by Payments.] If the processor does not answer within the budget, Bilt returns `202 PROCESSING` exactly like the async endpoint and the outcome arrives by webhook — handle both. Webhooks (`payment.succeeded` / `payment.failed`) are sent for sync payments too, so one reconciliation path covers both endpoints. **Always send an `Idempotency-Key`**. On a retry after a timeout, the same key returns the existing payment''s current status rather than charging again. Validation: all `lineItems` must share one `currency` (currently only `USD`), `integratorSkuId` values must be unique within a request, and `quantity` must be at least 1. `unitPriceCents` may be `0` for a bundled or promotional line but never negative.' parameters: - $ref: '#/components/parameters/IdempotencyKey' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreatePaymentRequest' example: integratorCustomerId: acme_customer_sandbox_123 orderId: acme_subscription_invoice_sandbox_2026_08 lineItems: - integratorSkuId: acme_membership_monthly lineItemType: PRODUCT quantity: 1 unitPriceCents: 4900 amountCents: 4900 currency: USD metadata: subscriptionId: acme_subscription_sandbox_456 responses: '200': description: Payment settled or declined content: application/json: schema: $ref: '#/components/schemas/HeadlessPaymentOutcomeEnvelope' examples: succeeded: value: data: sessionId: checkout_session_sandbox_headless_123 mode: headless status: SUCCEEDED orderId: acme_subscription_invoice_sandbox_2026_08 paymentId: payment_sandbox_789 amounts: subtotalCents: 4900 creditsAppliedCents: 500 chargedAmountCents: 4400 currency: USD declined: value: data: sessionId: checkout_session_sandbox_headless_124 mode: headless status: FAILED orderId: acme_subscription_invoice_sandbox_2026_09 failure: code: CARD_DECLINED message: The card issuer declined the charge retryable: true '202': description: Processing budget exhausted; outcome will arrive by webhook content: application/json: schema: $ref: '#/components/schemas/HeadlessPaymentEnvelope' example: data: sessionId: checkout_session_sandbox_headless_123 mode: headless status: PROCESSING orderId: acme_subscription_invoice_sandbox_2026_08 amounts: subtotalCents: 4900 creditsAppliedCents: 0 chargedAmountCents: 4900 currency: USD '400': $ref: '#/components/responses/InvalidRequest' '401': $ref: '#/components/responses/Unauthenticated' '404': $ref: '#/components/responses/HeadlessNotFound' '409': $ref: '#/components/responses/Conflict' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' callbacks: paymentSucceeded: https://acme.example.invalid/webhooks/bilt: post: tags: - Payment webhooks summary: payment.succeeded operationId: onPaymentSucceededSync security: [] parameters: - $ref: '#/components/parameters/WebhookId' - $ref: '#/components/parameters/WebhookTimestamp' - $ref: '#/components/parameters/WebhookSignature' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/PaymentWebhookEvent' example: type: payment.succeeded timestamp: '2026-08-24T22:15:12.344Z' data: sessionId: checkout_session_sandbox_headless_123 mode: headless orderId: acme_subscription_invoice_sandbox_2026_08 integratorCustomerId: acme_customer_sandbox_123 status: SUCCEEDED paymentId: payment_sandbox_789 amounts: subtotalCents: 4900 creditsAppliedCents: 500 chargedAmountCents: 4400 currency: USD responses: 2xx: description: Event acknowledged; Bilt will not redeliver it. paymentFailed: https://acme.example.invalid/webhooks/bilt: post: tags: - Payment webhooks summary: payment.failed operationId: onPaymentFailedSync security: [] parameters: - $ref: '#/components/parameters/WebhookId' - $ref: '#/components/parameters/WebhookTimestamp' - $ref: '#/components/parameters/WebhookSignature' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/PaymentWebhookEvent' example: type: payment.failed timestamp: '2026-08-24T22:15:12.344Z' data: sessionId: checkout_session_sandbox_headless_124 mode: headless orderId: acme_subscription_invoice_sandbox_2026_09 integratorCustomerId: acme_customer_sandbox_123 status: FAILED failure: code: CARD_DECLINED message: The card issuer declined the charge retryable: true responses: 2xx: description: Event acknowledged; Bilt will not redeliver it. components: schemas: HeadlessPaymentSucceeded: type: object required: - sessionId - mode - status - orderId - paymentId - amounts properties: sessionId: type: string example: checkout_session_sandbox_headless_123 mode: type: string enum: - headless status: type: string enum: - SUCCEEDED orderId: type: string example: acme_subscription_invoice_sandbox_2026_08 paymentId: type: string description: Bilt payment identifier; same value as `paymentId` on the `payment.succeeded` webhook example: payment_sandbox_789 amounts: description: Final payment split. $ref: '#/components/schemas/PaymentAmounts' PaymentWebhookEvent: description: 'Standard Webhooks payload. `type` is the discriminator: each event type fixes `data.mode` and `data.status` and states exactly which fields are present, so a validator generated from this document rejects e.g. `payment.failed` without `failure` or `payment.succeeded` without settled `amounts`. ' oneOf: - $ref: '#/components/schemas/CheckoutSessionCompletedEvent' - $ref: '#/components/schemas/CheckoutSessionCancelledEvent' - $ref: '#/components/schemas/CheckoutSessionExpiredEvent' - $ref: '#/components/schemas/PaymentSucceededEvent' - $ref: '#/components/schemas/PaymentFailedEvent' discriminator: propertyName: type mapping: checkout.session.completed: '#/components/schemas/CheckoutSessionCompletedEvent' checkout.session.cancelled: '#/components/schemas/CheckoutSessionCancelledEvent' checkout.session.expired: '#/components/schemas/CheckoutSessionExpiredEvent' payment.succeeded: '#/components/schemas/PaymentSucceededEvent' payment.failed: '#/components/schemas/PaymentFailedEvent' CheckoutSessionCompletedEvent: allOf: - $ref: '#/components/schemas/WebhookEventBase' - type: object properties: type: type: string enum: - checkout.session.completed data: allOf: - $ref: '#/components/schemas/WebhookDataBase' - type: object required: - paymentId - amounts properties: mode: type: string enum: - hosted status: type: string enum: - COMPLETED paymentId: type: string description: Opaque Bilt payment identifier. example: payment_sandbox_789 amounts: $ref: '#/components/schemas/PaymentAmounts' HeadlessPayment: type: object required: - sessionId - mode - status - orderId - amounts description: 'Acknowledgement that a headless payment was accepted for processing. The settled outcome arrives by webhook. ' properties: sessionId: type: string description: 'Opaque Bilt identifier for this payment; the `payment.*` webhook for it carries the same value. ' example: checkout_session_sandbox_headless_123 mode: type: string enum: - headless status: type: string enum: - PROCESSING description: 'Always `PROCESSING` on acceptance. `SUCCEEDED` / `FAILED` are delivered by webhook. ' orderId: type: string description: Your `orderId`, echoed unchanged. example: acme_subscription_invoice_sandbox_2026_08 amounts: $ref: '#/components/schemas/PaymentAmounts' WebhookEventBase: type: object required: - type - timestamp - data properties: type: type: string description: Event type; see **Introduction › Webhooks › Payload**. timestamp: type: string format: date-time description: When the event occurred (not when it was delivered). example: '2026-08-24T22:15:12.344Z' WebhookDataBase: type: object required: - sessionId - mode - orderId - integratorCustomerId - status properties: sessionId: type: string description: The `sessionId` returned when the session or payment was created. example: checkout_session_sandbox_123 orderId: type: string description: Your `orderId`, echoed unchanged. example: acme_order_sandbox_456 integratorCustomerId: type: string description: Your customer identifier, echoed unchanged. example: acme_customer_sandbox_123 metadata: $ref: '#/components/schemas/IntegratorMetadata' HeadlessPaymentOutcomeEnvelope: type: object required: - data properties: data: $ref: '#/components/schemas/HeadlessPaymentOutcome' IntegratorMetadata: type: - object - 'null' maxProperties: 20 additionalProperties: type: string maxLength: 500 description: 'Optional integrator-owned correlation values (up to 20 keys, string values up to 500 characters). Echoed back on webhooks and never interpreted by Bilt. Do not include secrets, credentials, card data, or personal data. ' example: correlationId: acme_correlation_sandbox_789 ExternalLineItem: type: object additionalProperties: false required: - integratorSkuId - lineItemType - quantity - unitPriceCents - amountCents - currency properties: integratorSkuId: type: string minLength: 1 maxLength: 255 description: 'Your identifier for the SKU; Bilt maps it to its catalog. Unique within one request. [CHECK: the current implementation accepts this field as `integratorSku`; rename pending.] ' example: acme_membership_monthly lineItemType: type: string enum: - PRODUCT description: 'Kind of line. `PRODUCT` today. [CHECK: `SHIPPING`, `SUBSCRIPTION`, `INCIDENTAL` are under discussion and not yet accepted.] ' example: PRODUCT quantity: type: integer minimum: 1 example: 1 unitPriceCents: type: integer format: int64 minimum: 0 description: 'Price per unit in minor currency units. May be `0` for a bundled or promotional line; never negative — a discount is not a line item. ' example: 4900 amountCents: type: integer format: int64 minimum: 0 description: 'Line total in minor units; must equal `quantity × unitPriceCents` or the request is rejected with `400 INVALID_REQUEST`. ' example: 4900 currency: type: string pattern: ^[A-Z]{3}$ description: ISO 4217 currency code. Currently only `USD` is accepted. example: USD PaymentFailure: type: object additionalProperties: false description: Why a headless charge could not be completed. required: - code - message - retryable properties: code: type: string pattern: ^[A-Z][A-Z0-9_]*$ description: 'Stable reason code. `CARD_DECLINED`, `PAYMENT_METHOD_EXPIRED`, `PAYMENT_METHOD_NOT_FOUND`, `PROCESSOR_UNAVAILABLE`. [CHECK: final failure-code list is owned by the payment processor integration.] ' example: CARD_DECLINED message: type: string description: Human-readable reason; do not branch on it. example: The card issuer declined the charge retryable: type: boolean description: 'Whether a **new** headless payment for the same order may succeed without the customer acting first (for example a transient processor failure). `false` means the customer needs to update their payment method in the Bilt app. ' example: true PaymentAmounts: type: object required: - subtotalCents - creditsAppliedCents - chargedAmountCents - currency description: 'Split of the order total between eligible Bilt credits and the customer''s card. `subtotalCents = creditsAppliedCents + chargedAmountCents`. On a `202` acceptance `creditsAppliedCents` is `0`; the final split is on the `payment.succeeded` webhook. A synchronous `200` response carries the final split. ' properties: subtotalCents: type: integer format: int64 minimum: 0 description: Sum of `amountCents` over all line items. example: 4900 creditsAppliedCents: type: integer format: int64 minimum: 0 description: Eligible Bilt credits applied automatically. example: 500 chargedAmountCents: type: integer format: int64 minimum: 0 description: Amount charged to the customer's payment method. example: 4400 currency: type: string pattern: ^[A-Z]{3}$ example: USD PaymentSucceededEvent: allOf: - $ref: '#/components/schemas/WebhookEventBase' - type: object properties: type: type: string enum: - payment.succeeded data: allOf: - $ref: '#/components/schemas/WebhookDataBase' - type: object required: - paymentId - amounts properties: mode: type: string enum: - headless status: type: string enum: - SUCCEEDED paymentId: type: string description: Opaque Bilt payment identifier. example: payment_sandbox_790 amounts: $ref: '#/components/schemas/PaymentAmounts' CheckoutSessionCancelledEvent: allOf: - $ref: '#/components/schemas/WebhookEventBase' - type: object properties: type: type: string enum: - checkout.session.cancelled data: allOf: - $ref: '#/components/schemas/WebhookDataBase' - type: object properties: mode: type: string enum: - hosted status: type: string enum: - CANCELLED ErrorResponse: type: object additionalProperties: false required: - error description: 'Error envelope returned on every non-`2xx` response. Branch on the stable `code`, not the human-readable `message`. ' properties: error: $ref: '#/components/schemas/ErrorDetail' HeadlessPaymentFailed: type: object required: - sessionId - mode - status - orderId - failure properties: sessionId: type: string example: checkout_session_sandbox_headless_124 mode: type: string enum: - headless status: type: string enum: - FAILED orderId: type: string example: acme_subscription_invoice_sandbox_2026_09 failure: $ref: '#/components/schemas/PaymentFailure' CheckoutSessionExpiredEvent: allOf: - $ref: '#/components/schemas/WebhookEventBase' - type: object properties: type: type: string enum: - checkout.session.expired data: allOf: - $ref: '#/components/schemas/WebhookDataBase' - type: object properties: mode: type: string enum: - hosted status: type: string enum: - EXPIRED PaymentFailedEvent: allOf: - $ref: '#/components/schemas/WebhookEventBase' - type: object properties: type: type: string enum: - payment.failed data: allOf: - $ref: '#/components/schemas/WebhookDataBase' - type: object required: - failure properties: mode: type: string enum: - headless status: type: string enum: - FAILED failure: $ref: '#/components/schemas/PaymentFailure' ErrorDetail: type: object additionalProperties: false required: - code - message - requestId - retryable properties: code: type: string pattern: ^[A-Z][A-Z0-9_]*$ description: Stable machine-readable code; see **Introduction › Errors**. enum: - INVALID_REQUEST - UNAUTHENTICATED - CUSTOMER_NOT_FOUND - PAYMENT_METHOD_NOT_FOUND - IDEMPOTENCY_CONFLICT - SESSION_ALREADY_COMPLETED - RATE_LIMIT_EXCEEDED - INTERNAL_ERROR - PAYMENT_UNAVAILABLE example: CUSTOMER_NOT_FOUND message: type: string description: Human-readable operational message; do not branch on it. example: No linked Bilt member for integratorCustomerId requestId: type: string description: Correlation id to quote when contacting Bilt. example: request_sandbox_123 retryable: type: boolean description: 'Whether sending the same request again may succeed. `false` whenever somebody has to act first. ' example: false HeadlessPaymentEnvelope: type: object required: - data properties: data: $ref: '#/components/schemas/HeadlessPayment' HeadlessPaymentOutcome: oneOf: - $ref: '#/components/schemas/HeadlessPaymentSucceeded' - $ref: '#/components/schemas/HeadlessPaymentFailed' discriminator: propertyName: status mapping: SUCCEEDED: '#/components/schemas/HeadlessPaymentSucceeded' FAILED: '#/components/schemas/HeadlessPaymentFailed' CreatePaymentRequest: type: object additionalProperties: false description: 'Shared request body for one-time payment sessions and headless payments. Unknown properties are rejected with `400 INVALID_REQUEST`. ' required: - integratorCustomerId - orderId - lineItems properties: integratorCustomerId: type: string minLength: 1 maxLength: 64 pattern: ^[A-Za-z0-9_.:~-]+$ description: 'Your stable identifier for the customer — the same key you use for account linking. Bilt resolves it to the linked Bilt member. Never send a Bilt member id. ' example: acme_customer_sandbox_123 orderId: type: string minLength: 1 maxLength: 255 pattern: ^[A-Za-z0-9_.:~-]+$ description: 'Your identifier for this order, invoice, or payment attempt. It must exist on your side before you call this endpoint — Bilt only stores and echoes it, unchanged, on the response and on every webhook for this payment. If your order record is created only after payment, generate the id first and attach the order to it when the webhook arrives. ' example: acme_order_sandbox_456 lineItems: type: array minItems: 1 maxItems: 100 description: 'Sealed list of what is being paid for. All items must share one `currency`, and `integratorSkuId` must be unique within the request. ' items: $ref: '#/components/schemas/ExternalLineItem' metadata: $ref: '#/components/schemas/IntegratorMetadata' parameters: WebhookId: name: webhook-id in: header required: true description: 'Unique message id, stable across redeliveries of the same event. Deduplicate on it. ' schema: type: string example: msg_2KWPBgLlAfxdpx2AI54pPJ85f4W IdempotencyKey: name: Idempotency-Key in: header required: false description: 'Optional but strongly recommended — required in practice for headless payments. Any string up to 255 characters; a fresh UUID per attempt is the recommended form. A retry with the same key and body returns the original result; the same key with a different body is rejected with `409 IDEMPOTENCY_CONFLICT`. Keys are scoped to your client. ' schema: type: string minLength: 1 maxLength: 255 example: 6f6b1afd-22e0-4137-a096-b15e41cdc890 WebhookSignature: name: webhook-signature in: header required: true description: 'Space-separated `v1,` signatures, each the base64 `HMAC-SHA256` of `"{webhook-id}.{webhook-timestamp}.{rawBody}"` keyed by your `whsec_` signing secret. Accept the delivery if any one verifies (constant-time comparison). Multiple entries appear only during a secret rotation. ' schema: type: string example: v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2pj9o9NDN/H/pI4= WebhookTimestamp: name: webhook-timestamp in: header required: true description: 'Unix timestamp in seconds of this delivery attempt. Reject deliveries more than 5 minutes from your clock. ' schema: type: integer format: int64 example: 1787609712 responses: InvalidRequest: description: 'The request is malformed. `message` names the offending field. Not retryable without changing the request. ' content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' examples: invalidField: value: error: code: INVALID_REQUEST message: lineItems[0].quantity must be at least 1 requestId: request_sandbox_123 retryable: false unknownField: value: error: code: INVALID_REQUEST message: Unrecognized field "paymentMethodId" requestId: request_sandbox_124 retryable: false mixedCurrency: value: error: code: INVALID_REQUEST message: All lineItems must use the same currency; only USD is supported requestId: request_sandbox_125 retryable: false RateLimited: description: 'Too many requests. Gateway-enforced; retry with backoff, honouring `Retry-After` when present. The sync endpoint''s limit is lower than the async endpoint''s. Per-integrator quotas are agreed during onboarding when your volume warrants one. ' headers: Retry-After: description: Number of seconds to wait before retrying. schema: type: integer minimum: 1 content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' example: error: code: RATE_LIMIT_EXCEEDED message: Too many requests requestId: request_sandbox_132 retryable: true InternalError: description: 'Unexpected Bilt error. For headless payments, do not retry blindly: the charge may have been accepted — check for a `payment.*` webhook for the same `orderId` first, and retry with the **same** `Idempotency-Key`. ' content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' example: error: code: INTERNAL_ERROR message: Unexpected server error requestId: request_sandbox_133 retryable: false Conflict: description: Idempotency conflict, or the session is already terminal. content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' examples: idempotencyConflict: value: error: code: IDEMPOTENCY_CONFLICT message: Idempotency-Key was already used with a different request body requestId: request_sandbox_130 retryable: false sessionAlreadyCompleted: value: error: code: SESSION_ALREADY_COMPLETED message: The checkout session is already in a terminal state requestId: request_sandbox_131 retryable: false HeadlessNotFound: description: 'The customer is not linked to a Bilt member, or the member has no default Bilt payment method to charge. ' content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' examples: customerNotFound: value: error: code: CUSTOMER_NOT_FOUND message: No linked Bilt member for integratorCustomerId requestId: request_sandbox_128 retryable: false paymentMethodNotFound: value: error: code: PAYMENT_METHOD_NOT_FOUND message: The member has no default payment method requestId: request_sandbox_129 retryable: false ServiceUnavailable: description: 'Bilt could not reach the customer''s wallet or another required dependency. Nothing was charged. Retry with backoff. ' content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' example: error: code: PAYMENT_UNAVAILABLE message: Payment could not be attempted; try again shortly requestId: request_sandbox_134 retryable: true Unauthenticated: description: Missing, expired, or wrong-audience access token. content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' example: error: code: UNAUTHENTICATED message: Missing or invalid access token requestId: request_sandbox_126 retryable: false securitySchemes: checkoutPartnerOAuth: type: oauth2 description: 'OAuth 2.0 client credentials against the `enterprise-partner` Keycloak realm. Bilt issues your client id and client secret during onboarding; tokens carry an audience Bilt assigns to your client at onboarding, and Bilt identifies your integration from the token''s `azp` claim. You do not request the audience or any scope yourself: Bilt assigns the audience to your client at onboarding, and no scopes are required — a plain client-credentials grant with your client id and secret is enough. The values you need from Bilt are the token endpoint for the environment, your client id, and your client secret. Send the result as `Authorization: Bearer `. The token URL below is **staging** — production is `https://www.bilt.com/realms/enterprise-partner/protocol/openid-connect/token`. Keep the client secret server-side only. ' flows: clientCredentials: tokenUrl: https://staging.biltrewards.com/realms/enterprise-partner/protocol/openid-connect/token scopes: {} x-tagGroups: - name: Checkout SDK tags: - Integration models - Gateway mode - Choosing an acquirer - One-time payments - Headless payments - Default payment method - Payment webhooks