Skip to main content

Endpoints

MethodEndpointDescriptionRate Limit
GET/v1/direct-debit/scenario-code/listGet supported scenario codes200 req/min
POST/v1/direct-debitCreate a new contract100 req/min
GET/v1/direct-debit/listList contracts100 req/min
GET/v1/direct-debit/:idGet contract details100 req/min
POST/v1/direct-debit/:id/syncQuery/sync contract status50 req/min
POST/v1/direct-debit/:id/terminateTerminate a contract50 req/min
POST/v1/direct-debit/:id/paymentExecute payment against contract100 req/min

Get Scenario Codes

Retrieves a list of supported scenario codes for direct debit contracts. Use these IDs when creating a contract. Scenarios define the type of service and transaction limits.
GET /v1/direct-debit/scenario-code/list

Authentication

Requires HMAC authentication with headers:
  • x-api-key: Your API key ID only (e.g., ak_live_xxx)
  • x-timestamp: Current Unix timestamp in milliseconds
  • x-signature: HMAC-SHA256 signature (using derived signing key)

Query Parameters

ParameterTypeRequiredDescription
providerstringNoFilter by payment provider: BINANCE_PAY, BYBIT_PAY, KUCOIN_PAY
activestringNoFilter by active status (true/false, default: true)

Example Request

curl "https://api.ceypay.io/v1/direct-debit/scenario-code/list?provider=BINANCE_PAY" \
  -H "x-api-key: ak_live_abc123" \
  -H "x-timestamp: 1705315800000" \
  -H "x-signature: your_signature_here"

Example Response

{
  "data": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440003",
      "scenarioId": "12345",
      "scenarioName": "Subscription Service",
      "paymentProvider": "BINANCE_PAY",
      "maxLimit": 1000,
      "isActive": true
    }
  ]
}

Error Responses

StatusDescription
401Unauthorized - invalid HMAC signature
429Too many requests - rate limit exceeded

Create Contract

Creates a pre-authorization contract that users can sign to enable on-demand payments. Supports multiple payment providers (currently: BINANCE_PAY). Returns QR code and deep link for user approval.
POST /v1/direct-debit

Authentication

Requires HMAC authentication with headers:
  • x-api-key: Your API key ID only (e.g., ak_live_xxx)
  • x-timestamp: Current Unix timestamp in milliseconds
  • x-signature: HMAC-SHA256 signature (using derived signing key)

Request Body

FieldTypeRequiredDescription
providerstringYesPayment provider: BINANCE_PAY
merchantContractCodestringNoUnique merchant contract code (alphanumeric, max 32 chars). Auto-generated if not provided
branchIdstring (UUID)NoBranch ID to associate this contract with
serviceNamestringYesService name displayed to user (max 32 chars)
scenarioIdstring (UUID)YesScenario ID from scenario-code/list endpoint
currencystringYesContract currency: USDT (crypto) or LKR (fiat)
singleUpperLimitnumberYesMaximum amount per transaction in the specified currency (min 0.01)
slippageBpsnumberNoSlippage buffer in basis points for LKR contracts (0-20000 bps = 0-200%). Not allowed for USDT. Default: 0. Example: 10000 bps = 100%
webhookUrlstringNoWebhook URL for contract events
returnUrlstring (URL)YesURL to redirect user after successful contract signing (max 512 chars)
cancelUrlstring (URL)YesURL to redirect user after contract signing cancellation (max 512 chars)

Example Request (USDT Contract)

curl -X POST "https://api.ceypay.io/v1/direct-debit" \
  -H "Content-Type: application/json" \
  -H "x-api-key: ak_live_abc123" \
  -H "x-timestamp: 1705315800000" \
  -H "x-signature: your_signature_here" \
  -d '{
    "provider": "BINANCE_PAY",
    "currency": "USDT",
    "serviceName": "Monthly Subscription",
    "scenarioId": "550e8400-e29b-41d4-a716-446655440003",
    "singleUpperLimit": 100.0,
    "returnUrl": "https://your-app.com/contract/success",
    "cancelUrl": "https://your-app.com/contract/cancelled",
    "webhookUrl": "https://your-app.com/api/contract-webhook"
  }'

Example Request (LKR Contract with Slippage)

