# Crownline Global — Payment API Integration Guide Welcome! This guide explains how to integrate your platform with Crownline Global's payment system to accept payments from your customers. --- ## 1. Overview 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. --- ## 2. Authentication 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`. --- ## 3. Creating a Payment You have two integration options, depending on whether you want to build your own checkout page or use ours. ### Option A — API Endpoint (you build your own checkout UI) 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:** ```bash 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:** ```json { "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) | ### Option B — Hosted Payment Page (we host the checkout) 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. ### Option C — Our Hosted Payment Page (branded, easiest integration) If you'd rather not build any payment UI at all — but still want your own branding instead of a third-party page — use **Option A (API Endpoint)** to create the payment, then simply redirect your customer to: ``` https://payment.crownlineglobal.co.uk/{merchantOrderId} ``` Using the same `merchantOrderId` you passed when creating the payment. This page: - Automatically adapts to the payment method (shows a code, a QR code, a redirect button, or app-open buttons depending on what's needed) - Displays in the language you specified in the `language` field of your request - Automatically updates when the payment is confirmed — no page refresh needed - Is fully mobile-responsive This is the fastest way to get a fully branded checkout experience with zero frontend work on your side. --- ## 4. Checking Payment Status You can check the status of any order at any time: ``` GET /api/payments/status?merchantOrderId=ORDER-1001 ``` ```bash curl "https://api.crownlineglobal.co.uk/api/payments/status?merchantOrderId=ORDER-1001" \ -H "Authorization: Bearer YOUR_API_KEY" ``` **Response:** ```json { "code": "SUCCESS", "status": "SUCCESS", "amount": 150000, "paidAmount": "150000", "currency": "Rp" } ``` > **Important:** `amount` is the amount requested. `paidAmount` is the amount **actually paid** by the customer — these can differ. Always use `paidAmount` to confirm whether an order was paid in full, not `amount`. **Possible `status` values:** `PENDING`, `SUCCESS`, `FAILED`. --- ## 5. Webhook Notifications 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:** ```json { "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) | ### Verifying the signature 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:** ```javascript const crypto = require('crypto'); function verifyWebhook(rawBody, signatureHeader, apiKey) { const expected = crypto .createHmac('sha256', apiKey) .update(rawBody) .digest('hex'); return expected === signatureHeader; } ``` **PHP example:** ```php 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. ### Responding to our webhook 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. --- ## 6. Error Handling All error responses follow this shape: ```json { "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 | --- ## 7. Testing 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. --- ## 8. Security Checklist - [ ] Store your API key securely (environment variables / secrets manager — never in client-side code or public repositories) - [ ] Always use HTTPS for your `notificationUrl` - [ ] Verify the `X-Payfac-Signature` header on every webhook before trusting its contents - [ ] Use `paidAmount`, not `amount`, to confirm payment completion - [ ] Regenerate your API key immediately if you suspect it has leaked --- ## 9. Support If 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. --- ## 10. Additional Resources - **Code examples:** `examples/nodejs-example.js`, `examples/php-example.php` — full working integration examples you can copy and adapt. - **Postman collection:** `examples/crownline-postman-collection.json` — import this into Postman to test all endpoints without writing any code. - **FAQ:** `faq.md` — answers to common integration questions.