Payments API for partners
Process payments for your merchants with Outpost as merchant of record. Send the payment with the order and customer details, and Outpost processes it on its own payment accounts, issues the receipt or invoice, and handles the tax. This API doesn't return those documents.
Amounts are tax-inclusive: submit the total the shopper sees at checkout.
Because Outpost is the seller, the merchant must add the seller disclosure to its checkout; the API doesn't return disclosure text.
| Endpoint | Purpose |
|---|---|
POST /api/payments | Create and process a payment |
GET /api/payments/{paymentId} | Retrieve a payment |
POST /api/payments/{paymentId}/cancel | Cancel one pending Pix Automático charge |
GET /api/pix-authorisations/{pixAuthorisationId} | Retrieve a Pix Automático authorisation |
POST /api/pix-authorisations/{pixAuthorisationId}/cancel | Cancel a Pix Automático authorisation |
POST /api/payments/{paymentId}/refunds | Refund a payment, in full or in part |
POST /api/webhooks | Register a webhook endpoint for a merchant |
Payment flow
Authentication
Requests use the merchant's own Outpost credentials. When a merchant enables Outpost in your platform, they enter the Client ID and Client Secret from their Outpost dashboard. Exchange them for an access token with the OAuth 2.0 client_credentials grant, sending them as client_id and client_secret. Each token acts for that merchant. The response returns access_token and expires_in in seconds; request a new token before it expires.
Authorization: Bearer <your_access_token>
Authentication
curl -X POST \
"https://access.outpostanywhere.com/oauth2/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=$MERCHANT_CLIENT_ID" \
-d "client_secret=$MERCHANT_CLIENT_SECRET" | jqConventions
| Topic | Rule |
|---|---|
| Base URL | https://api.outpostanywhere.com |
| Format | JSON over HTTPS, camelCase field names |
| Amounts | An object of amount, a decimal string (for example "120.99"), and an ISO 4217 currency |
| Countries | ISO 3166-1 alpha-2, uppercase |
| IDs | Payment, refund and Pix authorisation IDs are UUIDs |
| Idempotency | Every POST requires an Idempotency-Key header of at most 255 characters. Retrying with the same key and a byte-identical body returns the resource the first request created, in its current state; the same key with a different body returns 422 idempotency_key_reused. Keys are scoped to the merchant and stay used permanently once a request succeeds: use a new key for each new payment or refund |
Create payment
POST/api/paymentsProcesses a payment for the tax-inclusive total of an order. To retry a failed payment, create a new payment with a new Idempotency-Key; it can keep the same merchantReference.
Request Headers
| Parameter | Type | Required | Description |
|---|---|---|---|
| Authorization | string | Yes | Bearer <access_token> |
| Content-Type | string | Yes | application/json |
| Idempotency-Key | string | Yes | Unique key for this request. See Conventions |
Request Body Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| merchantReference | string | Yes | Your order or transaction reference. Can be reused across attempts; each attempt gets its own payment ID |
| amount | object | Yes | Tax-inclusive total: amount (decimal string) and currency (ISO 4217), equal to the sum of the line items. Must be BRL when the billing country is BR. "0.00" only for a card verification |
| customer.merchantCustomerReference | string | Your customer ID. Must stay the same for a customer and must not contain personal data | |
| customer.firstName | string | Yes | Shopper first name |
| customer.lastName | string | Yes | Shopper last name |
| customer.email | string | Yes | For the receipt or invoice |
| customer.billingAddress | object | Yes | line1, line2, city, state, postalCode, country. country is always required; outside the EU, line1, city and postalCode are too, and US and CA addresses need a two-letter state |
| customer.shippingAddress | object | The same fields and rules as billingAddress | |
| customer.taxIdentifiers[] | array | type (BR_CPF, BR_CNPJ, EU_VAT, GB_VAT, US_EIN) and code. Outpost checks CPF and CNPJ check digits | |
| lineItems[] | array | Yes | merchantLineItemReference, productCode (your own SKU; defaults to merchantLineItemReference), description, productType, unitPrice (tax-inclusive decimal string), quantity |
| lineItems[].productType | string | Yes | PHYSICAL, DIGITAL or SERVICES (a fee on a goods order). An order with a SERVICES line needs at least one PHYSICAL line priced above zero, or Outpost returns 400 invalid_argument. A service sold on its own is DIGITAL |
| lineItems[].ancillaryType | string | COMMISSION, SHIPPING_COST, HANDLING, PACKAGING or OTHER | |
| evidence.ipAddress | string | The shopper's IP address | |
| paymentMethod.type | string | Yes | How the shopper pays. See the payment method types below |
| returnUrl | string | Where the shopper returns after a 3-D Secure challenge or bank redirect | |
| metadata | object | No | String key-value pairs, returned on the payment and its webhooks |
Payment method types
Each method adds its own fields, described in its section.
| paymentMethod.type | Meaning |
|---|---|
| card | A card number or network token, including decrypted Apple Pay and Google Pay tokens. Outpost runs 3-D Secure when the shopper is present |
| ideal | Outpost returns a bank redirect |
| pix | Outpost returns a QR code. Add pixAutomatico to enrol a recurring authorisation |
| pixAutomatico | Charges an ACTIVE Pix Automático authorisation on billingDate |
Response 201 Created · captured
{
"id": "01a182d1-82b8-7b18-bf89-08ff16b3fbfd",
"merchantReference": "order-1042",
"status": "CAPTURED",
"amount": { "amount": "120.99", "currency": "EUR" },
"paymentMethod": { "type": "card", "brand": "visa", "last4": "1111" },
"createdAt": "2026-10-28T14:02:11Z",
"capturedAt": "2026-10-28T14:02:12Z",
"metadata": {}
}Response 201 Created · failed
failure says why the payment failed. See Payment failures for its fields and codes.
{
"id": "01a1830f-a8e0-7448-bd72-c4d4d3dd8e1b",
"merchantReference": "order-1043",
"status": "FAILED",
"amount": { "amount": "120.99", "currency": "EUR" },
"paymentMethod": { "type": "card", "brand": "visa", "last4": "1111" },
"failure": {
"code": "card_declined",
"message": "The card was declined by the issuer.",
"declineCode": "05",
"retryable": false
},
"createdAt": "2026-10-28T15:10:04Z",
"failedAt": "2026-10-28T15:10:05Z",
"metadata": {}
}Code Example
curl -X POST \
"https://api.outpostanywhere.com/api/payments" \
-H "Authorization: Bearer $OUTPOST_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"merchantReference": "order-1042",
"amount": { "amount": "120.99", "currency": "EUR" },
"customer": {
"merchantCustomerReference": "CUST-001",
"firstName": "John",
"lastName": "Doe",
"email": "john.doe@example.com",
"billingAddress": {
"line1": "Keizersgracht 123",
"city": "Amsterdam",
"postalCode": "1015 CJ",
"country": "NL"
}
},
"lineItems": [
{
"merchantLineItemReference": "ITEM-001",
"productCode": "SKU-123",
"description": "Design course, lifetime access",
"productType": "DIGITAL",
"unitPrice": "120.99",
"quantity": 1
}
],
"evidence": { "ipAddress": "185.23.108.42" },
"browserInfo": {
"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 14_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Safari/605.1.15",
"acceptHeader": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"language": "nl-NL",
"colorDepth": 24,
"screenHeight": 900,
"screenWidth": 1440,
"timeZoneOffset": -60,
"javaEnabled": false,
"javaScriptEnabled": true
},
"paymentMethod": {
"type": "card",
"card": {
"number": "4111111111111111",
"cvc": "737",
"expiryMonth": "03",
"expiryYear": "2030",
"holderName": "John Doe"
}
},
"returnUrl": "https://checkout.example.com/return"
}' | jqThis example is a card payment; see Cards for paymentMethod.card and browserInfo. Responses carry the fields listed under Get payment.
Get payment
GET/api/payments/{paymentId}Returns the payment's current state, with the fields below. Use it to confirm a result when the shopper returns from a redirect. If a create request times out, you have no payment ID: retry it with the same Idempotency-Key.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| paymentId | string | Yes | Outpost payment ID (UUID) |
Response 200 OK
{
"id": "01a182d1-82b8-7b18-bf89-08ff16b3fbfd",
"merchantReference": "order-1042",
"status": "CAPTURED",
"amount": { "amount": "120.99", "currency": "EUR" },
"paymentMethod": { "type": "card", "brand": "visa", "last4": "1111" },
"createdAt": "2026-10-28T14:02:11Z",
"capturedAt": "2026-10-28T14:02:12Z",
"metadata": {}
}Response Fields
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | string | - | Outpost payment ID (UUID) |
| merchantReference | string | - | As sent |
| status | string | - | PENDING, REQUIRES_ACTION, CAPTURED, FAILED or CANCELED. See Payment status. New values may be added |
| amount | object | - | As sent |
| paymentMethod.type | string | - | As sent |
| paymentMethod.brand | string | - | card only: visa, mastercard, amex, elo or hipercard. New values may be added |
| paymentMethod.last4 | string | - | card only: the last four digits of the card number, or of the network token |
| paymentMethod.networkTransactionId | string | - | On a CAPTURED payment with recurring.initiator CUSTOMER, in this response and on GET. After a 3-D Secure challenge, fetch it with GET when payment.captured arrives. Send it on later charges |
| paymentMethod.recurring | object | - | As sent, without networkTransactionId |
| paymentMethod.pixAuthorisationId | string | - | pixAutomatico charges only |
| paymentMethod.billingDate | string | - | pixAutomatico charges only |
| pixAuthorisation | object | - | Pix Automático enrolment payments only: id and status of the authorisation it created |
| action | object | - | REQUIRES_ACTION only. type REDIRECT, with url (open it with GET), or QR_CODE, with qrCodeData. expiresAt: when the step lapses and the payment fails |
| failure | object | - | FAILED only. See Payment failures |
| createdAt, capturedAt, failedAt, canceledAt | string | - | ISO 8601 timestamps. capturedAt, failedAt and canceledAt appear once the payment has that status |
| metadata | object | - | As sent |
Code Example
curl "https://api.outpostanywhere.com/api/payments/$PAYMENT_ID" \
-H "Authorization: Bearer $OUTPOST_ACCESS_TOKEN" | jqCards
Send paymentMethod.type card with the card details, or with card.networkToken for a network token or decrypted Apple Pay or Google Pay token. Send card details as you do to other providers, directly or through your card vault's forward proxy; card data is encrypted on receipt.
Card Fields
| Parameter | Type | Required | Description |
|---|---|---|---|
| paymentMethod.card | object | The card details: number, cvc, expiry and holderName, or a networkToken object instead of the number and expiry | |
| paymentMethod.card.number | string | Card number (PAN), 12 to 19 digits, no spaces or separators | |
| paymentMethod.card.cvc | string | No | Card security code, 3 or 4 digits. Send it whenever you have it; omit it when you don't, for example for a Google Pay card number, and always on charges with recurring.initiator MERCHANT |
| paymentMethod.card.expiryMonth | string | Two digits, 01 to 12 (e.g., "03") | |
| paymentMethod.card.expiryYear | string | Four digits (e.g., "2030") | |
| paymentMethod.card.holderName | string | Name as printed on the card, at most 255 characters | |
| paymentMethod.installments | integer | No | Monthly instalments the shopper chose, 2 to 12, for BRL card payments above zero. When omitted, the shopper pays in one instalment |
| browserInfo | object | The EMV 3-D Secure browser fields from the shopper's browser: userAgent, acceptHeader, language, colorDepth, screenHeight, screenWidth, timeZoneOffset, javaEnabled and javaScriptEnabled |
Response 201 Created · 3-D Secure
Send the shopper to action.url. They return to your returnUrl; the result follows as a webhook.
{
"id": "01a182f4-7020-72c6-aba3-26b4604bcb4e",
"merchantReference": "order-1044",
"status": "REQUIRES_ACTION",
"amount": { "amount": "120.99", "currency": "EUR" },
"paymentMethod": { "type": "card", "brand": "visa", "last4": "1111" },
"action": {
"type": "REDIRECT",
"url": "https://acs.issuer.example/challenge/7f3a9c...",
"expiresAt": "2026-10-28T14:55:20Z"
},
"createdAt": "2026-10-28T14:40:20Z",
"metadata": {}
}Apple Pay, Google Pay and network tokens
- You decrypt wallet payloads with your own Apple Pay merchant ID and certificate, and your own Google Pay setup. Outpost doesn't decrypt them.
- When Google Pay returns a card number instead of a token, send it as
typecard; 3-D Secure applies as for any card.
Network Token Fields
| Parameter | Type | Required | Description |
|---|---|---|---|
| paymentMethod.card.networkToken | object | No | The network token or decrypted wallet token. Fields below |
| paymentMethod.card.networkToken.token | string | Token number, 13 to 19 digits | |
| paymentMethod.card.networkToken.expiryMonth | string | Token expiry month, two digits (e.g., "03") | |
| paymentMethod.card.networkToken.expiryYear | string | Token expiry year, four digits (e.g., "2030") | |
| paymentMethod.card.networkToken.cryptogram | string | Base64 cryptogram from the network or wallet, as you received it | |
| paymentMethod.card.networkToken.eci | string | Electronic Commerce Indicator, two digits (e.g., "05") | |
| paymentMethod.card.networkToken.source | string | APPLE_PAY or GOOGLE_PAY: a wallet token you decrypted; Outpost skips 3-D Secure. NETWORK_TOKEN: a token you provisioned with Visa or Mastercard; also send browserInfo and returnUrl, as for a card number; Outpost runs 3-D Secure as for card |
Request Apple Pay
{
"merchantReference": "order-3301",
"amount": { "amount": "54.00", "currency": "EUR" },
"customer": {
"merchantCustomerReference": "CUST-3301",
"firstName": "John",
"lastName": "Doe",
"email": "john.doe@example.com",
"billingAddress": {
"line1": "Keizersgracht 123",
"city": "Amsterdam",
"postalCode": "1015 CJ",
"country": "NL"
},
"shippingAddress": {
"line1": "Keizersgracht 123",
"city": "Amsterdam",
"postalCode": "1015 CJ",
"country": "NL"
}
},
"lineItems": [
{
"merchantLineItemReference": "ITEM-001",
"productCode": "SKU-BAG",
"description": "Leather tote bag",
"productType": "PHYSICAL",
"unitPrice": "54.00",
"quantity": 1
}
],
"evidence": { "ipAddress": "185.23.108.42" },
"paymentMethod": {
"type": "card",
"card": {
"holderName": "John Doe",
"networkToken": {
"token": "4895370012003478",
"expiryMonth": "12",
"expiryYear": "2029",
"cryptogram": "AgAAAAAABk4DWZ4C28yUQAAAAAA=",
"eci": "05",
"source": "APPLE_PAY"
}
}
}
}Recurring card payments
Send paymentMethod.recurring on the first payment, with the shopper present, and on every later charge. You keep the card details and the networkTransactionId Outpost returns.
Recurring Fields
| Parameter | Type | Required | Description |
|---|---|---|---|
| paymentMethod.recurring | object | No | Marks a card payment as part of a recurring series. Send it on the first payment and on every later charge. When omitted, the payment is a one-off. |
| paymentMethod.recurring.initiator | string | Who starts the payment: CUSTOMER or MERCHANT. See the table below | |
| paymentMethod.recurring.type | string | SUBSCRIPTION: charges on a fixed schedule for a fixed or known amount. UNSCHEDULED: charges at varying times or amounts, for example top-ups or usage billing. Send the same value on every payment in the series | |
| paymentMethod.recurring.networkTransactionId | string | Links the charge to the payment the shopper agreed to. A new card number, a switch to a network token, or a subscription moved from another provider needs a new CUSTOMER payment |
| paymentMethod.recurring.initiator | Meaning |
|---|---|
| CUSTOMER | The first payment, with the shopper present. Outpost runs 3-D Secure (not for Apple Pay or Google Pay) and returns networkTransactionId. Send amount "0.00" to verify the card without charging it; Outpost issues no receipt |
| MERCHANT | Every later charge. No shopper step: the result is CAPTURED or FAILED |
Response 201 Created · first recurring card payment
Store paymentMethod.networkTransactionId with the card and send it on each later charge.
{
"id": "01a19c91-4eb8-7994-b099-3e4b67d564f6",
"merchantReference": "sub-2210-2026-11",
"status": "CAPTURED",
"amount": { "amount": "19.99", "currency": "EUR" },
"paymentMethod": {
"type": "card",
"brand": "visa",
"last4": "1111",
"networkTransactionId": "581234567890123",
"recurring": { "initiator": "CUSTOMER", "type": "SUBSCRIPTION" }
},
"createdAt": "2026-11-02T14:02:11Z",
"capturedAt": "2026-11-02T14:02:12Z",
"metadata": {}
}Request later charge
No cvc, browserInfo, returnUrl or evidence.
{
"merchantReference": "sub-2210-2026-12",
"amount": { "amount": "19.99", "currency": "EUR" },
"customer": {
"merchantCustomerReference": "CUST-2210",
"firstName": "John",
"lastName": "Doe",
"email": "john.doe@example.com",
"billingAddress": {
"line1": "Keizersgracht 123",
"city": "Amsterdam",
"postalCode": "1015 CJ",
"country": "NL"
}
},
"lineItems": [
{
"merchantLineItemReference": "PLAN-MONTHLY",
"productCode": "SKU-PLAN-M",
"description": "Design app, monthly plan",
"productType": "DIGITAL",
"unitPrice": "19.99",
"quantity": 1
}
],
"paymentMethod": {
"type": "card",
"card": {
"number": "4111111111111111",
"expiryMonth": "03",
"expiryYear": "2030",
"holderName": "John Doe"
},
"recurring": {
"initiator": "MERCHANT",
"type": "SUBSCRIPTION",
"networkTransactionId": "581234567890123"
}
}
}Request zero-amount card verification
Verifies and saves a card without charging it: one "0.00" line item and recurring.initiator CUSTOMER. installments doesn't apply. The response is CAPTURED with a zero amount and a networkTransactionId, or REQUIRES_ACTION for 3-D Secure.
{
"merchantReference": "card-setup-2210",
"amount": { "amount": "0.00", "currency": "EUR" },
"customer": {
"merchantCustomerReference": "CUST-2210",
"firstName": "John",
"lastName": "Doe",
"email": "john.doe@example.com",
"billingAddress": {
"line1": "Keizersgracht 123",
"city": "Amsterdam",
"postalCode": "1015 CJ",
"country": "NL"
}
},
"lineItems": [
{
"merchantLineItemReference": "PLAN-MONTHLY",
"productCode": "SKU-PLAN-M",
"description": "Design app, monthly plan (card verification)",
"productType": "DIGITAL",
"unitPrice": "0.00",
"quantity": 1
}
],
"evidence": { "ipAddress": "185.23.108.42" },
"paymentMethod": {
"type": "card",
"card": {
"number": "4111111111111111",
"cvc": "737",
"expiryMonth": "03",
"expiryYear": "2030",
"holderName": "John Doe"
},
"recurring": { "initiator": "CUSTOMER", "type": "SUBSCRIPTION" }
},
"browserInfo": {
"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 14_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Safari/605.1.15",
"acceptHeader": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"language": "nl-NL",
"colorDepth": 24,
"screenHeight": 900,
"screenWidth": 1440,
"timeZoneOffset": -60,
"javaEnabled": false,
"javaScriptEnabled": true
},
"returnUrl": "https://checkout.example.com/return"
}iDEAL
Send paymentMethod.type ideal with an amount in EUR and a returnUrl. iDEAL takes no other method fields.
Request iDEAL
{
"merchantReference": "order-3488",
"amount": { "amount": "39.00", "currency": "EUR" },
"customer": {
"merchantCustomerReference": "CUST-3488",
"firstName": "Sanne",
"lastName": "de Vries",
"email": "sanne.devries@example.com",
"billingAddress": {
"line1": "Oudegracht 120",
"city": "Utrecht",
"postalCode": "3511 AX",
"country": "NL"
}
},
"lineItems": [
{
"merchantLineItemReference": "EBOOK-01",
"productCode": "SKU-EBOOK-01",
"description": "Cookbook, ebook edition",
"productType": "DIGITAL",
"unitPrice": "39.00",
"quantity": 1
}
],
"evidence": { "ipAddress": "185.23.108.42" },
"paymentMethod": { "type": "ideal" },
"returnUrl": "https://checkout.example.com/return"
}Response 201 Created · bank redirect
Send the shopper to action.url to approve the payment in their bank. They return to your returnUrl; the result follows as a webhook. If they don't finish before action.expiresAt, the payment fails with authentication_failed.
{
"id": "01a18c7f-d008-7d21-9e3a-6f4b2c8d1a57",
"merchantReference": "order-3488",
"status": "REQUIRES_ACTION",
"amount": { "amount": "39.00", "currency": "EUR" },
"paymentMethod": { "type": "ideal" },
"action": {
"type": "REDIRECT",
"url": "https://ideal.example-bank.nl/pay/9c2f41...",
"expiresAt": "2026-10-30T11:24:09Z"
},
"createdAt": "2026-10-30T11:09:09Z",
"metadata": {}
}Pix
Send paymentMethod.type pix with an amount in BRL and the shopper's CPF or CNPJ in customer.taxIdentifiers[]. Pix has no redirect, so there is no returnUrl. For recurring Pix, see Pix Automático.
Request Pix
{
"merchantReference": "order-2077",
"amount": { "amount": "309.47", "currency": "BRL" },
"customer": {
"merchantCustomerReference": "CUST-5120",
"firstName": "Bruno",
"lastName": "Lima",
"email": "bruno.lima@example.com",
"billingAddress": {
"line1": "Avenida Paulista 1000",
"city": "São Paulo",
"state": "SP",
"postalCode": "01310-100",
"country": "BR"
},
"taxIdentifiers": [{ "type": "BR_CPF", "code": "12345678909" }]
},
"lineItems": [
{
"merchantLineItemReference": "COURSE-PRO",
"productCode": "SKU-COURSE-PRO",
"description": "Photography course, lifetime access",
"productType": "DIGITAL",
"unitPrice": "309.47",
"quantity": 1
}
],
"evidence": { "ipAddress": "177.45.12.8" },
"paymentMethod": { "type": "pix" }
}Response 201 Created · Pix
Render action.qrCodeData as a QR code and offer it to copy. The QR code expires one hour after creation, at action.expiresAt; if the shopper hasn't paid by then, the payment fails with authentication_failed. The result follows as a webhook.
{
"id": "01a18350-24b0-7373-9c9b-78d9b21f17fb",
"merchantReference": "order-2077",
"status": "REQUIRES_ACTION",
"amount": { "amount": "309.47", "currency": "BRL" },
"paymentMethod": { "type": "pix" },
"action": {
"type": "QR_CODE",
"qrCodeData": "00020126580014br.gov.bcb.pix0136...",
"expiresAt": "2026-10-28T17:20:30Z"
},
"createdAt": "2026-10-28T16:20:30Z",
"metadata": {}
}Pix Automático
Recurring Pix for subscriptions priced in BRL.
Enrol with the first payment
Create a payment with paymentMethod.type pix and a paymentMethod.pixAutomatico object. Outpost returns a QR code as for a one-off Pix payment. The shopper approves the first charge and the recurring authorisation together.
Pix Automático Fields
| Parameter | Type | Required | Description |
|---|---|---|---|
| paymentMethod.pixAutomatico | object | No | Enrols a Pix Automático authorisation with this payment; the shopper approves both in one QR code |
| paymentMethod.pixAutomatico.amountType | string | FIXED or VARIABLE. See the table below | |
| paymentMethod.pixAutomatico.recurringAmount | string | The amount every payment must equal, as a decimal string in BRL | |
| paymentMethod.pixAutomatico.minAmount | string | The lowest amount a payment can be, as a decimal string in BRL | |
| paymentMethod.pixAutomatico.frequency | string | WEEKLY, MONTHLY, QUARTERLY, SEMIANNUAL or ANNUAL. Pix Automático has no daily cycle; Outpost returns 400 invalid_argument for any other value | |
| paymentMethod.pixAutomatico.endsAt | string | No | ISO 8601, YYYY-MM-DD. Outpost charges no cycle after this date. When omitted, the authorisation runs until cancelled |
| paymentMethod.pixAutomatico.retryPolicy | boolean | No | Whether Outpost retries a failed debit; set once per authorisation. Defaults to true. See the table below |
| pixAutomatico.amountType | Meaning |
|---|---|
| FIXED | Every payment, including the enrolment, equals recurringAmount |
| VARIABLE | Every payment is at least minAmount. A charge above the shopper's bank-app ceiling fails with authorisation_amount_exceeded |
| pixAutomatico.retryPolicy | Meaning |
|---|---|
| true | Outpost retries a failed debit up to three times within 7 days of billingDate, then sends one payment.captured or payment.failed |
| false | Outpost sends payment.failed on the first failed debit |
Request enrolment
{
"merchantReference": "sub-1042",
"amount": { "amount": "49.90", "currency": "BRL" },
"customer": {
"merchantCustomerReference": "CUST-7781",
"firstName": "Ana",
"lastName": "Souza",
"email": "ana.souza@example.com",
"billingAddress": {
"line1": "Rua Augusta 1500",
"city": "São Paulo",
"state": "SP",
"postalCode": "01304-001",
"country": "BR"
},
"taxIdentifiers": [{ "type": "BR_CPF", "code": "12345678909" }]
},
"lineItems": [
{
"merchantLineItemReference": "PLAN-MONTHLY",
"productCode": "SKU-PLAN-M",
"description": "Fitness app, monthly plan",
"productType": "DIGITAL",
"unitPrice": "49.90",
"quantity": 1
}
],
"evidence": { "ipAddress": "177.45.12.8" },
"paymentMethod": {
"type": "pix",
"pixAutomatico": {
"amountType": "FIXED",
"recurringAmount": "49.90",
"frequency": "MONTHLY"
}
}
}Response 201 Created · enrolment
{
"id": "01a19c91-4eb8-7414-9330-f468f638178e",
"merchantReference": "sub-1042",
"status": "REQUIRES_ACTION",
"amount": { "amount": "49.90", "currency": "BRL" },
"paymentMethod": { "type": "pix" },
"action": {
"type": "QR_CODE",
"qrCodeData": "00020101021226990014br.gov.bcb.pix2577...",
"expiresAt": "2026-11-02T15:02:11Z"
},
"pixAuthorisation": {
"id": "01a19c91-4eb8-7231-b916-d081927e245a",
"status": "PENDING_APPROVAL"
},
"createdAt": "2026-11-02T14:02:11Z",
"metadata": {}
}- The response is
REQUIRES_ACTIONwithaction.qrCodeData, which expires after one hour, andpixAuthorisationinPENDING_APPROVAL. - On approval, Outpost sends
pix_authorisation.approvedandpayment.captured, the authorisation becomesACTIVE, andstartsAtis set to the approval date. The enrolment payment is the first cycle. - If the QR code expires, the authorisation becomes
EXPIREDand the payment fails withauthentication_failed. - If the shopper or their bank refuses, the authorisation becomes
REJECTEDand the payment fails withauthorisation_rejected.
Response 200 OK · Get payment after approval
{
"id": "01a19c91-4eb8-7414-9330-f468f638178e",
"merchantReference": "sub-1042",
"status": "CAPTURED",
"amount": { "amount": "49.90", "currency": "BRL" },
"paymentMethod": { "type": "pix" },
"pixAuthorisation": {
"id": "01a19c91-4eb8-7231-b916-d081927e245a",
"status": "ACTIVE"
},
"createdAt": "2026-11-02T14:02:11Z",
"capturedAt": "2026-11-02T14:05:40Z",
"metadata": {}
}Charge later cycles
- Create a payment with
paymentMethod.typepixAutomatico,pixAuthorisationIdandbillingDate, 2 to 10 days before the billing date. billingDatefalls on the authorisation'sstartsAtor a whole number offrequencycycles after it.- The response is
PENDING. The result arrives aspayment.capturedorpayment.failedon or afterbillingDate, after any retries, unless the charge or its authorisation is cancelled first. - The shopper's bank lets them cancel a single debit; it then fails with
debit_canceledand the authorisation staysACTIVE. - One charge per cycle: a second one returns
409 invalid_statusunless the first isCANCELED. After aFAILEDcharge, create the next cycle's payment. - To stop or change one charge, cancel it.
Charge Fields
| Parameter | Type | Required | Description |
|---|---|---|---|
| paymentMethod.pixAuthorisationId | string | An ACTIVE Pix Automático authorisation (UUID), from pix_authorisation.approved | |
| paymentMethod.billingDate | string | ISO 8601, YYYY-MM-DD. The date the shopper's bank debits the account |
Request charge
{
"merchantReference": "sub-1042-2026-12",
"amount": { "amount": "49.90", "currency": "BRL" },
"customer": {
"merchantCustomerReference": "CUST-7781",
"firstName": "Ana",
"lastName": "Souza",
"email": "ana.souza@example.com",
"billingAddress": {
"line1": "Rua Augusta 1500",
"city": "São Paulo",
"state": "SP",
"postalCode": "01304-001",
"country": "BR"
},
"taxIdentifiers": [{ "type": "BR_CPF", "code": "12345678909" }]
},
"lineItems": [
{
"merchantLineItemReference": "PLAN-MONTHLY",
"productCode": "SKU-PLAN-M",
"description": "Fitness app, monthly plan",
"productType": "DIGITAL",
"unitPrice": "49.90",
"quantity": 1
}
],
"paymentMethod": {
"type": "pixAutomatico",
"pixAuthorisationId": "01a19c91-4eb8-7231-b916-d081927e245a",
"billingDate": "2026-12-02"
}
}Response 201 Created · charge
{
"id": "01a211fa-92e0-7952-800d-54bf6e80d923",
"merchantReference": "sub-1042-2026-12",
"status": "PENDING",
"amount": { "amount": "49.90", "currency": "BRL" },
"paymentMethod": {
"type": "pixAutomatico",
"pixAuthorisationId": "01a19c91-4eb8-7231-b916-d081927e245a",
"billingDate": "2026-12-02"
},
"createdAt": "2026-11-25T09:12:44Z",
"metadata": {}
}Cancel Pix charge
POST/api/payments/{paymentId}/cancelCancels one PENDING Pix Automático charge, until the day before its billingDate; after that, or for any other payment, Outpost returns 409 invalid_status. The payment becomes CANCELED, Outpost sends payment.canceled, and the authorisation stays ACTIVE. On a VARIABLE authorisation, to change the amount, cancel the charge, then create a new one for the same billingDate while it is at least 2 days away. The request has no body.
Request Headers
| Parameter | Type | Required | Description |
|---|---|---|---|
| Authorization | string | Yes | Bearer <access_token> |
| Idempotency-Key | string | Yes | Unique key for this request. See Conventions |
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| paymentId | string | Yes | Outpost payment ID (UUID) |
Response 200 OK
{
"id": "01a211fa-92e0-7952-800d-54bf6e80d923",
"merchantReference": "sub-1042-2026-12",
"status": "CANCELED",
"amount": { "amount": "49.90", "currency": "BRL" },
"paymentMethod": {
"type": "pixAutomatico",
"pixAuthorisationId": "01a19c91-4eb8-7231-b916-d081927e245a",
"billingDate": "2026-12-02"
},
"createdAt": "2026-11-25T09:12:44Z",
"canceledAt": "2026-11-28T16:40:02Z",
"metadata": {}
}Create refund
POST/api/payments/{paymentId}/refundsRefunds a captured payment in full or in part. Outpost issues the corresponding tax document. The refund starts as INITIATED; the result arrives as a refund.completed or refund.failed webhook. A refund doesn't change the payment: it stays CAPTURED. A payment can have several partial refunds; their total can't exceed the captured amount, or Outpost returns 400 invalid_state on amount.
Request Headers
| Parameter | Type | Required | Description |
|---|---|---|---|
| Authorization | string | Yes | Bearer <access_token> |
| Content-Type | string | Yes | application/json |
| Idempotency-Key | string | Yes | Unique key for this request. See Conventions |
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| paymentId | string | Yes | Payment to refund (UUID) |
Request Body Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| merchantReference | string | Yes | Your refund reference |
| amount | object | No | amount (decimal string) + currency. Omit to refund the remaining amount in full |
| reason | string | No | REQUESTED_BY_CUSTOMER, DUPLICATE, FRAUDULENT or OTHER. Returned on the refund; null when omitted |
Response 201 Created
{
"id": "01a18708-cb98-7f0f-8672-bf02c2e98dc0",
"paymentId": "01a182d1-82b8-7b18-bf89-08ff16b3fbfd",
"merchantReference": "refund-1042-1",
"status": "INITIATED",
"amount": { "amount": "120.99", "currency": "EUR" },
"reason": "REQUESTED_BY_CUSTOMER",
"createdAt": "2026-10-29T09:41:03Z"
}| Refund status | Meaning |
|---|---|
| INITIATED | Outpost accepted the refund |
| COMPLETED | The payment provider confirmed the refund. Final |
| FAILED | The payment provider could not complete the refund. Final; create a new refund to try again |
Code Example
curl -X POST \
"https://api.outpostanywhere.com/api/payments/$PAYMENT_ID/refunds" \
-H "Authorization: Bearer $OUTPOST_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"merchantReference": "refund-1042-1",
"amount": { "amount": "120.99", "currency": "EUR" },
"reason": "REQUESTED_BY_CUSTOMER"
}' | jqWebhooks
Register an endpoint for each merchant with POST /api/webhooks, using that merchant's access token, and subscribe to the events below. The signing secret is returned once on creation.
| Event | Sent when | Subscribe |
|---|---|---|
| payment.captured | The payment was authorised and captured | Required |
| payment.failed | The payment was declined, failed, or expired before the shopper completed it. data includes the failure object | Required |
| payment.canceled | You cancelled a PENDING Pix Automático charge. data is as for payment.failed, with canceledAt instead of failedAt and failure | Pix Automático only |
| pix_authorisation.approved | The shopper approved a Pix Automático authorisation. Example below | Pix Automático only |
| pix_authorisation.rejected | The shopper or the shopper's bank refused a Pix Automático authorisation | Pix Automático only |
| pix_authorisation.canceled | A Pix Automático authorisation was cancelled. data.canceledBy is MERCHANT (through this API) or SHOPPER (in their bank app) | Pix Automático only |
| pix_authorisation.expired | A Pix Automático authorisation reached endsAt, or the shopper did not approve it in time | Pix Automático only |
| refund.completed | The payment provider confirmed the refund | Required |
| refund.failed | The refund could not be completed | Required |
The required events are the ones a one-time payment and refund integration needs. In each event's data, paymentId, refundId and pixAuthorisationId are the id of the payment, refund or Pix authorisation. Events carry the key facts of what happened; fetch the payment with GET /api/payments/{paymentId} for anything else, such as networkTransactionId. Events don't name the merchant, so register a separate URL for each merchant to know which signing secret to verify with. Treat event IDs as opaque, and ignore data fields you don't use. payment.captured fires for every captured payment of the merchant, including ones it took outside this API: match on paymentId.
payment.captured
{
"id": "evt_payment_captured_01a182d1-8a88-7ac9-96a6-ca7202384964",
"type": "payment.captured",
"created": "2026-10-28T14:02:13Z",
"data": {
"paymentId": "01a182d1-82b8-7b18-bf89-08ff16b3fbfd",
"merchantReference": "order-1042",
"amount": { "amount": "120.99", "currency": "EUR" },
"capturedAt": "2026-10-28T14:02:12Z",
"metadata": {}
}
}payment.failed
data.failure has the same fields as on the payment. See Payment failures.
{
"id": "evt_payment_failed_01a1830f-b0b0-7a9b-a354-2ace229bfacf",
"type": "payment.failed",
"created": "2026-10-28T15:10:06Z",
"data": {
"paymentId": "01a1830f-a8e0-7448-bd72-c4d4d3dd8e1b",
"merchantReference": "order-1043",
"amount": { "amount": "120.99", "currency": "EUR" },
"failure": {
"code": "card_declined",
"message": "The card was declined by the issuer.",
"declineCode": "05",
"retryable": false
},
"failedAt": "2026-10-28T15:10:05Z",
"metadata": {}
}
}refund.completed
{
"id": "evt_refund_completed_01a1870a-e2c0-7752-8b1f-8515a0199bd6",
"type": "refund.completed",
"created": "2026-10-29T09:43:20Z",
"data": {
"refundId": "01a18708-cb98-7f0f-8672-bf02c2e98dc0",
"paymentId": "01a182d1-82b8-7b18-bf89-08ff16b3fbfd",
"merchantReference": "refund-1042-1",
"amount": { "amount": "120.99", "currency": "EUR" },
"reason": "REQUESTED_BY_CUSTOMER",
"completedAt": "2026-10-29T09:43:19Z"
}
}refund.failed
A refund's failure has a message only, with no code.
{
"id": "evt_refund_failed_01a1870a-e2c0-7e74-b454-db21ceca6dc7",
"type": "refund.failed",
"created": "2026-10-29T09:43:20Z",
"data": {
"refundId": "01a18708-cb98-7f0f-8672-bf02c2e98dc0",
"paymentId": "01a182d1-82b8-7b18-bf89-08ff16b3fbfd",
"merchantReference": "refund-1042-1",
"amount": { "amount": "120.99", "currency": "EUR" },
"reason": "REQUESTED_BY_CUSTOMER",
"failure": {
"message": "The payment provider declined the refund."
},
"failedAt": "2026-10-29T09:43:19Z"
}
}pix_authorisation.approved
pix_authorisation.rejected, .canceled and .expired carry the same data with that status; canceled also sets canceledAt and canceledBy (MERCHANT or SHOPPER).
{
"id": "evt_pix_authorisation_approved_01a19c94-8308-7465-99fd-bbefd4aea268",
"type": "pix_authorisation.approved",
"created": "2026-11-02T14:05:41Z",
"data": {
"pixAuthorisationId": "01a19c91-4eb8-7231-b916-d081927e245a",
"status": "ACTIVE",
"merchantCustomerReference": "CUST-7781",
"enrolmentPaymentId": "01a19c91-4eb8-7414-9330-f468f638178e",
"startsAt": "2026-11-02",
"frequency": "MONTHLY",
"approvedAt": "2026-11-02T14:05:40Z",
"canceledAt": null,
"canceledBy": null
}
}Delivery and retries
- Acknowledge a delivery with any 2xx status. Each attempt has 30 seconds to respond.
- A 429 or 5xx response is retried. Any other 4xx response is a permanent failure and stops delivery of that event.
- Retries use exponential backoff: at most 8 attempts, capped at 9 hours in total.
- Event ids are the same on every retry of the same event. Deduplicate on the full id.
Verifying signatures
Each request carries an Outpost-Signature header of the form t=<timestamp>,v1=<hmac>. t is a Unix timestamp in seconds; v1 is the hex-encoded HMAC-SHA256 of {t}.{raw body}, keyed with your signing secret (whsec_…) exactly as returned. Compare in constant time, and reject a request whose t is more than 5 minutes old. Always verify the signature before acting on a payload.
Payment failures
A FAILED payment carries a failure object, on the payment and in the payment.failed webhook.
| Field | Description |
|---|---|
| failure.code | Why the payment failed, from the list below |
| failure.message | Human-readable explanation. Not for display to the shopper |
| failure.declineCode | Raw issuer or provider code, for information only. Its format varies by provider. Omitted when the provider returns none |
| failure.retryable | Always false on Pix Automático charges: Outpost runs any retries itself under retryPolicy. Otherwise, true when a new payment with the same card may succeed: always for processing_error, and for card_declined or insufficient_funds when the issuer marks the decline as temporary. false otherwise |
| failure.code | Meaning |
|---|---|
| card_declined | The issuer declined the card without a more specific reason |
| insufficient_funds | The card or account has insufficient funds or credit |
| expired_card | The card has expired |
| incorrect_cvc | The CVC is incorrect |
| authentication_failed | The shopper failed or abandoned 3-D Secure, did not complete the bank redirect or Pix payment in time, or did not approve a Pix Automático enrolment before it expired |
| authentication_required | The issuer refused a merchant-initiated charge without the shopper authenticating. Ask the shopper to pay again with recurring.initiator CUSTOMER |
| authorisation_rejected | The shopper or the shopper's bank refused a Pix Automático enrolment |
| authorisation_canceled | The Pix Automático authorisation was cancelled before the day of the charge's billingDate, or before the shopper approved the enrolment |
| debit_canceled | The shopper cancelled this debit in their bank app after the pre-debit notice. The Pix Automático authorisation stays ACTIVE |
| authorisation_amount_exceeded | The charge is above the ceiling the shopper set in their bank app for a VARIABLE Pix Automático authorisation |
| fraud_suspected | The issuer or Outpost blocked the payment as suspected fraud |
| processing_error | A provider or network error prevented processing |
Payment status
| Status | Meaning |
|---|---|
| PENDING | Outpost has accepted the payment and is waiting for the bank. The result arrives by webhook on or after paymentMethod.billingDate, unless the charge or its authorisation is cancelled first. Pix Automático charges only |
| REQUIRES_ACTION | Waiting for the shopper: 3-D Secure, bank redirect or Pix QR code |
| CAPTURED | Authorised and captured. Final. A zero-amount card verification also ends CAPTURED, with nothing charged |
| CANCELED | You cancelled a PENDING Pix Automático charge. Final |
| FAILED | Declined, failed or expired. Final; create a new payment to retry. For a Pix Automático charge, create the next cycle's payment instead |
Error handling
All error responses follow a consistent structure with a category code and, for invalid requests, the fields at fault. A declined payment is not an error: it returns 201 with status FAILED.
| HTTP | Code | Description |
|---|---|---|
| 400 | invalid_argument | The request is invalid. See errors for the fields |
| 400 | invalid_idempotency_key | The Idempotency-Key header is blank or longer than 255 characters |
| 400 | invalid_state | The refund amount exceeds what remains refundable on the payment. errors names amount |
| 401 | - | Missing or invalid access token |
| 404 | not_found | Payment or Pix authorisation not found for this merchant |
| 409 | invalid_status | The payment or authorisation is not in a status that allows the operation, for example refunding a failed payment, charging a cancelled Pix Automático authorisation, or a second charge for the same billing cycle |
| 422 | idempotency_key_reused | The Idempotency-Key was already used for a different request body, so Outpost created nothing |
| 429 | rate_limited | Too many requests. Retry after the Retry-After header |
{
"code": "invalid_argument",
"errors": [{ "field": "customer.billingAddress.country", "message": "is required" }]
}