coal
coal

Revenue Splits

Revenue Splits let you automatically distribute a payment to multiple wallet addresses in exact proportions — all on-chain, at settlement time. No manual transfers, no reconciliation spreadsheets.

Coal calculates each recipient's share using BigInt arithmetic (no floating-point rounding errors) and sends each portion in the same settlement transaction.

Splits are useful anywhere revenue needs to be shared: creator + platform royalties, affiliate commissions, DAO treasury contributions, multi-founder splits, and more.

Console split configuration uses Privy Bearer auth. Public checkout creation still uses x-api-key on /api/checkouts.


How It Works

When a checkout session with a split config is confirmed:

  1. Coal receives the full payment from the customer.
  2. The split config is looked up.
  3. Each recipient's share is calculated: floor(totalAmount * percent / 100) using integer arithmetic.
  4. Rounding dust (the difference from summing all shares) is assigned to the first recipient.
  5. A single on-chain transaction fans out to all recipient addresses simultaneously.

The Recipient Object

typescript
1interface SplitRecipient {
2 address: string; // EVM wallet address
3 percent: number; // Integer 1–99; all percents must sum to exactly 100
4 label?: string; // Optional human-readable label (stored for your records)
5}

Validation rules:

  • Percents must be positive integers (no decimals).
  • All percents must sum to exactly 100.
  • Maximum 10 recipients per split config.
  • Each address must be a valid EVM address (checksummed or lowercase).

Creating a Split Config

POST /api/console/splits

bash
1curl -X POST https://api.usecoal.xyz/api/console/splits \
2 -H "Content-Type: application/json" \
3 -H "Authorization: Bearer <privy_access_token>" \
4 -d '{
5 "name": "70/30 Creator Split",
6 "recipients": [
7 { "address": "0xCreator1234567890abcdef1234567890abcdef12", "percent": 70, "label": "Creator" },
8 { "address": "0xPlatform1234567890abcdef1234567890abcdef", "percent": 30, "label": "Platform" }
9 ]
10 }'

Response

json
1{
2 "id": "spl_clx9abc123def456",
3 "name": "70/30 Creator Split",
4 "recipients": [
5 { "address": "0xCreator1234567890abcdef1234567890abcdef12", "percent": 70, "label": "Creator" },
6 { "address": "0xPlatform1234567890abcdef1234567890abcdef", "percent": 30, "label": "Platform" }
7 ],
8 "createdAt": "2026-03-22T12:00:00.000Z"
9}

CRUD Operations

List all split configs

bash
1curl https://api.usecoal.xyz/api/console/splits \
2 -H "Authorization: Bearer <privy_access_token>"

Get a single split config

bash
1curl https://api.usecoal.xyz/api/console/splits/spl_clx9abc123def456 \
2 -H "Authorization: Bearer <privy_access_token>"

Update a split config

bash
1curl -X PUT https://api.usecoal.xyz/api/console/splits/spl_clx9abc123def456 \
2 -H "Content-Type: application/json" \
3 -H "Authorization: Bearer <privy_access_token>" \
4 -d '{
5 "name": "80/20 Creator Split",
6 "recipients": [
7 { "address": "0xCreator1234567890abcdef1234567890abcdef12", "percent": 80, "label": "Creator" },
8 { "address": "0xPlatform1234567890abcdef1234567890abcdef", "percent": 20, "label": "Platform" }
9 ]
10 }'

Delete a split config

bash
1curl -X DELETE https://api.usecoal.xyz/api/console/splits/spl_clx9abc123def456 \
2 -H "Authorization: Bearer <privy_access_token>"

Deleting a split config does not affect past payments. Sessions already confirmed with this split are unaffected.


Attaching a Split to a Checkout Session

Pass the splits field when creating a checkout session. You can reference a saved split config by ID, or define recipients inline for a one-off split.

By saved split ID

bash
1curl -X POST https://api.usecoal.xyz/api/checkouts \
2 -H "Content-Type: application/json" \
3 -H "x-api-key: coal_live_..." \
4 -d '{
5 "amount": 100.00,
6 "description": "NFT Mint — Issue #42",
7 "redirectUrl": "https://yoursite.com/success",
8 "splits": {
9 "configId": "spl_clx9abc123def456"
10 }
11 }'

Inline (one-off)

bash
1curl -X POST https://api.usecoal.xyz/api/checkouts \
2 -H "Content-Type: application/json" \
3 -H "x-api-key: coal_live_..." \
4 -d '{
5 "amount": 50.00,
6 "description": "Affiliate Sale",
7 "redirectUrl": "https://yoursite.com/success",
8 "splits": {
9 "recipients": [
10 { "address": "0xMerchant...", "percent": 90, "label": "Merchant" },
11 { "address": "0xAffiliate...", "percent": 10, "label": "Affiliate" }
12 ]
13 }
14 }'

Amount Calculation

Coal uses BigInt arithmetic throughout to avoid floating-point precision issues common with stablecoin amounts.

typescript
1// Internal implementation (TypeScript pseudocode)
2function calculateShares(
3 totalAmountRaw: bigint, // e.g. 100_000_000n for 100.00 units at 6 decimals
4 recipients: { percent: number }[]
5): bigint[] {
6 const shares = recipients.map(r =>
7 (totalAmountRaw * BigInt(r.percent)) / 100n
8 );
9
10 // Assign rounding dust to the first recipient
11 const distributed = shares.reduce((sum, s) => sum + s, 0n);
12 const dust = totalAmountRaw - distributed;
13 shares[0] += dust;
14
15 return shares;
16}
17
18// Example: 100 units split 70/30
19// totalAmountRaw = 100_000_000n
20// shares = [70_000_000n, 30_000_000n]
21// distributed = 100_000_000n, dust = 0n ✓
22
23// Example: 99.99 units split 70/30
24// totalAmountRaw = 99_990_000n
25// floor(99_990_000 * 70 / 100) = 69_993_000n
26// floor(99_990_000 * 30 / 100) = 29_997_000n
27// distributed = 99_990_000n, dust = 0n ✓

Payments always fully clear — no settlement-token value is left stranded due to rounding.


Webhook Payload with Splits

When a session with a split confirms, the checkout.confirmed webhook includes a splits array showing the exact amount each recipient received:

json
1{
2 "event": "checkout.confirmed",
3 "id": "evt_clx7k2p3q0000abc12345",
4 "timestamp": "2026-03-22T12:00:00.000Z",
5 "data": {
6 "sessionId": "clx7k2p3q0000abc12345",
7 "merchantId": "clx1mer0h0000xyz98765",
8 "amount": "100.00",
9 "currency": "USDC",
10 "status": "confirmed",
11 "txHash": "0xabc123...",
12 "splits": [
13 { "address": "0xCreator...", "label": "Creator", "amount": "70.00" },
14 { "address": "0xPlatform...", "label": "Platform", "amount": "30.00" }
15 ],
16 "metadata": {}
17 }
18}

Common Split Configurations

Creator + Platform

json
1[
2 { "address": "0xCreator...", "percent": 80, "label": "Creator" },
3 { "address": "0xPlatform...", "percent": 20, "label": "Platform" }
4]

Three-way affiliate

json
1[
2 { "address": "0xMerchant...", "percent": 85, "label": "Merchant" },
3 { "address": "0xAffiliate...", "percent": 10, "label": "Affiliate" },
4 { "address": "0xTreasury...", "percent": 5, "label": "DAO Treasury" }
5]

Equal co-founder split

json
1[
2 { "address": "0xFounderA...", "percent": 50, "label": "Founder A" },
3 { "address": "0xFounderB...", "percent": 50, "label": "Founder B" }
4]