Skip to main content
These endpoints are consumed by the hosted payment page (the buyer’s browser). You normally do not call them directly — the Z2Pay page does. They are documented here for transparency, or in case you want to build a custom checkout on top of our API.
Authentication: no x-api-key. Authentication is the possession of the cs_* ID (48-char hex = 192 bits of entropy). Public endpoints have rate-limiting per IP.
The examples use the sandbox: API at https://checkout-api.sandbox.z2pay.com and page at https://pay.sandbox.z2pay.com. In production, use https://checkout-api.z2pay.com and https://pay.z2pay.com.

Endpoints

MethodRouteWhat it doesRate-limit
GET/public/checkout/{id}Fetches the public config to render the page60 req/min/IP
POST/public/checkout/{id}/openedMarks the Session as “opened by the buyer”60 req/min/IP
POST/public/checkout/{id}/confirmConfirms the payment (tokenId + buyer data)10 req/min/IP
The {id} can be a Session (cs_*), a Link (chk_*), or a slug. When given a Link or slug, the endpoint materializes a new Session and returns it.

Get public config

GET /public/checkout/{id}
Returns the data needed to render the payment page. Accepts a Session (cs_*) or Link (chk_*). When given a Link, it materializes a new Session and returns it.
sessionId
string
Only when {id} is a Link (chk_*). The client sends a candidate ID (cs_[a-f0-9]{48}, locally generated with 192 bits of entropy) so the Session is materialized idempotently — a refresh with the same sessionId reuses the existing Session. For a direct cs_*, this parameter is ignored.
curl https://checkout-api.sandbox.z2pay.com/public/checkout/cs_a1b2c3d4...
Response (200):
{
  "session": {
    "id": "cs_...",
    "status": "created",
    "config": { "...": "branding, paymentMethods, customFields, requiredFields" },
    "amount": 8500,
    "currency": "BRL",
    "locale": "pt-BR",
    "expiresAt": "2026-06-25T12:00:00.000Z"
  },
  "url": "https://pay.sandbox.z2pay.com/c/cs_...",
  "items": [
    { "name": "...", "quantity": 1, "unitAmount": 8500, "imageUrl": null, "description": null }
  ]
}
The returned Session is a masked public view — it does not include metadata, tenantId, or transactionId. Only what is needed to render the page is exposed.
Possible statuses: 200 · 404 (invalid or expired ID).

Mark as opened

POST /public/checkout/{id}/opened
Idempotent — transitions the status created → opened only on the first call. Fires the checkout.session.opened event.
sessionId
string
Required only when {id} is a Link (chk_*). Same sessionId as the GET; allows the Session to be materialized idempotently.
curl -X POST https://checkout-api.sandbox.z2pay.com/public/checkout/cs_a1b2c3d4.../opened \
  -H "Content-Type: application/json" \
  -d '{}'
Response (200):
{ "session": { "id": "cs_...", "status": "opened", "openedAt": "2026-06-24T12:01:00.000Z" } }

Confirm payment

POST /public/checkout/{id}/confirm
Submits the buyer’s data plus card token(s) to finalize the payment. Accepts a Session (cs_*) or Link (chk_*). Idempotent via the Idempotency-Key header: repeated requests return the original response, and a concurrent call waits for the first one to finish — the primary defense against double charges.
amount and items are not accepted in the body — the Session’s values are used (immutable, following Stripe’s PaymentIntent pattern). To change the amount, create a new Session.
Archived Link: confirm re-validates the status of the parent Link. If the seller archived the Link after the Session was materialized, confirm returns 409 link_not_active — even if the Session already existed. This ensures no payment is processed against a discontinued Link.

Body

payments
array
required
Payment entries (1–8). 1 entry = single-method flow; 2+ entries = combined payment (requires paymentMethods.combined.enabled on the Session). The sum of all amount values must match exactly session.amount.
customer
object
required
Full buyer details. Must satisfy the Session’s requiredFields (email, document, and phone are always required; address if listed). See Customer.
customFieldsValues
object
Values for the Session’s customFields. Keys match customFields[].key; values are strings ("true"/"false" for checkboxes); each value ≤ 2000 chars.
Each payments entry is discriminated by paymentMethod:
{
  "paymentMethod": "credit_card",
  "amount": 8500,
  "card": {
    "tokenId": "tok_...",
    "holderName": "JOAO SILVA",
    "installments": 3
  }
}
tokenId is required; holderName is optional; installments from 1 to 12. Tokenize the card via the Tokenizer before calling confirm.
{ "paymentMethod": "pix", "amount": 5000 }
{ "paymentMethod": "boleto", "amount": 12000 }

Full example

curl -X POST https://checkout-api.sandbox.z2pay.com/public/checkout/cs_a1b2c3d4.../confirm \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 7c9e6679-7425-40de-944b-e07fc1f90ae7" \
  -d '{
    "payments": [
      {
        "paymentMethod": "credit_card",
        "amount": 8500,
        "card": { "tokenId": "tok_abc...", "holderName": "JOAO SILVA", "installments": 3 }
      }
    ],
    "customer": {
      "name": "João Silva",
      "email": "joao@example.com",
      "document": "12345678900",
      "documentType": "cpf",
      "phone": "+5511999999999"
    },
    "customFieldsValues": { "company_name": "Acme Inc" }
  }'
Response (200):
{
  "session": { "id": "cs_...", "status": "paid", "paidAt": "..." },
  "payments": [
    {
      "id": "pay_...",
      "status": "paid",
      "paymentMethod": "credit_card",
      "amount": 8500,
      "installments": 3,
      "boletoUrl": null,
      "boletoDigitableLine": null,
      "boletoBarcode": null,
      "pixUrl": null,
      "expiresAt": null,
      "errorMessage": null,
      "declineCode": null
    }
  ]
}
  • For PIX, pixUrl contains the BR-Code payload for the banking app; expiresAt indicates the expiration.
  • For boleto, boletoUrl / boletoDigitableLine / boletoBarcode carry the boleto data.
  • If declined, session.status reverts to opened (retry allowed) and payments[].errorMessage / declineCode explain the reason.
Possible statuses: 200 (payment result, success or decline) · 409 (Session in an invalid state — already paid, expired, or cancelled — or parent Link archived → link_not_active).
To test approvals and declines, use the sandbox test cards.

Buyer lifecycle (summary)

1

Opens the URL

The buyer accesses https://pay.sandbox.z2pay.com/c/{id}. The page calls GET /public/checkout/{id} to load the config.
2

Page marks as opened

The page calls POST /public/checkout/{id}/opened — the Session transitions from createdopened and fires checkout.session.opened.
3

Buyer confirms

When the buyer clicks “Pay”, the page tokenizes the card (if applicable) and calls POST /public/checkout/{id}/confirm. The Session passes through paying and ends in paid (or reverts to opened if declined).
4

You receive the webhook

checkout.session.payment_succeeded (or payment_failed) arrives at your webhook URL. Reconcile using the Session’s metadata.

See also

Checkout Sessions

Session states and the Customer object.

Checkout Overview

Concepts and endpoint map.

Tokenizer

How to generate the card tokenId before calling confirm.

Test Cards

Approval and decline scenarios in the sandbox.

Webhooks

Events fired throughout the buyer lifecycle.

Errors

Domain error codes from confirm (amount_mismatch, combined_disabled, etc.).