curl -X POST "https://api.ceypay.io/v1/direct-debit" \
  -H "Content-Type: application/json" \
  -H "x-api-key: ak_live_abc123" \
  -H "x-timestamp: 1705315800000" \
  -H "x-signature: your_signature_here" \
  -d '{
    "provider": "BINANCE_PAY",
    "currency": "LKR",
    "serviceName": "Monthly Subscription",
    "scenarioId": "550e8400-e29b-41d4-a716-446655440003",
    "singleUpperLimit": 33000.0,
    "slippageBps": 10000,
    "returnUrl": "https://your-app.com/contract/success",
    "cancelUrl": "https://your-app.com/contract/cancelled",
    "webhookUrl": "https://your-app.com/api/contract-webhook"
  }'

Example Response (USDT Contract)

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "merchantId": "merchant_12345",
  "merchantContractCode": "DD20260309120530A3F4",
  "serviceName": "Monthly Subscription",
  "status": "INITIATED",
  "currency": "USDT",
  "singleUpperLimit": 100.0,
  "paymentProvider": "BINANCE_PAY",
  "qrContent": "binance://contract?code=...",
  "deepLink": "https://app.binance.com/contract/sign?code=...",
  "createdAt": "2026-03-25T10:30:00.000Z"
}

Example Response (LKR Contract)

{
  "id": "550e8400-e29b-41d4-a716-446655440001",
  "merchantId": "merchant_12345",
  "merchantContractCode": "DD20260309120530B4G5",
  "serviceName": "Monthly Subscription",
  "status": "INITIATED",
  "currency": "LKR",
  "singleUpperLimit": 200.0,
  "singleUpperLimitLkr": 33000.0,
  "slippageBps": 10000,
  "paymentProvider": "BINANCE_PAY",
  "qrContent": "binance://contract?code=...",
  "deepLink": "https://app.binance.com/contract/sign?code=...",
  "createdAt": "2026-03-25T10:30:00.000Z"
}
Note for LKR Contracts:
  • singleUpperLimit shows the USDT amount sent to Binance (after currency conversion + slippage buffer)
  • singleUpperLimitLkr shows the original LKR amount specified
  • slippageBps shows the slippage buffer applied (10000 bps = 100%)
  • In this example: 33000 LKR ÷ 330 (exchange rate) = 100 USDT, with 100% slippage = 200 USDT total limit

Error Responses

StatusDescription
400Bad request - invalid contract data, slippage not allowed for USDT, or missing exchange rate for LKR
401Unauthorized - invalid HMAC signature
403Forbidden - merchant not authorized
429Too many requests - rate limit exceeded

List Contracts

Retrieves a paginated list of contracts for the authenticated merchant. Supports filtering by status, branch, currency, payment provider, and search.
GET /v1/direct-debit/list

Authentication

Requires HMAC authentication with headers:
  • x-api-key: Your API key ID only (e.g., ak_live_xxx)
  • x-timestamp: Current Unix timestamp in milliseconds
  • x-signature: HMAC-SHA256 signature (using derived signing key)

Query Parameters

ParameterTypeRequiredDescription
pagenumberNoPage number (default: 1)
limitnumberNoItems per page (default: 20, max: 100)
statusstringNoFilter by status: INITIATED, SIGNED, TERMINATED, EXPIRED
branchIdstring (UUID)NoFilter by branch ID
currencystringNoFilter by currency: USDT, LKR
paymentProviderstringNoFilter by provider: BINANCE_PAY, BYBIT_PAY, KUCOIN_PAY
searchstringNoSearch by merchant contract code or service name

Example Request

curl "https://api.ceypay.io/v1/direct-debit/list?page=1&limit=20&status=SIGNED" \
  -H "x-api-key: ak_live_abc123" \
  -H "x-timestamp: 1705315800000" \
  -H "x-signature: your_signature_here"

Example Response

{
  "data": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "merchantContractCode": "DD20260309120530A3F4",
      "serviceName": "Monthly Subscription",
      "status": "SIGNED",
      "currency": "USDT",
      "singleUpperLimit": 100.0,
      "paymentProvider": "BINANCE_PAY",
      "createdAt": "2026-03-25T10:30:00.000Z"
    }
  ],
  "meta": {
    "page": 1,
    "limit": 20,
    "totalItems": 45,
    "totalPages": 3
  }
}

Error Responses

StatusDescription
401Unauthorized - invalid HMAC signature
429Too many requests - rate limit exceeded

Get Contract Details

Retrieves contract details by ID. Only returns contracts belonging to the authenticated merchant.
GET /v1/direct-debit/:id

Authentication

Requires HMAC authentication with headers:
  • x-api-key: Your API key ID only (e.g., ak_live_xxx)
  • x-timestamp: Current Unix timestamp in milliseconds
  • x-signature: HMAC-SHA256 signature (using derived signing key)

Path Parameters

ParameterTypeRequiredDescription
idstring (UUID)YesContract ID

