API reference

Payments

Public payment request endpoints for provider-neutral merchant-facing BRL payment-link workflows.

Provider link generation is asynchronous. New records may briefly remain link_pending with payment_link_url = null until the payments worker records the configured provider's approval URL or Pix artifact. The offered merchant provider is currently abacate_pay (the sandbox default fixture reports provider: iniciador as its schema name); Pix providers may also return pix_copy_paste and pix_qr_code_base64.
Payment webhooks carry an event-time snapshot, not the payment's later live state. Link creation emits both payment.approval_available and the additive payment.link_generated alias. Delivery order is not guaranteed: use occurred_at as business-event time, dedupe by envelope id, and apply status updates monotonically. Once a payment is terminal, ignore a late payment.created or link-ready event. created_at records fanout time.
Agentic Payments is a separate partnership surface: /v1/agentic/banks, /v1/agentic/authorizations, and /v1/agentic/payments. Do not model payer-bank authorizations or dynamic Pix destinations through these generic Payments endpoints.

Merchant payment webhook contract

Subscribe to payment.created, payment.approval_available (or its payment.link_generated alias), and the terminal payment.paid, payment.failed, payment.expired, and payment.cancelled events. Every event carries the following sanitized snapshot under envelope data; raw provider callbacks and mutable provider_metadata are never included.

Webhook data

FieldTypeNotes
idrequiredstring
Tyxter payment request id.
len 1..∞
objectrequired"payment_request"
payment_request_idrequiredstring
Legacy alias of id; retained for existing integrations.
len 1..∞
statusrequired"link_pending" | "link_generated" | "paid" | "failed" | "expired" | "cancelled"
Payment status when this event occurred.
amount_brlrequiredstring | null
Decimal BRL amount from the event-time snapshot.
currencyrequiredstring
len 1..∞
descriptionrequiredstring | null
customer_namerequiredstring | null
customer_phonerequiredstring | null
customer_emailrequiredstring | null
external_referencerequiredstring | null
metadatarequiredunknown | null
payment_link_urlrequiredstring | null
providerrequiredstring | null
provider_payment_idrequiredstring | null
provider_approval_idrequiredstring | null
provider_event_idstring | null
provider_event_typestring
operationstring
error_codestring
error_messagestring
sandbox_simulatorboolean
sandbox_pay_pageboolean

payment.created has status: "link_pending" and payment_link_url: null. The two link-ready names have status: "link_generated" and a non-null URL. Terminal event names match their data.status.

payment.created

{
  "id": "evt_created_01K...",
  "type": "payment.created",
  "created_at": "2026-07-09T11:59:59.100Z",
  "occurred_at": "2026-07-09T11:59:59.000Z",
  "environment": "sandbox",
  "trace_id": "trc_01K...",
  "data": {
    "id": "pay_01K...",
    "object": "payment_request",
    "payment_request_id": "pay_01K...",
    "status": "link_pending",
    "amount_brl": "42.00",
    "currency": "BRL",
    "description": "Class booking",
    "customer_name": "Diego",
    "customer_phone": "+5511987654321",
    "customer_email": "[email protected]",
    "external_reference": "booking_123",
    "metadata": { "booking_id": "booking_123" },
    "payment_link_url": null,
    "provider": "abacate_pay",
    "provider_payment_id": null,
    "provider_approval_id": null,
    "provider_event_id": null
  }
}

payment.approval_available

{
  "id": "evt_01K...",
  "type": "payment.approval_available",
  "created_at": "2026-07-09T12:00:01.000Z",
  "occurred_at": "2026-07-09T12:00:00.000Z",
  "environment": "sandbox",
  "trace_id": "trc_01K...",
  "data": {
    "id": "pay_01K...",
    "object": "payment_request",
    "payment_request_id": "pay_01K...",
    "status": "link_generated",
    "amount_brl": "42.00",
    "currency": "BRL",
    "description": "Class booking",
    "customer_name": "Diego",
    "customer_phone": "+5511987654321",
    "customer_email": "[email protected]",
    "external_reference": "booking_123",
    "metadata": { "booking_id": "booking_123" },
    "payment_link_url": "https://pay.example.com/pay_01K...",
    "provider": "abacate_pay",
    "provider_payment_id": "bill_01K...",
    "provider_approval_id": null,
    "provider_event_id": null
  }
}

payment.paid

