Chains API (Marketplace)
The Chains API enables marketplace and platform businesses to split payments between platform and merchants. Build multi-party payment flows with automated commission handling.
Available Endpoints
- Create Charge Chain - POST /charges (with destination)
- Create Transfer Chain - POST /transfers (with merchant_id)
- List Chains - GET /chains
- Retrieve Chain Transfer - GET /chains/:id/transfer
Overview
Chains (also called Omise Link) enable:
- Split payments - Automatically split between platform and merchants
- Commission handling - Deduct platform fees before merchant payout
- Multi-merchant charges - Charge customer and distribute to multiple recipients
- Marketplace flows - Build Uber, Airbnb, Shopify-style payment flows
- Transparent tracking - Track entire payment chain from charge to transfer
How Chains Work
- Customer pays - Charge created with destination (recipient)
- Platform receives - Full amount goes to platform account
- Commission deducted - Platform fee is automatically calculated
- Merchant receives - Remaining amount transferred to recipient
- Chain tracked - Entire flow linked via chain ID
Prerequisites
- Chain-enabled account - Contact Omise to enable marketplace features
- Verified recipients - Recipients must be verified before receiving transfers
- KYC compliance - Recipients complete identity verification
Authentication
All Chains API endpoints require authentication using your secret key.
Commission Calculation
Platform fees can be specified as fixed amounts and/or percentages:
Fixed Commission
{
"platform_fee": {
"fixed": 50000
}
}
Deducts ฿500.00 (50,000 satang) from merchant payout.
Percentage Commission
{
"platform_fee": {
"percentage": 10.5
}
}
Deducts 10.5% from merchant payout.
Combined Commission
{
"platform_fee": {
"fixed": 10000,
"percentage": 5
}
}
Deducts ฿100 + 5% from merchant payout.
Calculation Example
Charge Amount: ฿10,000 (1,000,000 satang) Platform Fee: ฿100 fixed + 5% = ฿100 + ฿500 = ฿600 Merchant Receives: ฿10,000 - ฿600 = ฿9,400
Implementation Example
Creating a Chain Charge
// Node.js example
const charge = await omise.charges.create({
amount: 1000000, // ฿10,000
currency: 'thb',
card: 'tokn_test_123',
description: 'Order #1234 - Platform Marketplace',
// Destination merchant
destination: {
amount: 950000, // ฿9,500 (after ฿500 platform fee)
recipient: 'recp_test_merchant_456'
},
// Platform fee
platform_fee: {
fixed: 50000 // ฿500
},
metadata: {
order_id: '1234',
merchant_id: 'merchant_456',
customer_email: 'customer@example.com'
}
});
console.log('Chain ID:', charge.id);
console.log('Status:', charge.status);
Important Notes
- destination.amount must be less than or equal to charge amount minus platform fee
- Total of destination amounts cannot exceed charge amount
- Platform fee is deducted from the destination amount
- Funds are held in platform account until transfer is initiated
Chain Status Lifecycle
Chains progress through these stages:
- Charge Created - Customer payment processed
- Charge Successful - Payment confirmed
- Transfer Pending - Waiting for transfer schedule
- Transfer Created - Transfer to merchant initiated
- Transfer Sent - Funds sent to recipient's bank
- Transfer Paid - Merchant received funds
Multiple Recipients
You can split payments to multiple merchants:
{
amount: 1000000, // ฿10,000
destinations: [
{
amount: 400000, // ฿4,000 to merchant A
recipient: 'recp_test_merchant_a'
},
{
amount: 350000, // ฿3,500 to merchant B
recipient: 'recp_test_merchant_b'
}
],
platform_fee: {
fixed: 250000 // ฿2,500 platform keeps
}
}
Webhook Events
Monitor chain progress with webhooks:
charge.complete- Customer payment successfultransfer.create- Merchant transfer initiatedtransfer.sent- Funds sent to merchanttransfer.paid- Merchant received funds
Error Handling
| Error | Description | Solution |
|---|---|---|
chain_not_enabled | Account not enabled for chains | Contact support to enable |
invalid_destination | Recipient not found or inactive | Verify recipient exists and is active |
destination_amount_exceeds_charge | Destination sum > charge amount | Reduce destination amounts |
insufficient_balance | Not enough balance for transfer | Charge must complete before transfer |
Best Practices
1. Verify Recipients First
Ensure all recipients are verified before creating chain charges:
const recipient = await omise.recipients.retrieve('recp_test_123');
if (recipient.verified === false) {
throw new Error('Recipient not verified');
}
2. Use Metadata for Tracking
Store order and merchant details:
{
"metadata": {
"order_id": "ord_123",
"merchant_id": "merch_456",
"commission_rate": "5%"
}
}
3. Handle Failed Transfers
Not all transfers will succeed. Monitor webhooks and retry if needed:
if (transfer.status === 'failed') {
// Log failure reason
console.error('Transfer failed:', transfer.failure_code);
// Notify merchant
await notifyMerchant(transfer.recipient, transfer.failure_message);
}
4. Reconcile Daily
Match charges to transfers daily for accurate accounting:
- List all chains for a date range
- Verify each charge has corresponding transfer
- Track commission totals
Limitations
- Minimum transfer amount: ฿20 (2,000 satang)
- Maximum recipients per charge: 10
- Platform fee cannot exceed charge amount
- Recipients must have verified bank accounts
- Transfers follow standard settlement schedule (7 days Thailand, 21 days Japan)
Related Resources
- Recipients API - Create and manage merchant recipients
- Transfers API - Manual transfer operations
- Marketplace Guide - Complete marketplace implementation