Pre-auth API documentation

Overview

ℹ  NOTE

The API does not create authorizations from scratch via external calls — pre-auths originate from the Paystand checkout flow. Capture and void operations are explicitly merchant-initiated; no automatic retries are performed. All responses are synchronous.

While a pre-auth is active, Paystand blocks all additional payment attempts against the associated ERP document. Only captures from the existing authorization are allowed until it is fully captured, voided, or expired.

Authentication

All endpoints require an OAuth2 Bearer token and a customer scoping header on every request.

  • Authorization: Bearer <access_token> (Please contact your implementations manager to share the access token with you)
  • X-CUSTOMER-ID: <paystand_customer_id> (This can be retrieved from the paystand dashboard under the integrations tab in the API Configuration Values section)

 

⚠  IMPORTANT

X-CUSTOMER-ID is required on every request. This is Paystand's internal customer ID, you can find it in your Paystand Dashboard. A pre-auth belonging to a different customer returns 404 — it is not distinguishable from a record that does not exist.

 

 

Endpoints

Create Pre-Authorization

POST/preAuths

Creates a new pre-authorization against an existing saved card. Pre-auths are normally created through the Paystand checkout flow — use this endpoint for programmatic or integration-initiated authorizations.

ℹ  NOTE

The creation response returns receivables as a raw JSON string. Call GET /preAuths/:id after creation to retrieve the enriched receivables array with per-invoice amounts, captured totals, expiration date, and invoice keys needed for subsequent captures.

Request Body

FieldTypeRequiredDescription
amountnumberYesAmount to authorize. Must be greater than 0.
currencystringYesCurrency code, e.g. USD
cardIdstringYesPaystand saved card ID. Raw processor token strings are not accepted.
expiresAtstringOptionalISO 8601 expiry date. Defaults to 7 days from creation if omitted. Up to 30 days for certain MCC categories.
receivablesarrayOptionalArray of Paystand receivable/invoice IDs to link this pre-auth to.
idempotencyKeystringOptionalClient-supplied key to prevent duplicate pre-auth creation on retry. Scoped to this endpoint only.

Example Request

{

  "amount": 1000.00,

  "currency": "USD",

  "cardId": "crd_abc123",

  "idempotencyKey": "my-system-ref-7890",

  "expiresAt": "2026-04-01T00:00:00Z"

}

Response — 200 Success

{

  "id": "pa_987654",

  "amount": 1000.00,

  "currency": "USD",

  "status": "authorized",

  "amountCaptured": 0,

  "expiresAt": "2026-04-01T00:00:00Z",

  "authorizedAt": "2026-03-18T10:00:00Z",

  // Call GET /preAuths/:id for enriched receivables data

  "receivables": "[{\"id\":\"inv_001\",\"amountToPay\":\"600.00\"}]"

}

Error — 409 Duplicate Pre-Auth

{

  "error": {

    "code": "validationError",

    "explanation": "A pre-authorization already exists for one or more

     of the selected receivables."

  }

}

 

Capture Pre-Authorization

POST/preAuths/:id/capture

Triggers fund settlement against an existing pre-authorization. Supports full captures, partial captures, and multiple sequential captures until the authorized balance is fully consumed.

Option A — ERP / Invoice Capture (receivables-based)

Use when the pre-auth was created against one or more Paystand receivables. Pass the receivable IDs — the capture amount is derived automatically from the amountToPay frozen at pre-auth creation time. Fee splits are recalculated proportionally.

FieldTypeRequiredDescription
receivablesarrayYesArray of receivable IDs to capture against. Pass plain ID strings or { "id": "..." } objects.

Full capture — all linked invoices:

{ "receivables": ["inv_001", "inv_002"] }

Partial capture — one of two linked invoices:

{ "receivables": ["inv_001"] }

Option B — Direct / Amount-based Capture

Use when the pre-auth has no linked receivables, or when you need to capture an explicit dollar amount regardless of invoice breakdown.

FieldTypeRequiredDescription
amountnumberYesAmount to capture. Must be greater than 0 and less than or equal to the remaining authorized balance.

Partial capture:

{ "amount": 500.00 }

Full capture — omit amount to capture full remaining balance:

{}

Response — 200 Success

{

  "preAuth": {

    "id": "pa_987654",

    "status": "partially_captured",

    "amount": 1000.00,

    "amountCaptured": 500.00,

    "currency": "USD",

    "expiresAt": "2026-04-01T00:00:00Z"

  },

  "payment": {

    "id": "pay_11223344"

  }

}

Status After Capture

ScenariopreAuth.status
Captured amount < authorized amountpartially_captured
Captured amount = authorized amountcaptured

Validation Errors — 400

