Skip to content

Processing payments

The direct payment flow has three phases: tokenize card data in the browser (so it never touches your servers), validate the payment to get the exact convenience fee, then capture it.

If you want a complete UI instead of raw API calls, use hosted sessions — same engine, none of the plumbing below.

Fetch short-lived processor credentials (anonymous endpoint, rate-limited, scoped by the account header):

GET /api/paymentaccounts/{uid}/client-config
{
"processor": "zift",
"config": {
"account_id": "",
"api_key": "",
"temporary_password": "",
"expiration_date": "2026-06-11T18:30:00Z"
},
"supported_methods": ["credit", "ach", "apple_pay"]
}

Feed this to @caselle/payment-sdk’s ZiftPaymentSDK to proxynize the card: the SDK swaps the real PAN for a token (the fingerprint) valid ~15 minutes. Your server only ever sees the fingerprint.

Create the payment without capturing — this validates the method and returns the authoritative convenience fee:

POST /api/payments
X-Payment-Account-Uid: {uid}
{
"base_amount": 12345,
"tax_amount": 0,
"currency": "USD",
"reference_id": "fee-check-7f3a…",
"payment_method": {
"payment_method_type": "credit",
"credit": {
"fingerprint": "{proxynized_token}",
"last4": "4242",
"exp_month": 12,
"exp_year": 2027,
"bin": "411111",
"holder_name": "Alex Morales"
}
}
}

ACH uses "payment_method_type": "ach" with an ach object (routing number, account suffix, account type); saved methods use "wallet_credit" / "wallet_ach" with "wallet": { "saved_payment_method_uid": "…" }.

{
"uid": "pay_…",
"processing_fee_amount": 99,
"total_amount": 12444,
"payment_method": { "…": "sanitized echo" }
}

Show processing_fee_amount / total_amount to the customer. Never compute fees yourself — the engine that charges them quotes them.

Once the customer confirms, capture using the validation’s uid, repeating the exact validated payment method and fee amounts:

POST /api/payments/{uid}/capture
{
"base_amount": 12345,
"tax_amount": 0,
"currency": "USD",
"reference_id": "{yourPaymentReference}",
"payment_method": { "…": "same as validation" },
"processing_fee_amount": 99,
"total_amount": 12444
}

The response uid is your transaction reference. Then confirm asynchronously via the payment.completed / payment.failed webhooks — captures settle through the processor.

  • POST /api/payments/{uid}/refund — full or partial refund.
  • POST /api/payments/record-external — record a payment taken outside the platform so reporting stays complete.
  • GET /api/payments, GET /api/transactions — OData-queryable history.