{
  "id": "evt_paid_01K...",
  "type": "payment.paid",
  "created_at": "2026-07-09T12:00:02.000Z",
  "occurred_at": "2026-07-09T12:00:01.500Z",
  "environment": "sandbox",
  "trace_id": "trc_01K...",
  "data": {
    "id": "pay_01K...",
    "object": "payment_request",
    "payment_request_id": "pay_01K...",
    "status": "paid",
    "amount_brl": "42.00",
    "currency": "BRL",
    "description": "Class booking",
    "customer_name": "Diego",
    "customer_phone": "+5511987654321",
    "customer_email": "[email protected]",
    "external_reference": "booking_123",
    "metadata": { "booking_id": "booking_123" },
    "payment_link_url": "https://pay.example.com/pay_01K...",
    "provider": "abacate_pay",
    "provider_payment_id": "bill_01K...",
    "provider_approval_id": null,
    "provider_event_id": "provider_evt_01K..."
  }
}

Monotonic consumer

const terminal = new Set(['paid', 'failed', 'expired', 'cancelled']);

function applyPaymentStatus(current, incoming) {
  if (terminal.has(current)) return current; // terminal is absorbing
  if (terminal.has(incoming)) return incoming;
  if (current === 'link_generated' && incoming === 'link_pending') return current;
  return incoming;
}

// Dedupe event.id before calling this function. Never send a link when the
// resulting state is terminal, even if a link-ready event arrived last.

Fees

Every accepted payment carries its payment-service fees in fees, the same object on agentic payments (/v1/agentic/payments), returned by create, retrieve, list and every other route that returns the payment. fees.initiation.amount_brl is the flat initiation fee, charged once at acceptance whatever the outcome. fees.completion.amount_brl is the completion fee, fees.completion.rate of the amount (a fraction: "0.01" is 1%), held from the balance at acceptance until the outcome. fees.completion.state is held, settled (the payment collected the money and the fee is charged), released (the hold was returned to the balance, normally because the payment ended without being paid) or unresolved (a production hold still held after the payment reached a final status, or 24 hours after acceptance, while Tyxter waits for the provider to confirm the outcome). fees.rate_card_id is the pricing version, and the two reservation_id values match payment_fee.reservation_id on GET /v1/billing/ledger. Amounts are decimal strings with four places.

In sandbox fees.simulated is true: the same amounts are recorded and nothing leaves the balance; list those ledger entries with GET /v1/billing/ledger?environment=sandbox. fees: null means no fee is owed, because the payment was charged none (it was accepted before payment-service fees applied, or by an API version that did not charge them). A creation, request approval or sandbox status call replayed with the same Idempotency-Key returns its stored response, with the fees as they were at the original call (a response stored before the field existed replays without it); retrieve the payment for the current state.

Creation refuses for the fees before anything is created or charged, and leaves no idempotency receipt: 402 insufficient_balance when the production balance cannot cover the initiation fee plus the completion hold (top up, then retry with the same Idempotency-Key), and 503 payment_fee_pricing_unavailable when the fee prices cannot be read (retry later). Both carry the error.feedback pointer. A production key whose credit is exhausted is refused before that with 402 credit_balance_exhausted, which is not retryable until credit recovers and carries no error.feedback pointer.

Create

POST/v1/paymentsIdempotency-Key supported

Request