ConditionError
Amount ≤ 0 or > remaining balancecapture_amount must be > 0 and ≤ remaining balance
Status is not authorized, pending, or partially_capturedPreAuth can only be captured when status is authorized, pending, or partially captured
Pre-auth has expiredPreAuth has expired` — status also updated to expire
No remaining balancePreAuth has no remaining amount to capture
Pre-auth not found or belongs to different customer404 NOT_FOUND
X-CUSTOMER-ID header absent400 validationError: Customer context is required

Processor Errors — 400

ScenarioBehavior
Stripe: provider hold released or amount mismatchPre-auth marked expired. Capture failed: the authorized amount at the payment provider does not match the expected capture amount.
Stripe: other processor failureGeneric providerFailureError — raw provider message is not surfaced.
Vantiv: processor failureProvider error surfaced directly.

✕  WARNING

On any processor failure, the pre-auth status and amountCaptured are not modified. No payment record is created and no ERP record is posted.

⚠  IMPORTANT

The capture endpoint does not currently support a per-capture idempotency key. A duplicate POST while the pre-auth is in partially_captured state will re-execute. For full captures, the second call will be rejected because the status will already be captured.

 

Void Pre-Authorization

POST/preAuths/:id/void

Cancels the authorization at the payment provider and releases any remaining hold on the payer's card. No payment record is created and no GL impact occurs. Voiding is significantly cheaper than issuing a refund.

No request body is required.

Response — 200 Success

{

  "id": "pa_987654",

  "status": "voided",

  "amount": 1000.00,

  "amountCaptured": 0,

  "currency": "USD"

}

Void Behavior by Current Status

Current statusBehavior
authorized / pendingProvider cancel called → status set to voided
partially_capturedProvider cancel called (Stripe: capture with amount_to_capture: 0) → status set to voided
voidedNo-op — returns current record as-is (idempotent)
expiredNo-op — returns current record as-is (idempotent)
capturedRejected — Cannot void an already fully captured pre-auth (400)

List Pre-Authorizations

GET/preAuths

Returns an array of PreAuth objects scoped to the authenticated customer. Accepts a standard LoopBack filter object via ?f=.... Supports where, limit, offset, and order.

Get Pre-Authorization

GET/preAuths/:id

Returns the fully enriched PreAuth object — including the resolved receivables array, expiration date, payer details, captured amounts, and full payment history. Use this after creation to get enriched data.

Response — 200 Success

{

  "id": "pa_987654",

  "amount": 1000.00,

  "currency": "USD",

  "status": "partially_captured",

  "amountCaptured": 600.00,

  "expiresAt": "2026-04-01T00:00:00Z",

  "authorizedAt": "2026-03-18T10:00:00Z",

  "hasLinkedReceivables": true,

  "payerDisplayName": "Acme Corp",

  "payerEmail": "billing@acme.com",

  "receivables": [

    {

      "id": "inv_001",

      "amountToPay": "600.00",

      "amountRemaining": 0.00,

      "amountCaptured": 600.00,

      "invoiceKey": "INV-2026-001",

      "status": "captured"

    },

    {

      "id": "inv_002",

      "amountToPay": "400.00",

      "amountRemaining": 400.00,

      "amountCaptured": 0,

      "invoiceKey": "INV-2026-002",

      "status": "open"

    }

  ],

  "capturedPayments": [

    {

      "id": "pay_11223344",

      "amount": 600.00,

      "status": "posted",

      "datePaid": "2026-03-18T12:00:00Z",

      "currency": "USD"

    }

  ]

}

Receivable Status Values

StatusMeaning
capturedamountCaptured >= amountToPay — fully settled
releasedPre-auth was voided before this receivable was captured
other valuesReflects the underlying Paystand Receivable status, e.g. open, paid

 

PreAuth Object Schema

FieldTypeDescription
idstringUnique pre-auth identifier
amountnumberOriginally authorized amount
currencystringCurrency code
statusstringSee Status Values section below
amountCapturednumberTotal captured to date — accumulates across partial captures
expiresAtstring (ISO 8601)When the authorization expires. Visible in the Paystand Dashboard and returned via GET /preAuths/:id.
authorizedAtstring (ISO 8601)When the provider confirmed the hold
cardIdstringPaystand saved card ID used for the authorization
providerstringPayment processor: stripe or vantiv
receivablesarrayLinked receivables with id, amountToPay, currency, invoiceKey. The amountToPay is frozen at creation time and drives Option A capture amounts.
capturedPaymentIdsstringAll payment IDs from all captures against this pre-auth
idempotencyKeystringClient key supplied at creation time — prevents duplicate auth creation on retry
metadataobjectArbitrary extra data

Status Values

StatusDescription
pendingCreated — provider authorization is in flight
authorizedProvider hold active. No capture yet. Funds are reserved. Expiration date is set.
partially_capturedOne or more partial captures completed. Remaining balance still available. Authorization remains open.
capturedFully captured. No remaining balance. Pre-auth is closed.
voidedAuthorization cancelled at the provider. Hold released. No funds moved.
expiredExpiry date passed or provider hold released. A new authorization must be created.

 

 

ℹ  NOTE

While a pre-auth is in an active status (authorized, pending, partially_captured), Paystand blocks all additional payment attempts against the associated ERP document from any other payment source. Payment capability is restored once the authorization is fully captured, voided, or expired.

Was this article helpful?
0 out of 0 found this helpful