Welcome! This guide explains how to integrate your platform with Crownline Global's payment system to accept payments from your customers.
Crownline Global handles the full payment process for you — from generating payment instructions for your customers to confirming when funds have arrived. You only need to talk to our API, using the API key we provide you.
Base URL (production):
https://api.crownlineglobal.co.uk
All requests must be sent over HTTPS. Requests over plain HTTP will be rejected.
Every API request must include your API key in the Authorization header:
Authorization: Bearer YOUR_API_KEY
Your API key is issued when your merchant account is created, and is visible (masked, with a "Show" option) in your Merchant Dashboard.
Keep your API key secret. Anyone with your API key can create payments on your behalf. If you believe your key has been compromised, regenerate it immediately from your dashboard under API Key → Regenerate.
⚠️ Regenerating your key immediately invalidates the old one. Update your integration with the new key right away, or your payment requests will start failing with
401 Unauthorized.
You have two integration options, depending on whether you want to build your own checkout page or use ours.
Use this if you want full control over how the payment method (bank transfer code, QR code, etc.) is displayed to your customer.
Endpoint:
POST /api/payments/create
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
merchantOrderId |
string | Yes | Your own unique order ID (must be unique per request) |
amount |
number | Yes | Payment amount |
countryCode |
string | Yes | e.g. IDN, VN, BR, COL, IN, BD, KR |
currency |
string | Yes | e.g. Rp, VND, BRL, COP, INR, BDT, KRW |
language |
string | Yes | e.g. EN, ID |
paymentMethodCode |
string | Yes | The payment method to use (we'll provide the list of available codes for your target country) |
notificationUrl |
string | Yes | Your own webhook URL — we will POST payment status updates here (see Section 5) |
customerName |
string | Yes | Customer's full name |
customerEmail |
string | Yes | Customer's email address |
customerPhone |
string | Yes | Customer's phone number |
customerPersonalId |
string | Conditional | Customer's national ID / personal identification number. Required for some countries (e.g. Vietnam, Brazil, India) — check with us for your target country. Omit if not required. |
productName |
string | Yes | Description of what's being purchased |
Example request:
curl -X POST https://api.crownlineglobal.co.uk/api/payments/create \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"merchantOrderId": "ORDER-1001",
"amount": 150000,
"countryCode": "IDN",
"currency": "Rp",
"language": "ID",
"paymentMethodCode": "BNIVA",
"notificationUrl": "https://yourshop.com/webhooks/payment",
"customerName": "Jane Doe",
"customerEmail": "jane@example.com",
"customerPhone": "081234567890",
"productName": "Order #1001"
}'
Response:
{
"code": "SUCCESS",
"status": "PENDING",
"platformOrderId": "2026080600100001",
"paymentInfo": {
"type": "code",
"content": "8330600001522451",
"expiredTime": "20260806141616"
}
}
The paymentInfo.content field is what you show your customer — its meaning depends on paymentInfo.type:
type |
Meaning |
|---|---|
code |
A virtual account number / payment code for the customer to use |
url |
A link to redirect the customer to for payment |
html |
Raw HTML content to render on your page |
json |
A nested JSON object (e.g. QR code data + a fallback link) |
Use this if you'd rather not build a payment UI yourself. Same request format, different endpoint:
POST /api/payments/create-h5
The response's paymentInfo.content will be a URL — redirect your customer's browser there to complete payment. Once done, they'll be redirected back automatically.
You can check the status of any order at any time:
GET /api/payments/status?merchantOrderId=ORDER-1001
curl "https://api.crownlineglobal.co.uk/api/payments/status?merchantOrderId=ORDER-1001" \
-H "Authorization: Bearer YOUR_API_KEY"
Response:
{
"code": "SUCCESS",
"status": "SUCCESS",
"amount": 150000,
"paidAmount": "150000",
"currency": "Rp"
}
Important:
amountis the amount requested.paidAmountis the amount actually paid by the customer — these can differ. Always usepaidAmountto confirm whether an order was paid in full, notamount.
Possible status values: PENDING, SUCCESS, FAILED.
When a payment's status changes (typically when it succeeds), we send a POST request to the notificationUrl you provided when creating the payment.
What we send:
{
"merchantOrderId": "ORDER-1001",
"status": "SUCCESS",
"amount": 150000,
"paidAmount": "150000",
"currency": "Rp"
}
Headers:
| Header | Description |
|---|---|
Content-Type |
application/json |
X-Payfac-Signature |
HMAC-SHA256 signature of the raw request body, signed with your API key (hex-encoded) |
To confirm a webhook genuinely came from us (and not an impersonator), recompute the signature yourself and compare:
Pseudocode:
expected_signature = HMAC_SHA256(key = your_api_key, message = raw_request_body)
if expected_signature != X-Payfac-Signature header:
reject the request
Node.js example:
const crypto = require('crypto');
function verifyWebhook(rawBody, signatureHeader, apiKey) {
const expected = crypto
.createHmac('sha256', apiKey)
.update(rawBody)
.digest('hex');
return expected === signatureHeader;
}
PHP example:
function verifyWebhook($rawBody, $signatureHeader, $apiKey) {
$expected = hash_hmac('sha256', $rawBody, $apiKey);
return hash_equals($expected, $signatureHeader);
}
Always compute the signature over the raw, unparsed request body — not a re-serialized version of the JSON, as formatting differences will cause the signature check to fail.
Return an HTTP 200 status code to acknowledge receipt. If we don't receive a 200, we currently do not automatically retry — we recommend checking payment status via the API (Section 4) as a backup if you suspect a webhook was missed.
All error responses follow this shape:
{
"error": "description of what went wrong"
}
Common HTTP status codes:
| Status | Meaning |
|---|---|
200 |
Success |
400 |
Invalid request (missing/malformed fields) |
401 |
Missing or invalid API key |
403 |
Your merchant account has been suspended — contact us |
502 |
We couldn't process the request — retry shortly |
Before going live, we can provide you with a test/sandbox API key so you can validate your integration end-to-end without moving real funds. Contact us to request sandbox access.
notificationUrlX-Payfac-Signature header on every webhook before trusting its contentspaidAmount, not amount, to confirm payment completionIf you run into issues integrating, or need the list of paymentMethodCode values available for your target country, please reach out to your Crownline Global account contact.
examples/nodejs-example.js, examples/php-example.php — full working integration examples you can copy and adapt.examples/crownline-postman-collection.json — import this into Postman to test all endpoints without writing any code.faq.md — answers to common integration questions.