Skip to main content

Direct payments

A direct payment creates a one-time payment in a single, merchant-initiated call. Unlike a hosted checkout session, you supply the amount, currency, country, and payment_method yourself rather than handing the whole flow to Orchestr.

The payment is completed on a provider-hosted page, so payment details never touch your servers. (Paying by card without a redirect — collecting the card on your own page — is its own flow: see Card payments.) A successful POST /v1/payments returns one of:

  • status: requires_action — redirect the customer to next_action.redirect_url to finish paying.
  • status: completed — the payment settled immediately.
  • status: failed — the payment was declined or errored.

When to use a direct payment

Use a direct payment when…Use a checkout session when…
You already know the amount, currency, country, and payment method and want a single server-to-server call.You want Orchestr to host the entire payment page and collect customer/payment details for you.
You manage your own return-URL redirect.You want line items, address/phone collection, and locale handling out of the box.

Both flows share the same providers and settlement — the resulting order surfaces with subtype: direct_payment on the Orders and Transactions endpoints.

1. Create a payment

This POST /v1/payments call reuses the buildSignatureHeader helper from the Signing guide (the signed string for a request is timestamp + path + body). It assumes you've exported ORCHESTR_SECRET_KEY and ORCHESTR_SIGNING_SECRET as shown in Getting started.

REQ_PATH="/v1/payments"
BODY='{"amount":"42.00","currency":"GBP","country":"GB","payment_method":{"code":"paypal"},"merchant_reference":"order-1001","success_url":"https://shop.example.com/ok","cancel_url":"https://shop.example.com/cancel","customer":{"email":"jane@example.com"}}'
TS=$(date +%s)
SIG=$(printf '%s' "${TS}${REQ_PATH}${BODY}" \
| openssl dgst -sha256 -hmac "$ORCHESTR_SIGNING_SECRET" | sed 's/^.*= //')

curl -sS -X POST "https://api.sandbox.upprove.com${REQ_PATH}" \
-H "Authorization: Bearer $ORCHESTR_SECRET_KEY" \
-H "X-Signature: t=${TS}, v1=${SIG}" \
-H "Content-Type: application/json" \
--data-raw "$BODY"

The required fields are amount, currency, country, payment_method, merchant_reference, success_url, and cancel_url. merchant_reference must be unique per account and doubles as your idempotency key — retrying with the same reference will not create a duplicate.

:::note LATAM local methods require the customer's identity document

For PIX, BOLETO, SPEI, OXXO and PSE, pass the paying customer's national identity document in payment_method.details.document_id — the CPF in Brazil (11 digits, punctuation optional), CURP or RFC in Mexico, cedula in Colombia (6–10 digits). The payment is rejected with a validation error when it is missing or malformed for the method's country.

"payment_method": {"code": "pix", "details": {"document_id": "123.456.789-01"}}

:::

2. Read the response

A 200 OK returns the payment. The X-Signature response header signs the body — verify it before trusting the response (see Signing).

Most payments come back requires_action — redirect the customer to next_action.redirect_url:

{
"order_id": "ord_5b4a3c2d",
"transaction_id": "txn_9f8e7d6c",
"status": "requires_action",
"amount": 42.00,
"currency": "GBP",
"next_action": {
"type": "redirect",
"redirect_url": "https://pay.provider.example/session/abc123"
}
}

For a payment that settles immediately, status is completed, next_action is null, and provider_transaction_id carries the settlement reference:

{
"order_id": "ord_5b4a3c2d",
"transaction_id": "txn_9f8e7d6c",
"status": "completed",
"amount": 42.00,
"currency": "GBP",
"provider_transaction_id": "pi_3PqRsT2eZvKYlo2C1aBcD3eF",
"next_action": null
}
FieldDescription
order_idThe order created for this payment.
transaction_idThe payment transaction attempt.
statusrequires_action, completed, or failed. A card charge can also return authorized (a manual-capture hold), settling, or canceled.
amount / currencyThe payment amount and currency.
provider_transaction_idSettlement/charge reference; null before settlement.
additional_identifiersExtra provider-side identifiers, each { "identifier": …, "type": "checkout" | "order" }.
next_actionPresent when status is requires_action; null on terminal outcomes.

3. Handle the outcome

The create response tells you the initial state; the final outcome arrives asynchronously via the payment.* webhooks (payment.succeeded, payment.failed, payment.requires_action, …). Fulfil the order on payment.succeeded.

Direct-payment declines are terminal

Unlike a checkout session, a declined direct payment has no retry surface — the payment does not reopen for another attempt. To try again, create a new payment with a new merchant_reference. Inspect the decline code on the failed transaction to decide whether retrying is worthwhile.

Next steps

  • Signing — build and verify the X-Signature header.
  • Webhooks — the payment.* events that report the final outcome.
  • Decline codes — interpret failed payments.
  • The full API Reference for POST /v1/payments.