Skip to main content

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 amount and a currency.
  • It has a result (such as approved, declined, canceled, abandoned, or unknown) and a status (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 /transactions returns a 201 Created status 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 result and status fields in the response body before treating a transaction as successful. A response containing result: "declined" or status: "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 the metadata field. The financial state of a transaction — including its amount, result, and status — 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:

TypeWhat it does
saleAuthorizes and captures funds in a single step. The customer is charged immediately.
authorizeReserves 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:

ValueDefinition
trueMerchant-initiated transaction (MIT): A recurring charge or renewal executed without the customer present, utilizing a stored credential-on-file.
falseCustomer-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

FieldRequiredNotes
typeYesUse sale or authorize.
customerIdYesThe ID of the customer being charged. Maximum 50 characters.
currencyYesThe ISO currency code (for example, USD).
amountYesThe transaction amount.
paymentInstructionYesProvide either { token } or { paymentInstrumentId }.
redirectUrlConditionalRequired 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.
idempotencyKeyRecommendedDeduplicates retried requests. Maximum 100 characters.
metadataOptionalA free-form key-value object for custom data tracking.
isMerchantInitiatedOptionalMIT/CIT flag tracking customer presence.
billingAddressOptionalThe 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:

FieldMeaning
idThe unique transaction ID.
amountThe original transaction amount.
refundAmountThe total amount already refunded (returns null if no refunds have occurred).
refundableAmountThe remaining balance available for refund actions.
currencyThe ISO currency code.
statusSee Transaction statuses.
resultSee Transaction statuses.
combinedStatusA merged representation of status and result (supports 13 distinct values).
typeThe transaction type (sale, authorize, capture, refund, credit, void, 3ds-authentication).
paymentTypeReturns one-time-payment or subscription-payment.
paymentInstrumentA historical data snapshot of the payment instrument captured at the moment of processing.
subscriptionIdThe originating subscription ID. This field populates only if the transaction was generated automatically by a subscription engine.
gatewayName / gatewaySlugThe gateway that processed the transaction.
permissionBundle.isRefundableReturns true if the transaction can currently accept a refund request.
isProcessedOutsideReturns 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. The subscriptionId field populates with the matching reference ID.
  • one-time-payment: A distinct, one-off charge originating from a single POST /transactions call 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.paymentInstrument for 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:

ParameterTypeExample
combinedStatusesarray?combinedStatuses=completed,refunded
paymentMethodsarray?paymentMethods=payment-card,paypal
paymentTypeenum?paymentType=subscription-payment
gatewaysarray?gateways=stripe,paypal
currenciesarray?currencies=USD,EUR
dateFrom / dateTodate-time?dateFrom=2026-01-01T00:00:00Z&dateTo=2026-01-31T23:59:59Z
amountMin / amountMaxnumber?amountMin=10&amountMax=100
customerIdstring?customerId=<id>
subscriptionIdstring?subscriptionId=<id>
searchstring?search=John
limit / offsetinteger?limit=20&offset=40
sortBy / sortDirectionstring?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:

ValuePayment Method
payment-cardCredit and debit cards
achACH bank transfer (US)
paypalPayPal
Apple PayApple Pay
GooglePayGoogle Pay
KlarnaKlarna
bitcoin / cryptocurrencyCryptocurrency payments routed via the Coinbase gateway
bank-transferGeneric 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.