Requirements
A merchant must be ready to accept payments in KemisPay before an external platform can integrate.
Create an account and complete merchant verification.
Attach an active merchant payment provider inside KemisPay.
Developer API access is included with Business at B$11.99/month.
Generate a named key from Settings → Developer API. Give each integration its own key so access can be revoked independently.
Authentication
Send the merchant API key as a Bearer token. The key identifies the KemisPay merchant. Do not include or select a merchant ID in your request body.
Authorization: Bearer kp_live_<prefix>_<secret>
KemisPay displays the secret once at creation and stores only a SHA-256 hash. The current v1 scope is payment_links:create.
Quickstart
The production API base URL is https://kemispay.com/api/v1.
curl -X POST https://kemispay.com/api/v1/payment-links \
-H "Authorization: Bearer kp_live_..." \
-H "Idempotency-Key: order-123-attempt-1" \
-H "Content-Type: application/json" \
-d '{
"productName": "GrandBridge Order #123",
"amount": "25.00",
"externalSource": "grandbridge",
"externalReference": "order_123",
"metadata": {
"orderNumber": "123"
}
}'
Create a payment link
POST /payment-links
| Field | Required | Rules | Purpose |
|---|---|---|---|
productName | Yes | 1–200 chars | Shopper-facing description |
amount | Yes | Positive two-decimal string | BSD amount |
externalSource | Yes | 1–64 letters, numbers, _ or - | Stable integration identifier |
externalReference | Yes | 1–255 chars | Your order/invoice ID |
metadata | No | JSON object | Non-secret integration metadata |
Response
{
"id": "payment-link-database-id",
"linkId": "public-link-id",
"url": "https://kemispay.com/pay/public-link-id",
"amount": "25.00",
"currency": "BSD",
"isActive": true,
"externalSource": "grandbridge",
"externalReference": "order_123"
}
A new link returns 201 Created. A safe replay or same-amount reuse returns 200 OK.
Idempotency
Every create request requires Idempotency-Key. Retry the same logical request with the same key and KemisPay returns the original result instead of creating a duplicate.
KemisPay also treats merchant + externalSource + externalReference as the external identity of the payment link. If the amount changes, the previous active external link is deactivated and a replacement is created.
Errors
Integrations should branch on error.code, not human-readable message text.
{
"error": {
"code": "invalid_api_key",
"message": "The supplied API key is invalid."
}
}
| Code | Status | Meaning |
|---|---|---|
| invalid_api_key | 401 | Missing, malformed, revoked or invalid key |
| developer_api_plan_required | 403 | Business API access required |
| merchant_verification_required | 403 | Merchant verification incomplete |
| payment_provider_required | 403 | No active provider connected |
| idempotency_key_required | 400 | Missing/invalid Idempotency-Key |
| invalid_request | 400 | Request failed validation |
| invalid_amount | 400 | Invalid amount |
| idempotency_conflict | 409 | Key reused with different data |
| payments_unavailable | 503 | Payment features temporarily unavailable |
Security
- Keep API keys server-side only.
- Never expose keys in browser JavaScript, mobile bundles, HTML or public repositories.
- Use one key per integration and revoke immediately if a key may have leaked.
- Never put provider secrets, passwords or card data in
metadata. - Underlying Cash N Go, SunCash, Kanoo and other provider credentials stay inside KemisPay.
Webhooks
KemisPay's public webhook contract is built on the same authoritative settlement outbox already used by KRM Desk. Events are emitted only after payment settlement.
{
"eventId": "payment.completed:<payment-id>",
"type": "payment.completed",
"occurredAt": "2026-10-10T12:00:00.000Z",
"source": "kemispay",
"externalSource": "grandbridge",
"externalReference": "order_123",
"paymentId": "payment-id",
"paymentLinkId": "payment-link-id",
"publicLinkId": "public-link-id",
"amountCents": 2500,
"currency": "BSD",
"provider": "cng"
}
Webhook delivery will use deterministic event IDs, HMAC-SHA256 signatures, replay protection guidance and bounded retries. Integrations must deduplicate by eventId.
Webhook verification
KemisPay signs the exact UTF-8 JSON body with a timestamp and shared signing secret.
X-KemisPay-Event-Id: payment.completed:...
X-KemisPay-Timestamp: 1791626400
X-KemisPay-Signature: sha256=<hex-hmac>
HMAC_SHA256(secret, timestamp + "." + rawBody)
Verify the signature against the exact raw request body, enforce a timestamp replay window and store processed event IDs.
Production checklist
- Business-plan API entitlement is active.
- Merchant is verified and has an active payment provider connected.
- Generate a dedicated key for the integration.
- Store the key in server-side secrets or environment variables.
- Use idempotency for every payment-link creation.
- Persist
externalReferenceso webhooks can map back to your order/invoice. - Verify webhook signatures and deduplicate events.
- Handle HTTP
429and respectRetry-Afterwhen present.
Developer API v1 is currently in pre-launch hardening. The public developer portal and generalized partner webhook configuration are the final launch items.