Quickstart
From a fresh Partner account to a verified sandbox payment, in four steps.
Create a hosted-page session, have the payer pay on that page with a sandbox card, then read the resulting transaction back. Every example here uses the sandbox host.
What you need
A sandbox API key from the Partner Portal, sent as
Authorization: Bearer csk_ab12cd34_xxxxxxxxxxxxxxxxxxxxxxxx on every request. The key
carries no environment marker — the host selects the environment. Sandbox is
https://api.sandbox.cresoracommerce.ai/api/v1, production is
https://api.cresoracommerce.ai/api/v1.
A sandbox merchant id, from GET /merchants or the merchant's page in the Portal.
Merchant ids are UUIDs like 0190a1b2-c3d4-7e5f-8901-23456789abcd — there is no prefix.
Every POST requires an Idempotency-Key header, sandbox included: one fresh key per
logical request, idem_$(uuidgen). A retry with the same key returns the first result,
not a second charge.
1. Create the hosted-page session
Three fields — the merchant, the amount as a decimal string, and the currency.
curl -X POST https://api.sandbox.cresoracommerce.ai/api/v1/hpp/sessions \
-H "Authorization: Bearer csk_ab12cd34_xxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Idempotency-Key: idem_$(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"merchant_id": "0190a1b2-c3d4-7e5f-8901-23456789abcd",
"amount": "10.00", "currency": "USD"}'import os, uuid, requests
BASE = "https://api.sandbox.cresoracommerce.ai/api/v1"
resp = requests.post(
f"{BASE}/hpp/sessions",
headers={"Authorization": f"Bearer {os.environ['CRESORA_API_KEY']}",
"Idempotency-Key": f"idem_{uuid.uuid4()}"},
json={"merchant_id": "0190a1b2-c3d4-7e5f-8901-23456789abcd",
"amount": "10.00", "currency": "USD"},
)
session = resp.json() # session["state"], session["hpp_url"]const BASE = "https://api.sandbox.cresoracommerce.ai/api/v1";
const res = await fetch(`${BASE}/hpp/sessions`, {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.CRESORA_API_KEY}`,
"Idempotency-Key": `idem_${crypto.randomUUID()}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ merchant_id: "0190a1b2-c3d4-7e5f-8901-23456789abcd",
amount: "10.00", currency: "USD" }),
});
const session = await res.json(); // session.state, session.hpp_url200, a session nobody has paid yet. Keep id — you poll on it — and send the payer to
hpp_url exactly as returned:
{ "id": "0190a1c4-5e6f-7a8b-9c0d-1e2f3a4b5c6d", "state": "PENDING",
"hpp_url": "<absolute URL of the hosted page>",
"expires_at": "2026-08-12T14:47:07Z" }2. Pay on the hosted page
Open hpp_url in a browser and pay there. Card 4012000098765439, expiry 12/28,
CVV 999, amount left at $10.00 approves. In sandbox the cents portion of the amount
drives the decline scenarios and .00 approves; CVV 999 approves, 111 declines.
Card data is entered on the hosted page and never sent to the Cresora API. A raw card
number posted to the API is rejected with 400.
3. Confirm the outcome
Webhooks are the primary path. A completed payment delivers transaction.captured.
The type field is event_type, and business fields live under data:
{
"envelope_version": 1,
"event_id": "0190a1e6-7081-7c9d-8e0f-3a4b5c6d7e8f",
"event_type": "transaction.captured",
"occurred_at": "2026-08-12T14:32:09Z",
"partner_id": "0190a190-2b3c-7d4e-8f50-6a7b8c9d0e1f",
"idempotency_key": "evt_0190a1e6-7081-7c9d-8e0f-3a4b5c6d7e8f",
"data": { "transaction_id": "0190a1d5-6f70-7b8c-9d0e-2f3a4b5c6d7e",
"state": "CAPTURED", "amount": "10.00" }
}Polling is the fallback. GET /hpp/sessions/{id} returns the session state, and a
transaction_id once that state reads COMPLETED — then read the transaction:
BASE=https://api.sandbox.cresoracommerce.ai/api/v1
AUTH="Authorization: Bearer csk_ab12cd34_xxxxxxxxxxxxxxxxxxxxxxxx"
curl "$BASE/hpp/sessions/$SESSION_ID" -H "$AUTH"
curl "$BASE/transactions/$TRANSACTION_ID" -H "$AUTH"{
"transaction_id": "0190a1d5-6f70-7b8c-9d0e-2f3a4b5c6d7e",
"type": "SALE", "state": "CAPTURED", "amount": "10.00",
"surcharge_amount": "0.00", "convenience_fee_amount": "0.00", "tax_amount": "0.00"
}entry_mode is returned alongside these. States are UPPERCASE, and a decline is still
200 — state reads FAILED with a decline_code.
Errors you may hit
| Code | When |
|---|---|
unauthorized | Key missing, malformed, or wrong for this host. |
merchant_not_found | The merchant_id is unknown to your Partner. |
idempotency_key_reused | Same key reused with a different body (422). |
What to build next
- Hosted Payment Page — iframe versus redirect, expiry, and auth-only via
capture_mode: "authorize". There is no manual-capture field onPOST /transactions;type: "AUTHORIZATION"there returns501. - Tokenization — save a card during the hosted-page flow, then
charge it with a
SALEcarryingvault_token+use_type, per Direct API. - Webhook setup — endpoints, signatures, retries.