Every gateway exposes three endpoints under its own slug. This page covers their request formats, authentication, responses, and errors.
Endpoints
| Method | Path | Purpose | Rate limit |
|---|---|---|---|
| POST | /api/pg/{slug}/init | Start a payment | 120 / minute |
| GET | /api/pg/{slug}/verify/{paymentId} | Read a payment's state | — |
| POST | /api/pg/{slug}/oauth2/token | Trade credentials for a Bearer token | 120 / minute |
The slug and API key are on the gateway's Integration tab.
Authentication
The scheme is set per gateway. Templates inherit whichever one the provider they copy uses.
| Scheme | How to send it | Checked against |
|---|---|---|
bearer | Authorization: Bearer <key> | The gateway's API key |
basic | Authorization: Basic <base64> | Configured username and password |
api_key_header | A header, X-API-Key unless renamed | The gateway's API key |
api_key_query | A query parameter, api_key unless renamed | The gateway's API key |
none | Nothing | — |
A token from the gateway's own OAuth endpoint is accepted on every call, whatever the configured scheme. That is what makes two-step flows work.
Token exchange
POST /api/pg/{slug}/oauth2/token
Authorization: Basic <base64 of client_id:secret>
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials
Any other grant_type returns 400 with {"error":"unsupported_grant_type"}.
Starting a payment
The fields init accepts come from the gateway's schema. Every gateway needs an amount and a currency; the names depend on the template.
POST /api/pg/{slug}/init
Authorization: Bearer sk_test_XXXXXXXX
Content-Type: application/json
{
"amount": 4999,
"currency": "USD"
}
Some templates want the amount as a whole number and reject decimals. The Stripe template is one of them.
A gateway with no response template replies with the default body:
{
"payment_url": "https://mockgateway.com/pg/pay/9f8c2a1e-...",
"payment_id": "9f8c2a1e-..."
}
With a template set, you get whatever that template produces. Send the customer to the payment URL inside it.
Reading a payment
GET /api/pg/{slug}/verify/{paymentId}
Authorization: Bearer sk_test_XXXXXXXX
The default reply, when no verify template is set:
{
"payment_id": "9f8c2a1e-...",
"status": "pending",
"amount": "4999.00",
"currency": "USD",
"created_at": "2026-08-08T09:12:44.000000Z"
}
The identifier can be the internal one or the one your init reply advertised. Templates that mint provider-shaped identifiers hand you the second kind, and that is all a server-to-server integration has, so both resolve to the same payment.
Errors
| Status | Body | Cause |
|---|---|---|
| 401 | {"error":"Unauthorized","message":"Invalid or missing Bearer token."} |
Credentials missing or wrong. The wording names the scheme in use. |
| 422 | {"error":"Validation failed","message":"The request payload does not match the required schema."} |
Body does not satisfy the schema |
| 422 | {"error":"Validation failed","message":"Amount and currency are required."} |
One of the two is missing |
| 422 | {"error":"Validation failed","message":"The amount must be a number."} |
The amount field is not numeric |
| 400 | {"error":"Gateway Setup Incomplete","message":"This payment gateway is not fully configured. Please complete the setup before using the API."} |
The gateway is missing something it needs to reply |
| 404 | {"error":"Not found","message":"No payment with that id."} |
No payment on this gateway matches |
| 429 | — | Rate limit passed on init or the token endpoint |
Gateways carrying their own error bodies return those instead, at whatever status they specify. The above are the defaults. Templates that copy a provider's error format return that format — the Stripe template, for example, answers a bad amount with a Stripe-shaped invalid_request_error.
Repeated requests
A gateway can name a header to treat as an idempotency key. When it does, a repeat carrying the same key gets exactly the body the first request received instead of starting a second payment.
Hosted pages
These are browser URLs, not API endpoints. They need no credentials.
| Path | Shows |
|---|---|
/pg/pay/{paymentId} | The hosted page with the gateway's scenarios |
/pg/result/{paymentId} | The result page shown afterwards |
Was this page helpful?