Three calls and a webhook.
Gateway is a hosted checkout, so the integration is deliberately small: create an order, send the customer to the page, verify the signed result. Everything below is the whole surface — the payment UI, the method logic, 3-D Secure, wallets, and receipts are ours to build and keep current.
What you're integrating against.
- REST over HTTPS
- JSON in, JSON out
- Bearer API keys
- Idempotency keys
- Signed webhooks
- Replay protection
- Test and live modes
- iOS & Android SDKs
- Store plugins
- Embedded fields
From nothing to a paid order.
The whole happy path. Amounts are in minor units, references are yours, and the checkout URL is what you redirect the customer to. The API base URL is issued with your sandbox keys — export it as PROTOCORE_API_BASE and the calls below run exactly as written.
Create the order
One call with the amount, the currency, and your own reference. The idempotency key is yours to generate — a retried request returns the original order rather than creating a second one.
curl -X POST "$PROTOCORE_API_BASE/v1/orders" \
-H "Authorization: Bearer $PROTOCORE_API_KEY" \
-H "Idempotency-Key: 9F21-0716" \
-H "Content-Type: application/json" \
-d '{
"amount": 4900,
"currency": "EUR",
"reference": "9F21-0716",
"line_items": [
{ "name": "Brand identity sprint", "amount": 3850 },
{ "name": "Typeface licensing", "amount": 600 },
{ "name": "Rush delivery", "amount": 400 }
],
"return_url": "https://arcstudio.ro/thanks"
}'Send the customer to the checkout
The response carries a checkout URL on your own checkout host — the one issued with your sandbox, or your own domain once you point it at us. Redirect to it, or open it in the SDK; that page is where the methods, the wallets, and 3-D Secure live, so there is nothing to build on your side.
{
"id": "ord_2h4Kq9wRz",
"reference": "9F21-0716",
"amount": 4900,
"currency": "EUR",
"status": "pending",
"checkout_url": "https://<your-checkout-host>/c/2h4Kq9wRz"
}Verify the signed result
When the payment completes, a signed event reaches your endpoint. Verify the signature against your webhook secret before you trust anything, then fulfil against the reference you already know.
{
"type": "order.paid",
"id": "evt_7Ka2Lm",
"created": "2026-07-23T09:41:02Z",
"data": {
"id": "ord_2h4Kq9wRz",
"reference": "9F21-0716",
"amount": 4900,
"currency": "EUR",
"method": "usdc",
"settlement": { "currency": "EUR", "amount": 4900, "rate": "0.9184" }
}
}The endpoints you'll actually use.
There is more in the docs, but this is the set most integrations never grow beyond.
What your backend hears about.
Every event carries the order reference you created, so your handler can be a switch on the type and a lookup on your own side.
Check the signature before you trust the body.
Every delivery carries a timestamp and an HMAC signature over the raw body. Compare in constant time, reject anything older than your tolerance window, and treat a duplicate event id as already handled — we retry on non-2xx responses, so your handler should be idempotent too.
import { createHmac, timingSafeEqual } from "node:crypto";
export function verify(rawBody, header, secret) {
const [ts, sig] = header.split(",").map((p) => p.split("=")[1]);
const expected = createHmac("sha256", secret)
.update(`${ts}.${rawBody}`)
.digest("hex");
const a = Buffer.from(sig, "hex");
const b = Buffer.from(expected, "hex");
if (a.length !== b.length || !timingSafeEqual(a, b)) return false;
// Reject replays outside a five-minute window.
return Math.abs(Date.now() / 1000 - Number(ts)) < 300;
}The properties you can build against.
Idempotent creates
Every order creation takes an idempotency key. A retried request — after a timeout, a deploy, or a queue redelivery — returns the original order rather than charging twice.
Signed, replay-protected events
Webhooks carry a timestamped HMAC signature and a stable event id. Deliveries retry with backoff until your endpoint answers 2xx, so a deploy window doesn't lose a payment.
One reference, end to end
The reference you supply on creation appears on the checkout, the receipt, the webhook, the payout, and any later refund. There is no second identifier to map between systems.
Test mode is the same code path
Test keys run the identical flows against test sessions. What passes in test is what ships — the difference is which keys you send, not which endpoints you call.
How to exercise the paths that matter.
Each path below has a test card behind it, listed with your keys when the sandbox is issued — the numbers are per-sandbox rather than published here, so they stay correct as scheme test ranges change. Behaviour is deterministic either way: a test asserts on a decline as easily as on a success.
Get keys and start.
A sandbox merchant with API keys, webhook secrets, and every method switched on — plus the full reference, so your team can integrate before anything is signed.
Request sandbox access