Example Request

curl "https://api.ceypay.io/v1/direct-debit/550e8400-e29b-41d4-a716-446655440000" \
  -H "x-api-key: ak_live_abc123" \
  -H "x-timestamp: 1705315800000" \
  -H "x-signature: your_signature_here"

Example Response

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "merchantId": "merchant_12345",
  "branchId": "550e8400-e29b-41d4-a716-446655440002",
  "paymentProvider": "BINANCE_PAY",
  "merchantContractCode": "DD20260309120530A3F4",
  "preContractId": "29383937493038367292",
  "contractId": 123456789,
  "bizId": "420471959722147840",
  "serviceName": "Monthly Subscription",
  "scenarioId": "550e8400-e29b-41d4-a716-446655440003",
  "currency": "USDT",
  "singleUpperLimit": 100.0,
  "periodic": false,
  "contractEndTime": "2027-03-25T00:00:00.000Z",
  "requestExpireTime": "2026-03-26T00:00:00.000Z",
  "openUserId": "eb6b287a44dd73dd81645a3cbcfee162",
  "merchantAccountNo": "[email protected]",
  "status": "SIGNED",
  "paymentCount": 3,
  "totalAmountCharged": 150.0,
  "lastPaymentAt": "2026-03-24T10:30:00.000Z",
  "webhookUrl": "https://your-app.com/api/contract-webhook",
  "createdAt": "2026-03-25T10:30:00.000Z",
  "updatedAt": "2026-03-25T11:00:00.000Z"
}

Error Responses

StatusDescription
401Unauthorized - invalid HMAC signature
403Forbidden - contract does not belong to merchant
404Contract not found
429Too many requests - rate limit exceeded

Query/Sync Contract Status

Queries the payment provider for the latest contract status and syncs it to the database. Use this to check if a user has signed the contract.
POST /v1/direct-debit/:id/sync

Authentication

Requires HMAC authentication with headers:
  • x-api-key: Your API key ID only (e.g., ak_live_xxx)
  • x-timestamp: Current Unix timestamp in milliseconds
  • x-signature: HMAC-SHA256 signature (using derived signing key)

Path Parameters

ParameterTypeRequiredDescription
idstring (UUID)YesContract ID

Request Body

Empty object {}

Example Request

curl -X POST "https://api.ceypay.io/v1/direct-debit/550e8400-e29b-41d4-a716-446655440000/sync" \
  -H "Content-Type: application/json" \
  -H "x-api-key: ak_live_abc123" \
  -H "x-timestamp: 1705315800000" \
  -H "x-signature: your_signature_here" \
  -d '{}'

Example Response

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "merchantId": "merchant_12345",
  "paymentProvider": "BINANCE_PAY",
  "merchantContractCode": "DD20260309120530A3F4",
  "preContractId": "29383937493038367292",
  "contractId": 123456789,
  "bizId": "420471959722147840",
  "serviceName": "Monthly Subscription",
  "scenarioId": "550e8400-e29b-41d4-a716-446655440003",
  "currency": "USDT",
  "singleUpperLimit": 100.0,
  "periodic": false,
  "contractEndTime": "2027-03-25T00:00:00.000Z",
  "requestExpireTime": "2026-03-26T00:00:00.000Z",
  "openUserId": "eb6b287a44dd73dd81645a3cbcfee162",
  "merchantAccountNo": "[email protected]",
  "status": "SIGNED",
  "paymentCount": 0,
  "totalAmountCharged": 0,
  "webhookUrl": "https://your-app.com/api/contract-webhook",
  "createdAt": "2026-03-25T10:30:00.000Z",
  "updatedAt": "2026-03-25T11:00:00.000Z"
}

Error Responses

StatusDescription
401Unauthorized - invalid HMAC signature
404Contract not found
429Too many requests - rate limit exceeded

Terminate Contract

Terminates a signed Direct Debit contract. Only contracts in SIGNED status can be terminated.
POST /v1/direct-debit/:id/terminate

Authentication

Requires HMAC authentication with headers:
  • x-api-key: Your API key ID only (e.g., ak_live_xxx)
  • x-timestamp: Current Unix timestamp in milliseconds
  • x-signature: HMAC-SHA256 signature (using derived signing key)

Path Parameters

ParameterTypeRequiredDescription
idstring (UUID)YesContract ID

Request Body

FieldTypeRequiredDescription
terminationNotesstringNoOptional notes about contract termination (max 256 chars)

Example Request