FieldTypeNotes
amount_brl_centavosrequiredinteger
range -∞..9007199254740991
descriptionstring
len 1..500
customer_namestring
len 1..255
customer_tax_idstring
pattern: ^\d{11}(\d{3})?$
customer_phonestring
pattern: ^\+\d{8,15}$
customer_emailstring
len 0..255; pattern: ^(?!\.)(?!.*\.\.)([A-Za-z0-9_'+\-\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\-]*\.)+[A-Za-z]{2,}$
external_referencestring
len 1..255
metadataobject
provider_optionsobject

Response

FieldTypeNotes
idrequiredstring
objectrequired"payment_request"
statusrequired"link_pending" | "link_generated" | "approval_requested" | "approved" | "paid" | "failed" | "expired" | "cancelled"
environmentrequired"sandbox" | "production"
amount_brlrequiredstring
currencyrequired"BRL"
descriptionrequiredstring | null
customer_namerequiredstring | null
customer_tax_idrequiredstring | null
customer_phonerequiredstring | null
customer_emailrequiredstring | null
external_referencerequiredstring | null
metadatarequiredobject | null
payment_link_urlrequiredstring | null
pix_copy_pasterequiredstring | null
pix_qr_code_base64requiredstring | null
providerrequired"iniciador" | "abacate_pay"
provider_connection_idrequiredstring | null
provider_payment_idrequiredstring | null
provider_approval_idrequiredstring | null
provider_metadatarequiredobject | null
trace_idrequiredstring
created_atrequiredstring<ISO-8601>
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
updated_atrequiredstring<ISO-8601>
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
link_generated_atrequiredstring<ISO-8601> | null
approval_requested_atrequiredstring<ISO-8601> | null
approved_atrequiredstring<ISO-8601> | null
paid_atrequiredstring<ISO-8601> | null
failed_atrequiredstring<ISO-8601> | null
expired_atrequiredstring<ISO-8601> | null
cancelled_atrequiredstring<ISO-8601> | null
feesobject | null
The payment-service fees of this payment. null: no fee is owed, because the payment was charged none (it was accepted before payment-service fees applied, or by an API version that did not charge them). A request replayed with the same Idempotency-Key (creation, request approval, the sandbox status route or cancel) returns its stored response, so fees are as they were at the original call; read the payment for their current state. Absent only on such a replay whose response was stored before this field existed.

List

GET/v1/payments

Query

FieldTypeNotes
limitrequiredinteger
range 1..100
starting_afterstring
status"link_pending" | "link_generated" | "approval_requested" | "approved" | "paid" | "failed" | "expired" | "cancelled"

Response

FieldTypeNotes
objectrequired"list"
datarequiredobject[]
has_morerequiredboolean
next_cursorrequiredstring | null

Retrieve

GET/v1/payments/{payment_id}

Response

FieldTypeNotes
idrequiredstring
objectrequired"payment_request"
statusrequired"link_pending" | "link_generated" | "approval_requested" | "approved" | "paid" | "failed" | "expired" | "cancelled"
environmentrequired"sandbox" | "production"
amount_brlrequiredstring
currencyrequired"BRL"
descriptionrequiredstring | null
customer_namerequiredstring | null
customer_tax_idrequiredstring | null
customer_phonerequiredstring | null
customer_emailrequiredstring | null
external_referencerequiredstring | null
metadatarequiredobject | null
payment_link_urlrequiredstring | null
pix_copy_pasterequiredstring | null
pix_qr_code_base64requiredstring | null
providerrequired"iniciador" | "abacate_pay"
provider_connection_idrequiredstring | null
provider_payment_idrequiredstring | null
provider_approval_idrequiredstring | null
provider_metadatarequiredobject | null
trace_idrequiredstring
created_atrequiredstring<ISO-8601>
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
updated_atrequiredstring<ISO-8601>
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
link_generated_atrequiredstring<ISO-8601> | null
approval_requested_atrequiredstring<ISO-8601> | null
approved_atrequiredstring<ISO-8601> | null
paid_atrequiredstring<ISO-8601> | null
failed_atrequiredstring<ISO-8601> | null
expired_atrequiredstring<ISO-8601> | null
cancelled_atrequiredstring<ISO-8601> | null
feesobject | null
The payment-service fees of this payment. null: no fee is owed, because the payment was charged none (it was accepted before payment-service fees applied, or by an API version that did not charge them). A request replayed with the same Idempotency-Key (creation, request approval, the sandbox status route or cancel) returns its stored response, so fees are as they were at the original call; read the payment for their current state. Absent only on such a replay whose response was stored before this field existed.

Cancel a hosted checkout

POST/v1/payments/{payment_id}/cancel

Send an empty JSON object with payments:write and an optional Idempotency-Key. HTTP 200 returns the current payment while cancellation runs asynchronously. Poll the payment or consume its terminal webhook to observe provider confirmation. A keyed retry replays the original response; retrieve for current state. Supported terminal payments are a no-op; a link that is not ready returns 409 payment_link_not_ready. Transparent Pix and unsupported providers return 400 payment_cancellation_unsupported with error.feedback and no mutation. Pix requires a provider-confirmed terminal outcome such as expiry. Failed or uncertain reads and deletion attempts keep the completion fee held for automated recovery. Confirmed paid takes precedence; nonpaid release also requires proven create history. The SDK method is client.payments.cancel(id, { idempotencyKey }).

Request approval

POST/v1/payments/{payment_id}/request-approvalIdempotency-Key supported

Request

FieldTypeNotes
notestring
len 1..500
metadataobject

Response

FieldTypeNotes
idrequiredstring
objectrequired"payment_request"
statusrequired"link_pending" | "link_generated" | "approval_requested" | "approved" | "paid" | "failed" | "expired" | "cancelled"
environmentrequired"sandbox" | "production"
amount_brlrequiredstring
currencyrequired"BRL"
descriptionrequiredstring | null
customer_namerequiredstring | null
customer_tax_idrequiredstring | null
customer_phonerequiredstring | null
customer_emailrequiredstring | null
external_referencerequiredstring | null
metadatarequiredobject | null
payment_link_urlrequiredstring | null
pix_copy_pasterequiredstring | null
pix_qr_code_base64requiredstring | null
providerrequired"iniciador" | "abacate_pay"
provider_connection_idrequiredstring | null
provider_payment_idrequiredstring | null
provider_approval_idrequiredstring | null
provider_metadatarequiredobject | null
trace_idrequiredstring
created_atrequiredstring<ISO-8601>
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
updated_atrequiredstring<ISO-8601>
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
link_generated_atrequiredstring<ISO-8601> | null
approval_requested_atrequiredstring<ISO-8601> | null
approved_atrequiredstring<ISO-8601> | null
paid_atrequiredstring<ISO-8601> | null
failed_atrequiredstring<ISO-8601> | null
expired_atrequiredstring<ISO-8601> | null
cancelled_atrequiredstring<ISO-8601> | null
feesobject | null
The payment-service fees of this payment. null: no fee is owed, because the payment was charged none (it was accepted before payment-service fees applied, or by an API version that did not charge them). A request replayed with the same Idempotency-Key (creation, request approval, the sandbox status route or cancel) returns its stored response, so fees are as they were at the original call; read the payment for their current state. Absent only on such a replay whose response was stored before this field existed.

Sandbox terminal status

POST/v1/sandbox/payments/{payment_id}/statusIdempotency-Key supported

Sandbox-only fixture. Forces a payment request to paid, failed, expired, or cancelled and emits the matching customer-visible payment event, such as payment.paid, without calling a provider.

The connectionless sandbox default uses a deterministic hosted-link fixture. It does not emulate Abacate Pay checkout or transparent-Pix options; select an Abacate Pay sandbox connection, then re-read GET /v1/provider-connections/status and require channels.payments.active_mode === "abacate_pay" before sending provider_options.abacate_pay. This read requires provider_connections:read; a key without it receives 403 insufficient_scope.

Request

FieldTypeNotes
statusrequired"paid" | "failed" | "expired" | "cancelled"
provider_event_idstring
len 1..255
metadataobject

Response

FieldTypeNotes
idrequiredstring
objectrequired"payment_request"
statusrequired"link_pending" | "link_generated" | "approval_requested" | "approved" | "paid" | "failed" | "expired" | "cancelled"
environmentrequired"sandbox" | "production"
amount_brlrequiredstring
currencyrequired"BRL"
descriptionrequiredstring | null
customer_namerequiredstring | null
customer_tax_idrequiredstring | null
customer_phonerequiredstring | null
customer_emailrequiredstring | null
external_referencerequiredstring | null
metadatarequiredobject | null
payment_link_urlrequiredstring | null
pix_copy_pasterequiredstring | null
pix_qr_code_base64requiredstring | null
providerrequired"iniciador" | "abacate_pay"
provider_connection_idrequiredstring | null
provider_payment_idrequiredstring | null
provider_approval_idrequiredstring | null
provider_metadatarequiredobject | null
trace_idrequiredstring
created_atrequiredstring<ISO-8601>
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
updated_atrequiredstring<ISO-8601>
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
link_generated_atrequiredstring<ISO-8601> | null
approval_requested_atrequiredstring<ISO-8601> | null
approved_atrequiredstring<ISO-8601> | null
paid_atrequiredstring<ISO-8601> | null
failed_atrequiredstring<ISO-8601> | null
expired_atrequiredstring<ISO-8601> | null
cancelled_atrequiredstring<ISO-8601> | null
feesobject | null
The payment-service fees of this payment. null: no fee is owed, because the payment was charged none (it was accepted before payment-service fees applied, or by an API version that did not charge them). A request replayed with the same Idempotency-Key (creation, request approval, the sandbox status route or cancel) returns its stored response, so fees are as they were at the original call; read the payment for their current state. Absent only on such a replay whose response was stored before this field existed.