Integrate deposits into your own cashier across two rails from a single API: Europe open banking (SEPA / Instant / Revolut / FPS) and LATAM (Peru, Chile, Ecuador, Mexico, Colombia). Create a payment, send the customer to the returned URL, then track its status via webhooks (recommended) or polling. Built for casino and high-volume merchants.
https://platinum-edge.ca/api/v1
Every request is authenticated with a secret API key you generate in the dashboard (API keys panel). Send it as a Bearer token. Keep it server-side only - never expose it in a browser or mobile app.
Authorization: Bearer pe_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Generate a separate pe_test_ key in the dashboard to integrate end-to-end with no real money. A test key uses the exact same endpoints; the platform simulates the payment instead of calling the bank, so you can build and verify your create → webhook → return_url flow before going live.
Authorization: Bearer pe_test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
amount ending in .13 (e.g. 10.13) is declined; any other amount is approved instantly.livemode: false in the response.GET /payments with the test key.pe_live_ key when you are ready - nothing else in your integration changes.Pick a country, then a method. We jump you to that solution's section with its required fields, currency, allowed document types, and a copy-paste POST /payments example.
| Method | Best for | You build |
|---|---|---|
| Hosted Checkout (recommended) | Fastest path - a casino cashier that wants minimal code and a ready-made, PCI/PSD2-grade payment page. | One API call + redirect the player. We host the payment page. |
| Direct API (advanced) | Full control over the deposit UI on your own page. | Collect the player + bank details yourself, then call the API and redirect to the returned bank URL. |
Both settle through the same pipeline and fire the same webhooks. Pick one per integration; you can mix per transaction. LATAM solutions always use the Direct API shape documented in Solution picker - one POST /payments that returns a redirect URL.
Four open-banking methods across NL, MT and GB. Each is a standalone solution below; all share the Hosted Checkout and Direct API request shapes that follow. The per-solution blocks are generated from the same rail config the gateway uses, so they never drift.
Create a checkout session, then redirect the player to the returned URL. The player completes payment on a PlatinumEdge-hosted page - you never handle bank details. You can pass everything up front (player skips straight to the bank) or pass only the amount (our page collects the rest).
| Field | Required | Description |
|---|---|---|
amount | yes | Major units, e.g. "250.00" |
return_url | recommended | https:// page to send the player back to. We append ?ref=&status=. |
merchant_reference | no | Your player/deposit id; echoed on the webhook and status lookup. |
method, bankCountry | no | Pre-select the rail (e.g. fps/GB). Omit to let the player choose on our page. |
email, firstName, lastName, country, address1, city, zipCode, phone | no | Prefill the player's details. Anything omitted is collected on the hosted page. |
expires_in | no | Session lifetime in seconds (300-86400, default 3600). |
curl -X POST https://platinum-edge.ca/api/v1/checkout-sessions \
-H "Authorization: Bearer pe_live_..." \
-H "Content-Type: application/json" \
-d '{
"amount": "250.00",
"merchant_reference": "player-90431/dep-2207",
"return_url": "https://cashier.example.com/deposit/return"
}'
201{
"ok": true,
"id": "cs_xxxxxxxxxxxxxxxx",
"url": "https://checkout.platinum-edge.ca/c/cs_xxxxxxxxxxxxxxxx",
"expires_in": 3600
}
Redirect the player's browser to url. When they finish, we return them to your return_url and - separately - notify your server via webhook. Treat the webhook as the source of truth for crediting; the browser return is only a UX signal. The amount and merchant are locked to the session, so the player cannot change them.
Collect the player + bank details yourself, then create a payment and get a bank redirect URL to send your customer to.
| Field | Required | Description |
|---|---|---|
amount | yes | Major units, e.g. "250.00" |
method | yes | sepa | instant | revolut | fps |
bankCountry | yes | NL | MT | GB (FPS is GB only) |
email | yes | Customer email |
firstName, lastName | yes | Customer name |
country | yes | Billing country, ISO-2 (e.g. GB) |
address1, city, zipCode | yes | Billing address |
phone | no | Customer phone |
merchant_reference | no | Your own ID for this deposit (player / cashier reference). Echoed back on the status webhook and on GET /payments/{reference}, so you can reconcile against your cashier without storing our reference. Max 128 chars. |
return_url | no | Where to send the player's browser after the bank flow finishes. Must be https://. We redirect to {return_url}?ref={reference}&status={status}. If omitted, the player lands on our generic result page. |
idempotency_key | no | A unique string per deposit attempt. If you retry the same key, you get the original payment back instead of a duplicate. Also accepted as the Idempotency-Key header. |
curl -X POST https://platinum-edge.ca/api/v1/payments \
-H "Authorization: Bearer pe_live_..." \
-H "Content-Type: application/json" \
-H "Idempotency-Key: dep_8f3a1c9e" \
-d '{
"amount": "250.00",
"method": "fps",
"bankCountry": "GB",
"email": "customer@example.com",
"firstName": "Alex", "lastName": "Doe",
"country": "GB", "address1": "1 High St", "city": "London", "zipCode": "EC1A 1BB",
"merchant_reference": "player-90431/dep-2207",
"return_url": "https://cashier.example.com/deposit/return"
}'
201{
"ok": true,
"payment": {
"reference": "PE-MC-XXXX-XXXX",
"redirect_url": "https://",
"status": "redirected",
"merchant_reference": "player-90431/dep-2207"
}
}
Redirect the customer's browser to redirect_url to complete the bank payment. When they finish, we return them to your return_url (if supplied) and - separately - notify your server via webhook (below). Treat the webhook as the source of truth for crediting a deposit; the browser return is only a UX signal.
LATAM solutions are created with the same POST /payments endpoint by selecting a country and (where the country has more than one option) a method. The customer is sent to a hosted payment link (returned as redirect_url), and settlement is confirmed by webhook. Required fields, currency and allowed document types differ per solution - the blocks below are generated from the rail's FIELD_MATRIX + GEO_CURRENCY so the docs never drift.
| Field | Required | Description |
|---|---|---|
country | yes | ECUADOR | CHILE | PERU | MEXICO | COLOMBIA - selects the LATAM rail. |
method | cond. | Chile: cards | bank. Peru: bank | qr. Single-method countries (Ecuador, Mexico, Colombia) omit it. |
amount | yes | Major units. Currency is implied by the country (see each solution). CLP and COP are zero-decimal - send integer amounts (e.g. "5000", not "5000.00"). |
currency | no | Optional override; defaults to the country currency. |
email | yes | Customer email. |
firstName, lastName | yes | Customer name (first / last). |
documentType | yes | Case-sensitive ID type - allowed values are per-country (see each solution). |
documentNumber | yes | ID document number. Format is validated per geo (e.g. Peru DNI = 8 digits, Chile RUT = NNNNNNNN-D). |
phone, phoneCode | cond. | Phone + country code (e.g. "+57"). Required for Chile cards and Colombia; Ecuador rejects phone fields entirely - omit them. |
successUrl, errorUrl | cond. | Redirect URLs after the hosted payment. Required varies per solution. |
redirectUrl | cond. | Colombia only - the post-interaction return URL (paid, unpaid or aborted). |
expiresAt | cond. | Link expiry, ISO 8601. Ecuador requires a near-future expiry; Peru/Chile ignore it (provider sets 30 min). |
merchant_reference, return_url, idempotency_key | no | Same as the Europe Direct API - your deposit id, browser return, and idempotency. |
GET /payments/{reference} if a customer does not return.| Status | Meaning |
|---|---|
redirected / pending | Awaiting the customer's bank payment |
approved_for_payment | Authorized - money has left the payer's account |
approved | Settled - funds received |
declined | Not completed - no money taken |
Configure a webhook URL in the dashboard (Developers section). On every status change we send a POST to that URL so your cashier can credit a deposit automatically - no polling needed. This is identical for Europe and LATAM solutions.
| Event | When |
|---|---|
payment.approved | Funds confirmed - safe to credit the player. |
payment.declined | Payment failed or was abandoned - do not credit. |
POST https://your-cashier.example.com/webhooks/platinum-edge
Content-Type: application/json
X-PE-Signature: t=1733600000,v1=9b2c...e1
{
"id": "evt_4a8c...",
"event": "payment.approved",
"livemode": true,
"created_at": "2026-06-08T12:00:00Z",
"data": {
"reference": "PE-MC-XXXX-XXXX",
"merchant_reference": "player-90431/dep-2207",
"status": "approved",
"amount": "250.00",
"currency": "GBP"
}
}
livemode is true for real payments and false for sandbox/test payments (test API key or the dashboard "send test payment"). Use it to ignore test events in your production handler, and to drive your own test assertions.
Each delivery carries an X-PE-Signature header: t=<unix-timestamp>,v1=<hmac>. Compute HMAC-SHA256 over the string "{t}.{raw_request_body}" using your webhook signing secret (shown once in the dashboard), and compare it - in constant time - to v1. Reject deliveries older than ~5 minutes to prevent replay.
// Node.js
import crypto from "node:crypto";
function verify(rawBody, header, secret) {
const parts = Object.fromEntries(header.split(",").map(p => p.split("=")));
const expected = crypto.createHmac("sha256", secret)
.update(parts.t + "." + rawBody).digest("hex");
const ok = crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
const fresh = Math.abs(Date.now()/1000 - Number(parts.t)) < 300;
return ok && fresh;
}
Return 2xx within 10 seconds to acknowledge. Any other response (or a timeout) is retried with exponential backoff for up to 24 hours. Make your handler idempotent - key on data.reference - because a delivery can arrive more than once.
GET /payments/{reference} after redirecting the customer. Webhooks are strongly recommended for production deposits.This is the step that tops up the player's wallet in your system. We confirm the deposit and tell you who (merchant_reference) and how much (amount + currency); your server applies it to the player. We never touch your player accounts.
merchant_reference to something that identifies the player (and ideally the deposit), e.g. "player-90431/dep-2207".payment.approved with that same merchant_reference plus amount, currency, and our reference.merchant_reference to the player, and credits the amount - once.// POST /webhooks/platinum-edge (your server)
export default async function handler(req, res) {
const raw = req.rawBody; // the exact bytes we sent
if (!verify(raw, req.headers["x-pe-signature"], WEBHOOK_SECRET))
return res.status(401).end(); // reject forged / stale calls
const evt = JSON.parse(raw);
if (evt.event === "payment.approved") {
const playerId = playerFrom(evt.data.merchant_reference); // your mapping
// Idempotent: only credit the first time we see this reference.
if (await ledger.recordOnce(evt.data.reference)) {
await wallet.credit(playerId, evt.data.amount, evt.data.currency);
}
}
return res.status(200).json({ ok: true }); // 2xx within 10s
}
data.reference (retries can deliver twice); the amount/currency come from us and are locked to the deposit, so a player cannot inflate them; do not credit on the browser return_url alone - it is only a UX signal. The webhook is the source of truth.| Step | PlatinumEdge | You (casino) |
|---|---|---|
| Detect the bank payment succeeded | yes | - |
Send signed payment.approved (player ref + amount) | yes | - |
| Retry until acknowledged (up to 24h) | yes | - |
| Map reference to player and add balance | - | yes |
| Show the new balance in the player's profile | - | yes |
Fetch a single payment's current status.
curl https://platinum-edge.ca/api/v1/payments/PE-MC-XXXX-XXXX \
-H "Authorization: Bearer pe_live_..."
{
"ok": true,
"payment": {
"reference": "PE-MC-XXXX-XXXX",
"status": "approved",
"amount": "250.00",
"currency": "GBP",
"customer_email": "customer@example.com",
"customer_name": "Alex Doe",
"merchant_reference": "player-90431/dep-2207",
"created_at": "...", "updated_at": "..."
}
}
List your payments, newest first. Paginate with the before cursor.
| Query | Description |
|---|---|
limit | 1-200 (default 50) |
before | Cursor: pass the last id from the previous page |
{ "ok": true, "data": [ /* payments */ ], "paging": { "limit": 50, "next_before": 123 } }
Payouts let you pay your own players - withdrawals from your cashier to a player's bank account. This is the reverse of a deposit and is distinct from settlement: settlement is when we automatically pay you (the merchant) your accumulated deposit balance; a payout is when you send money to one of your players. One neutral API covers every supported country.
pe_test_ key simulates a payout (no money moves) so you can build your integration end-to-end. Live payouts must be enabled on your account before they will process; until then a live request returns 503 { "ok": false, "error": "Payouts are not yet enabled for live mode." }. Ask us to enable live payouts when you are ready.Create a payout to a player's bank account. The amount is in major units; the currency is implied by the country (CLP and COP are zero-decimal - send integer amounts).
| Field | Required | Description |
|---|---|---|
country | yes | ECUADOR | CHILE | PERU | MEXICO | COLOMBIA. Selects the payout rail + currency. |
amount | yes | Major units, e.g. "250.00" (or integer "5000" for CLP / COP). |
currency | no | Optional override; defaults to the country currency. |
beneficiary | yes | The player's payout details - see Beneficiary by country for the required sub-fields. |
merchant_reference | no | Your own id for this payout (e.g. "player-90431/wd-5512"). Echoed on the payout webhook and on GET /payouts. Max 128 chars. |
idempotency_key | no | A unique string per payout attempt. Retrying the same key returns the original payout instead of sending a duplicate. Also accepted as the Idempotency-Key header. |
| Field | Description |
|---|---|
name | Beneficiary full name (first + last). For a company beneficiary, the company name. |
document_type | Case-sensitive ID type, per country (see each country block). |
document_number | ID document number. |
account_number | Destination account number (the CLABE for Mexico). |
bank_code | Case-sensitive bank code, per country (see each country block). |
account_type | Account type code, per country (e.g. savings / checking / CLABE). |
cci | Peru only - the interbank (CCI) number, different from account_number. For other countries this is optional and defaults to account_number. |
201{
"ok": true,
"payout": {
"reference": "PE-PO-XXXX-XXXX",
"status": "pending",
"amount": "250.00",
"currency": "PEN",
"country": "PERU",
"merchant_reference": "player-90431/wd-5512"
}
}
A payout starts pending. The final outcome arrives later as a payout webhook (and is reflected on GET /payouts). A 422 with a missing array is returned when required beneficiary fields are absent for the country.
Required beneficiary sub-fields differ per country. The blocks below are generated from the same rail data the payout API validates against, so they never drift.
| Status | Meaning |
|---|---|
pending | Accepted and awaiting settlement to the player's account (initial state). |
paid | Settled - the funds reached the player's account. |
bounced | Rejected by the bank (e.g. invalid account, closed account, wrong code). Final. |
reverted | Was paid, then reversed - the funds were returned. Final. |
When a payout reaches a terminal state we POST a webhook to your configured URL, signed with the same X-PE-Signature scheme as payment webhooks (see Webhooks for verification). Subscribe to these events in the dashboard.
| Event | When |
|---|---|
payout.paid | The payout settled - the player received the funds. |
payout.bounced | The payout was rejected and did not pay out. |
payout.reverted | A previously-paid payout was reversed; funds returned. |
{
"id": "evt_...",
"event": "payout.paid",
"livemode": true,
"created_at": "2026-06-18T12:00:00Z",
"data": {
"reference": "PE-PO-XXXX-XXXX",
"merchant_reference": "player-90431/wd-5512",
"status": "paid",
"amount": "250.00",
"currency": "PEN"
}
}
Be idempotent on data.reference - a delivery can arrive more than once. livemode is false for sandbox payouts.
List your payouts, newest first. A test key lists only sandbox payouts; a live key lists only live payouts. Paginate with the before cursor.
{ "ok": true, "data": [ /* payouts */ ], "paging": { "limit": 50, "next_before": 123 } }
Errors return a non-2xx status with { "ok": false, "error": "message" }. 401 means a missing/invalid/revoked API key.