curl -X POST "https://api.ceypay.io/v1/direct-debit/550e8400-e29b-41d4-a716-446655440000/terminate" \
  -H "Content-Type: application/json" \
  -H "x-api-key: ak_live_abc123" \
  -H "x-timestamp: 1705315800000" \
  -H "x-signature: your_signature_here" \
  -d '{
    "terminationNotes": "User requested cancellation"
  }'

Example Response

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "merchantId": "merchant_12345",
  "paymentProvider": "BINANCE_PAY",
  "merchantContractCode": "DD20260309120530A3F4",
  "preContractId": "29383937493038367292",
  "contractId": 123456789,
  "bizId": "420471959722147840",
  "serviceName": "Monthly Subscription",
  "scenarioId": "550e8400-e29b-41d4-a716-446655440003",
  "currency": "USDT",
  "singleUpperLimit": 100.0,
  "periodic": false,
  "contractEndTime": "2027-03-25T00:00:00.000Z",
  "requestExpireTime": "2026-03-26T00:00:00.000Z",
  "openUserId": "eb6b287a44dd73dd81645a3cbcfee162",
  "merchantAccountNo": "[email protected]",
  "status": "TERMINATED",
  "contractTerminationWay": 3,
  "contractTerminationTime": "2026-03-25T12:00:00.000Z",
  "terminationNotes": "User requested cancellation",
  "paymentCount": 5,
  "totalAmountCharged": 250.0,
  "lastPaymentAt": "2026-03-24T10:30:00.000Z",
  "webhookUrl": "https://your-app.com/api/contract-webhook",
  "createdAt": "2026-03-25T10:30:00.000Z",
  "updatedAt": "2026-03-25T12:00:00.000Z"
}

Error Responses

StatusDescription
400Bad request - contract not in SIGNED status
401Unauthorized - invalid HMAC signature
404Contract not found
429Too many requests - rate limit exceeded

Execute Payment

Executes an on-demand payment against a signed Direct Debit contract. Amount must not exceed the contract’s single upper limit.
POST /v1/direct-debit/:id/payment

Authentication

Requires HMAC authentication with headers:
  • x-api-key: Your API key ID only (e.g., ak_live_xxx)
  • x-timestamp: Current Unix timestamp in milliseconds
  • x-signature: HMAC-SHA256 signature (using derived signing key)

Path Parameters

ParameterTypeRequiredDescription
idstring (UUID)YesContract ID

Request Body

FieldTypeRequiredDescription
currencystringYesPayment currency: USDT or LKR (can differ from contract currency)
amountnumberYesPayment amount in the specified currency (min 0.01). Must not exceed contract’s buffered limit after conversion
productNamestringYesProduct name (max 256 chars)
productDetailstringNoProduct detail (max 256 chars)
goodsarrayNoArray of goods items (see structure below)
webhookUrlstringNoWebhook URL to override contract webhook
customerBillingobjectNoCustomer billing information (see structure below)

Goods Item Structure

FieldTypeRequiredDescription
goodsTypestringYesGoods type (01: Tangible goods, 02: Virtual goods)
goodsCategorystringYesGoods category code (e.g., Z000)
referenceGoodsIdstringYesReference goods ID
goodsNamestringYesGoods name (max 256 chars)
goodsDetailstringNoGoods detail description (max 256 chars)

Customer Billing Structure

FieldTypeRequiredDescription
firstNamestringYesCustomer first name
lastNamestringYesCustomer last name
emailstringYesCustomer email
phonestringNoCustomer phone
addressstringNoCustomer address

Example Request (USDT Payment)

curl -X POST "https://api.ceypay.io/v1/direct-debit/550e8400-e29b-41d4-a716-446655440000/payment" \
  -H "Content-Type: application/json" \
  -H "x-api-key: ak_live_abc123" \
  -H "x-timestamp: 1705315800000" \
  -H "x-signature: your_signature_here" \
  -d '{
    "currency": "USDT",
    "amount": 50.0,
    "productName": "Monthly Subscription",
    "productDetail": "Premium membership for March 2026",
    "customerBilling": {
      "firstName": "John",
      "lastName": "Doe",
      "email": "[email protected]",
      "phone": "+94771234567"
    },
    "webhookUrl": "https://your-app.com/api/payment-webhook"
  }'

Example Request (LKR Payment)

