Transactions
A transaction is an instance of an action that requires a payment. Every charge, authorization, refund, and card verification on Payments AI is a transaction.
A transaction has the following characteristics:
- It includes an
amountand acurrency. - It has a
result(such asapproved,declined,canceled,abandoned, orunknown) and astatus(see Transaction statuses). - It is related to a specific merchant website and a customer.
- It links to a specific payment instrument, such as the card, bank account, or wallet being charged.
- It can connect to another transaction. For example, a refund references the specific sale it reverses.
HTTP 201 does not mean logical success:
POST /transactionsreturns a201 Createdstatus code whenever the transaction record is successfully created on the PaymentsAI platform. This includes declined payments. A 201 status code indicates that the request was accepted, not that the customer was successfully charged.Always check the
resultandstatusfields in the response body before treating a transaction as successful. A response containingresult: "declined"orstatus: "not-sent"returns a 201 status code but represents a logical failure.
A transaction's financial state is immutable in the public API:
PATCH /transactions/{id}updates only themetadatafield. The financial state of a transaction — including itsamount,result, andstatus— cannot be modified via the API once the record is created. Corrections to that state, such as marking an offsite payment as completed, must be handled directly within the PaymentsAI panel. See Updating transaction metadata and Updating transactions via the dashboard.
Transaction types
The type value you specify on POST /transactions determines the action taken:
| Type | What it does |
|---|---|
sale | Authorizes and captures funds in a single step. The customer is charged immediately. |
authorize | Reserves funds without capturing them. You can capture these funds later using a separate sale action. See Authorize and capture. |
The response field Transaction.type can return any of the following values: 3ds-authentication, authorize, capture, credit, refund, sale, or void. See Transaction statuses for the definition of each type. System-generated types appear automatically when secondary actions occur. For example, the refund type appears when you call the refund endpoint.
Creating a transaction
curl -X POST \
"https://staging-api.payments.ai/v1/public-api/organizations/${ORGANIZATION_ID}/transactions" \
-H 'Content-Type: application/json' \
-H "Authorization: ApiKey ${API_KEY}" \
-d '{
"type": "sale",
"customerId": "Customer ID Here",
"currency": "USD",
"amount": 10,
"paymentInstruction": { "paymentInstrumentId": "PaymentInstrumentID Here" }
}'
paymentInstruction
The paymentInstruction object defines what asset to charge. It accepts one of two structures:
{ "token": "<token>" }: A fresh tokenization token used for a one-off charge that is not tied to a saved instrument. See Token lifecycle.{ "paymentInstrumentId": "<id>" }: A payment instrument ID that is already attached to a customer profile. See Attach a token to a customer.
Customer-initiated vs. merchant-initiated transactions
The isMerchantInitiated flag indicates whether the customer is present during the transaction sequence:
| Value | Definition |
|---|---|
true | Merchant-initiated transaction (MIT): A recurring charge or renewal executed without the customer present, utilizing a stored credential-on-file. |
false | Customer-initiated transaction (CIT): The customer is actively present at the checkout interface. |
null (default) | PaymentsAI infers the classification from context. For example, a subscription renewal is automatically treated as merchant-initiated. |
This flag manages credential-on-file handling, network token usage, and Strong Customer Authentication (SCA) / 3DS exemption logic. Merchant-initiated transactions are typically out of scope for SCA requirements.
API Reference
Request fields
| Field | Required | Notes |
|---|---|---|
type | Yes | Use sale or authorize. |
customerId | Yes | The ID of the customer being charged. Maximum 50 characters. |
currency | Yes | The ISO currency code (for example, USD). |
amount | Yes | The transaction amount. |
paymentInstruction | Yes | Provide either { token } or { paymentInstrumentId }. |
redirectUrl | Conditional | Required when 3DS may apply. Specifies where the customer is redirected after completing an offsite step, such as a 3DS challenge. Maximum 1024 characters. See 3DS2 guide. |
idempotencyKey | Recommended | Deduplicates retried requests. Maximum 100 characters. |
metadata | Optional | A free-form key-value object for custom data tracking. |
isMerchantInitiated | Optional | MIT/CIT flag tracking customer presence. |
billingAddress | Optional | The billing address for the transaction. The street address field name is address (unlike the customer endpoint, which uses address1). |
Response fields
The response returns a standard Transaction object containing these key fields:
| Field | Meaning |
|---|---|
id | The unique transaction ID. |
amount | The original transaction amount. |
refundAmount | The total amount already refunded (returns null if no refunds have occurred). |
refundableAmount | The remaining balance available for refund actions. |
currency | The ISO currency code. |
status | See Transaction statuses. |
result | See Transaction statuses. |
combinedStatus | A merged representation of status and result (supports 13 distinct values). |
type | The transaction type (sale, authorize, capture, refund, credit, void, 3ds-authentication). |
paymentType | Returns one-time-payment or subscription-payment. |
paymentInstrument | A historical data snapshot of the payment instrument captured at the moment of processing. |
subscriptionId | The originating subscription ID. This field populates only if the transaction was generated automatically by a subscription engine. |
gatewayName / gatewaySlug | The gateway that processed the transaction. |
permissionBundle.isRefundable | Returns true if the transaction can currently accept a refund request. |
isProcessedOutside | Returns true if the transaction state was modified manually outside gateway interaction. |
paymentType: Subscription vs. one-off
The paymentType field indicates whether the transaction originated from an automated subscription or a standard one-off payment:
subscription-payment: Generated by an automated subscription renewal. ThesubscriptionIdfield populates with the matching reference ID.one-time-payment: A distinct, one-off charge originating from a singlePOST /transactionscall or a single order event.
Use paymentType to organize UI groupings ("recurring" vs. "one-off") and clean up reporting metrics. Use subscriptionId to link a transaction back to its parent subscription profile.
paymentInstrument is a historical snapshot
The paymentInstrument object nested within a transaction response is a static snapshot captured at the moment of transaction execution. It does not act as a live reference. While the card brand and the last four digits remain constant, fields like expireDate can drift if a customer updates their stored payment profile later on.
- Use
Transaction.paymentInstrumentfor receipts, invoices, and historical ledger displays to reflect what was actually charged. - Use
GET /payment-instruments/{Transaction.paymentInstrument.id}to verify the live state of the instrument, including current expiration data and active status.
Filtering transactions
GET /transactions supports query parameters for complex searching and ledger filtering:
| Parameter | Type | Example |
|---|---|---|
combinedStatuses | array | ?combinedStatuses=completed,refunded |
paymentMethods | array | ?paymentMethods=payment-card,paypal |
paymentType | enum | ?paymentType=subscription-payment |
gateways | array | ?gateways=stripe,paypal |
currencies | array | ?currencies=USD,EUR |
dateFrom / dateTo | date-time | ?dateFrom=2026-01-01T00:00:00Z&dateTo=2026-01-31T23:59:59Z |
amountMin / amountMax | number | ?amountMin=10&amountMax=100 |
customerId | string | ?customerId=<id> |
subscriptionId | string | ?subscriptionId=<id> |
search | string | ?search=John |
limit / offset | integer | ?limit=20&offset=40 |
sortBy / sortDirection | string | ?sortBy=createdAt&sortDirection=desc |
Filter examples
All completed transactions in January 2026, sorted by descending creation date:
GET /transactions?combinedStatuses=completed&dateFrom=2026-01-01T00:00:00Z&dateTo=2026-01-31T23:59:59Z&sortBy=createdAt&sortDirection=desc
All transactions associated with a single customer ID:
GET /transactions?customerId=<customerId>&sortBy=createdAt&sortDirection=desc
All fully or partially refunded transactions with an amount over $50:
GET /transactions?combinedStatuses=refunded&amountMin=50
All recurring transactions tied to a specific subscription record:
GET /transactions?paymentType=subscription-payment&subscriptionId=<subscriptionId>
All Stripe transactions processed during May 2026:
GET /transactions?gateways=stripe&dateFrom=2026-05-01T00:00:00Z
Supported gateways
The gateways parameter accepts default, paypal, klarna, coinbase, nmi, and stripe. See Gateways.
Supported payment methods
The paymentMethods parameter accepts an enum covering cards, ACH transfers, digital wallets, local payment options, and cryptocurrencies. Common values include:
| Value | Payment Method |
|---|---|
payment-card | Credit and debit cards |
ach | ACH bank transfer (US) |
paypal | PayPal |
Apple Pay | Apple Pay |
GooglePay | Google Pay |
Klarna | Klarna |
bitcoin / cryptocurrency | Cryptocurrency payments routed via the Coinbase gateway |
bank-transfer | Generic bank transfers |
For the complete list of roughly 120 regional payment types (such as PIX, WeChat Pay, Trustly, or MuchBetter), see the full GET /transactions API reference documentation.
Updating transaction metadata
PATCH /transactions/{id} updates the metadata field on an existing transaction. This is the only mutable field on a transaction in the public API — the financial state (amount, result, status, and so on) cannot be changed.
curl -X PATCH \
"https://staging-api.payments.ai/v1/public-api/organizations/${ORGANIZATION_ID}/transactions/${TRANSACTION_ID}" \
-H 'Content-Type: application/json' \
-H "Authorization: ApiKey ${API_KEY}" \
-d '{
"metadata": { "internalRef": "INV-2026-0042", "reconciled": true }
}'
Only the metadata field can be updated this way; all other fields on the request are ignored.
Updating transactions via the dashboard
The public API does not expose endpoints to modify a transaction's financial state. Account operators can update a transaction's result field via the administrative panel under specific conditions (such as logging an offline settlement). This capability is restricted to the user interface. When an off-platform correction occurs, the transaction's isProcessedOutside flag updates to true.
Webhooks
PaymentsAI issues two distinct webhook notifications for transaction lifecycles:
transaction-processed: Sent as soon as a gateway completes transaction execution. This represents the primary integration hook for successful payments.transaction-declined: Sent if a gateway declines the transaction. For automated subscription collection, this notification triggers on every consecutive billing retry.
Pass these identifiers inside the eventTypes array when registering endpoints. See Subscription webhooks for details on payload shapes and Webhook setup to review the registration workflow.