Split
Bill an enterprise partner once and have Blitz split the payment across a roster of contractors or vendors on your behalf.
Create a Split
/api/commerce/integration/splitsRequires an API key with the split:write scope. Your company is the SME billing the named enterprise.
curl -X POST https://api.nest.useblitz.co/api/commerce/integration/splits \
-H "Authorization: Bearer bk_live_..." \
-H "Content-Type: application/json" \
-d '{
"enterpriseCompanyId": "co_...",
"apContactBusinessProfileId": "bp_...",
"clientIdempotencyKey": "unique-per-split",
"totalAmountCents": "10000",
"roster": [
{ "amountCents": "6000", "earlyPayoutElected": false, "contractorPaymentProfileId": "pp_..." },
{ "amountCents": "3500", "earlyPayoutElected": true, "autoWithdrawElected": true, "subVendorId": "sv_..." }
]
}'roster— 1 to 50 rows. Each row is exactly one ofcontractorPaymentProfileId(an existing creator/business),subVendorId(your own vendor roster), oremail(onboard someone brand new — see below).earlyPayoutElected(defaultfalse) — take an instant advance (fee deducted) once the Split funds, instead of waiting for a manual payout later.autoWithdrawElected(defaultfalse) — the moment this row's share settles, auto-forward it to the contractor's own active, verified wallet. If they have none, it simply lands as Blitz balance instead — never an error.businessCoversFee(defaultfalse) — your company (not the contractor) absorbs this row's early-payout fee, added on top of what's drawn from your own balance. Only meaningful for a row that actually takes an instant payout.totalAmountCents— optional. Must be at least the roster sum, and the difference (your margin) is capped at 20% of this total. Omit to bill exactly the roster sum (no margin). See Margin below for how it's released.clientIdempotencyKey— required. A repeated call with the same value against the same SME/Enterprise/AP-contact triple returns the existing Split instead of creating a duplicate.
Margin
Billing the Enterprise more than the roster sum (totalAmountCents minus the roster total, capped at 20% of totalAmountCents) declares your company's margin — but it isn't auto-credited. It's held once the Split funds, tracked by marginStatus on the response (NONE → PENDING → HELD → RELEASED), and released either by your own instant election or Blitz's scheduled net-terms auto-release. Both the instant election and the underlying POST :id/settle-margin call are session-only — not exposed to this API key — so subscribe to split.margin.settled (or poll marginStatus) rather than expecting to trigger it yourself.
Response shape
Every Split-returning call below (create, check status, revise roster, list) returns this shape as data — see Responses & Errors for the envelope it's wrapped in:
{
"id": "spl_...",
"smeCompanyId": "co_...",
"smeCompanyName": "Acme Talent Agency",
"enterpriseCompanyId": "co_...",
"enterpriseCompanyName": "Big Brand Inc.",
"enterpriseNetTermsDays": 30,
"apContactBusinessProfileId": "bp_...",
"legAPayoutId": "pay_...",
"totalAmountCents": "10000",
"marginAmountCents": "500",
"marginStatus": "PENDING",
"marginHoldStartedAt": null,
"marginReleasedAt": null,
"feeBufferAmountCents": "0",
"enterpriseCoversFee": false,
"enterpriseFeeAmountCents": "0",
"currency": "USD",
"status": "PENDING_APPROVAL",
"distributions": [
{
"id": "dist_...",
"contractorPaymentProfileId": "pp_...",
"subVendorId": null,
"contractorDisplayName": "Jordan Lee",
"creatorProfileId": "cr_...",
"amountCents": "6000",
"earlyPayoutElected": false,
"autoWithdrawElected": false,
"businessCoversFee": false,
"status": "PENDING",
"legBTransferPayoutId": null,
"legBWithdrawalPayoutId": null,
"feeAmountCents": null,
"netAmountCents": null,
"failureReason": null
}
],
"createdAt": "2026-08-24T18:02:11.482Z",
"updatedAt": "2026-08-24T18:02:11.482Z"
}status—PENDING_APPROVAL→APPROVED→FUNDED→SETTLING→SETTLED, orREJECTED/CANCELLED. Funding and payout afterAPPROVEDhappen automatically, server-side — there's no separate "release" call to make.legAPayoutId— the underlyingPayoutid for the Enterprise's bill, if you need to cross-reference it elsewhere.- Each
distributionsrow'sstatusis"PENDING"until its transfer starts, then the linked payout's own live status (e.g."COMPLETED"), or"FAILED"if the transfer attempt errored before a payout was even created — treat it as an opaque string, not a fixed enum.feeAmountCents/netAmountCentsare set once the row actually transfers. contractorDisplayNameandcreatorProfileIdare resolved for you server-side — useful for rendering a roster row without a separate lookup.creatorProfileIdisnullfor a business-profile contractor or an unresolved row.
Add a roster row by email
Set email (plus optional fullName) instead of contractorPaymentProfileId or subVendorIdto add a contractor who isn't on your roster yet, with no separate invite step:
{
"amountCents": "500",
"earlyPayoutElected": false,
"email": "new-contractor@example.com",
"fullName": "Jordan Lee"
}- Already a SubVendor on your own roster for that email? It's reused as-is.
- Already a real Blitz account for that email? A SubVendor is created and auto-attached to it immediately — no invite/accept step.
- No existing account at all? A brand-new, passwordless account is provisioned immediately and lands active right away.
Either way, the row resolves to a subVendorId server-side — the response reflects it the same as if you'd passed subVendorIdyourself. A contractor onboarded this way with no PayPal email on file still can't be elected for instant payout until one's added.
Check status
/api/commerce/integration/splits/:idSame API key scope. Only returns Splits your own company created.
Revise a pending roster
/api/commerce/integration/splits/:id/rosterSame API key scope. Only while status is PENDING_APPROVAL — replaces the entire roster.
curl -X PUT https://api.nest.useblitz.co/api/commerce/integration/splits/spl_.../roster \
-H "Authorization: Bearer bk_live_..." \
-H "Content-Type: application/json" \
-d '{
"totalAmountCents": "10500",
"roster": [
{ "amountCents": "6000", "earlyPayoutElected": false, "contractorPaymentProfileId": "pp_..." },
{ "amountCents": "4000", "earlyPayoutElected": true, "subVendorId": "sv_..." }
]
}'Body shape matches creation: roster (required, same row shape as above — including email) and totalAmountCents (optional, omit to bill exactly the new roster sum, same 20% margin cap as creation). This replaces the roster wholesale, not a partial patch.
List your Splits
/api/commerce/integration/splitsSame API key scope. Paginated — page (default 1), limit (default 20, max 100). Scoped to Splits your own company created.
Errors specific to Split
- 422 — a roster row's
contractorPaymentProfileIddoesn't resolve to an active creator's own payment profile, or itssubVendorIddoesn't belong to your own company. Also returned if a SubVendor row has no PayPal email on file and was elected for instant payout — add one to that SubVendor first. - 400 —
totalAmountCentswas supplied but is less than the roster sum, the margin it implies exceeds the 20% cap, or the roster sum is zero. - 404 (not 403) —
GET :id/PUT :id/rosteragainst a Split your API key's company doesn't own. Existence is never leaked across companies.
Skipping manual approval — auto-accept
By default, a Split you create through this API still waits for the named enterprise to approve it manually in their Blitz account, exactly like a Split created in the product. If an enterprise wants to skip that step for your company specifically, they can turn on auto-accept for you from their own Split settings — every Split you then create against them moves straight to approved and pays out automatically. This is entirely their decision; there's nothing for you to configure on your side.
Webhook events
Subscribe to these from your webhook endpoint instead of polling GET :id/GET in a loop. Every payload is intentionally thin — cross-reference the status endpoints above for the full current state (fees, net amounts, status, etc.).
split.leg_a.approved— the enterprise approved the Split (manually, or via auto-accept).split.leg_a.rejected— the enterprise rejected the Split.split.leg_a.claimed— your company's balance was credited the roster sum.split.roster_entry.settled— one roster row was transferred to its contractor (instant election or on-demand instant payout).split.roster_entry.failed— one roster row's transfer failed. Not something you retry yourself — it's independently retried server-side.split.margin.settled— your declared margin was released, either by your own instant election or the scheduled net-terms auto-release. See Margin above.
split.leg_a.* payloads carry { splitId, legAPayoutId }:
{
"splitId": "spl_...",
"legAPayoutId": "pay_..."
}split.roster_entry.* payloads carry { splitId, rosterEntryId }:
{
"splitId": "spl_...",
"rosterEntryId": "dist_..."
}split.margin.settled carries only { splitId }— there's no separate margin payout id to cross-reference; read marginAmountCents off GET :id instead:
{
"splitId": "spl_..."
}