curl -X POST "https://api.ceypay.io/v1/direct-debit/550e8400-e29b-41d4-a716-446655440001/payment" \
  -H "Content-Type: application/json" \
  -H "x-api-key: ak_live_abc123" \
  -H "x-timestamp: 1705315800000" \
  -H "x-signature: your_signature_here" \
  -d '{
    "currency": "LKR",
    "amount": 16500.0,
    "productName": "Monthly Subscription",
    "productDetail": "Premium membership for March 2026",
    "customerBilling": {
      "firstName": "John",
      "lastName": "Doe",
      "email": "[email protected]",
      "phone": "+94771234567"
    },
    "webhookUrl": "https://your-app.com/api/payment-webhook"
  }'

Example Response

{
  "id": "550e8400-e29b-41d4-a716-446655440001",
  "merchantId": "merchant_12345",
  "payId": "binance_pay_xyz789",
  "paymentNo": "320045925617",
  "amount": 50.0,
  "currency": "USDT",
  "status": "INITIATED",
  "paymentProvider": "BINANCE_PAY",
  "directDebitContractId": "550e8400-e29b-41d4-a716-446655440000",
  "createdAt": "2026-03-25T10:30:00.000Z",
  "feeBreakdown": {
    "grossAmountUSDT": 50.0,
    "exchangeFeePercentage": 1.0,
    "exchangeFeeAmountUSDT": 0.50,
    "ceypayFeePercentage": 0.5,
    "ceypayFeeAmountUSDT": 0.25,
    "totalFeesUSDT": 0.75,
    "netAmountUSDT": 49.25
  }
}

Response Notes

  • Direct debit payments do not include qrContent or checkoutLink fields as the payment is charged directly without user interaction
  • Payment starts in INITIATED status and transitions to PAID via webhook notification
  • In sandbox mode, payments are automatically marked as PAID

Error Responses

StatusDescription
400Bad request - contract not signed, expired, amount exceeds limit after currency conversion, or exchange rate unavailable
401Unauthorized - invalid HMAC signature
404Contract not found
429Too many requests - rate limit exceeded

Currency & Slippage

Currency Support

Direct Debit contracts support two currencies:
CurrencyTypeDescription
USDTCryptoTether stablecoin on blockchain
LKRFiatSri Lankan Rupee

Cross-Currency Payments

You can execute payments in either USDT or LKR regardless of the contract’s currency:
  • USDT contract → Can accept both USDT and LKR payments
  • LKR contract → Can accept both LKR and USDT payments
All payments are converted to USDT before being sent to the payment provider.

Slippage Protection for LKR Contracts

When creating an LKR contract, exchange rates may fluctuate between contract creation and payment execution. Slippage protection adds a buffer to handle these fluctuations. Example:
Contract: 1000 LKR with 100% slippage (10000 bps)
Exchange rate: 1 USDT = 330 LKR

Calculation:
1. Base conversion: 1000 LKR ÷ 330 = 3.03 USDT
2. Apply slippage: 3.03 USDT × (1 + 100%) = 6.06 USDT
3. Contract limit sent to Binance: 6.06 USDT

This allows:
- LKR payments up to ~2000 LKR (if rate stays at 330)
- USDT payments up to 6.06 USDT
Slippage in Basis Points:
  • 0 bps = 0% (no buffer)
  • 5000 bps = 50%
  • 10000 bps = 100%
  • 20000 bps = 200% (maximum)
Important Notes:
  • Slippage only applies to LKR contracts
  • USDT contracts do not use slippage (rejected if provided)
  • Slippage defaults to 0 if not specified for LKR contracts
  • Maximum allowed slippage is 20000 bps (200%)

Payment Validation

When executing a payment:
  1. Currency conversion: Payment amount is converted to USDT using current exchange rate
  2. Limit validation: Converted USDT amount must not exceed contract’s singleUpperLimit (which includes slippage buffer for LKR contracts)
  3. Error handling: If payment exceeds limit, request is rejected with clear error message showing the conversion
Example Error Response:
{
  "statusCode": 400,
  "message": "Payment 5000 LKR converts to 15.15 USDT, exceeding contract limit 6.06 USDT.",
  "error": "Bad Request"
}

Contract Status Reference

Direct Debit contracts have the following lifecycle statuses:
StatusDescription
INITIATEDContract created but not yet signed by user
SIGNEDUser has signed the contract (ready for payments)
TERMINATEDContract has been terminated
EXPIREDContract has expired

Webhooks

Set webhookUrl in your contract creation request to receive real-time contract and payment status updates. See Webhooks Guide for payload format, signature verification, and retry policy.

Error Responses

StatusErrorDescription
400Bad RequestInvalid request body or validation error
401UnauthorizedInvalid API key or signature
403ForbiddenContract belongs to another merchant
404Not FoundContract not found
429Too Many RequestsRate limit exceeded
See Error Codes for detailed error handling.