Disburs API · private beta
Private payroll rails with an operator built in.
Custodial wallets, USDC payouts on Stellar and a ledger that matches the chain, as a REST API. An agent proposes each run inside a policy you set, and zero-knowledge proofs let the chain verify every salary without ever learning one. Autonomous and private, without your product holding a key or an amount.
curl -X POST https://api.disburs.io/api/payments/pay \
-H "Content-Type: application/json" \
-b "session=…" \
-d '{
"contractorId": "a1b2c3d4-…",
"amount": "1200.00",
"memo": "March salary",
"idempotencyKey": "run-2026-03-kwabena"
}'{
"id": "5f9e1c2a-…",
"type": "PAYOUT",
"status": "SETTLED",
"amount": "1200.0000000",
"assetCode": "USDC",
"destination": "GCUBHDBN…LKRWW",
"memo": "March salary",
"txHash": "57dd5365…",
"createdAt": "2026-03-01T09:03:07Z"
}Autonomous by design
Not a payout API with a chatbot. An operator with an API.
Most payment APIs stop at “move money”. Disburs also decides what to move and why: the agent turns agreements and timesheets into a proposed run, the policy engine checks it, and only an authorized run reaches the rails. Your integration gets the outcome of that loop, not the burden of building it.
- 01
Agent proposes
Reads contracts and hours, drafts every line, clears routine exceptions. It never holds a key or a balance.
- 02
Policy validates
Spending limits, per-payee caps, new-wallet holds and raise thresholds are checked before anything is built.
- 03
Proof verifies
Right recipient, within budget, proven without exposing the amount. Zero-knowledge in Phase 4.
- 04
Human authorizes
Inside policy, a single approval. Outside it, the run waits for the person the rule names.
- 05
Rails execute
Native USDC payments on Stellar, one idempotent call each, every one on the ledger with its hash.
Private by proof
The chain verifies every salary. It never learns one.
A native Stellar payment is public, so privacy cannot be bolted on afterwards. Disburs adds a second settlement path: a shielded payroll pool where amounts are commitments and each payout carries a zero-knowledge proof that it is valid. Your integration keeps the same pay call; only the settlement changes. When an auditor needs the numbers, you hand them a view key, deliberately, instead of the whole ledger being open to everyone.
Honest limits: pool inflows and outflows stay visible in aggregate and timing leaks. Perfect anonymity is not the claim. Hiding individual salaries is.
- Public
Deposit
USDC enters the payroll pool contract. The aggregate inflow is visible on Stellar, as any deposit is.
- Private
Inside the pool
Salaries are commitments, not amounts. A payout is a proof that it is valid: right recipient, within budget. The number never appears.
- Edge
Claim
The payee claims with a proof and the amount is revealed only to them. Auditors get a view key, not the ledger.
POST /api/payments/pay # same call
{
"contractorId": "a1b2c3d4-…",
"amount": "1200.00", # never on-chain
"settlement": "shielded"
}
→ {
"status": "SETTLED",
"proof": "zk:0x9f3a…", # valid, proven
"commitment": "0x51c0…", # what the chain sees
"viewKey": "org auditors"
}Endpoints
The whole payroll loop, as endpoints.
Session-authenticated REST today. Everything marked live is in the OpenAPI spec now.
Payments
LivePay a payee from the organization treasury. A caller-supplied idempotency key means a retry returns the original payout instead of a second one.
- POST/api/payments/pay
- GET/api/payments
09:03:07 POST /api/payments/pay 201 PENDING a1b2c3d4 1200.00
09:03:07 stellar submit tx 57dd5365… sponsor-paid fee
09:03:11 stellar ledger 4888068 successful=true
09:03:11 ledger 5f9e1c2a PENDING → SETTLED
09:03:12 POST /api/payments/pay 201 SETTLED a1b2c3d4 1200.00 (same key, replayed)Onboarding
LiveCreate the paying org or the payee profile. A custodial wallet is provisioned and activated on completion.
- POST /api/onboarding/client
- POST /api/onboarding/contractor
- GET /api/contractors/lookup
Wallets
LiveBalances straight from Horizon, activation retry, and memo-aware USDC sends for exchange deposits.
- GET /api/me
- POST /api/me/activate
- POST /api/me/send
Payroll runs
Phase 1Roster and cadence, draft → approve → execute → reconcile, every line with a paid / failed status.
Webhooks
Phase 1payout.settled, payout.failed, wallet.activated, run.completed. Stop polling.
Agent SDK
Phase 3A typed, scoped client the agent uses to propose and reconcile runs. Never keys, never the chain.
Guardrails
Rails you can reason about.
Money-moving endpoints are built so the careless call and the malicious call both fail safely. Here is how that compares with the alternatives your team would otherwise wire up.
| Capability | Raw chain SDK | Bank wires | |
|---|---|---|---|
| Settlement time | ~4 seconds | Minutes to hours | 3–5 business days |
| Fee per payout | <$0.01 network + 0.5% | Network + spread | $25–45 + FX spread |
| Idempotent by default | |||
| Failures move no money | |||
| Custody handled for you | |||
| Ledger matches the chain | |||
| Policy engine before execution | |||
| Agent that proposes runs | |||
| Salary amounts off the public ledger | By proof (Phase 4) | Bank sees all |
Solutions
Who gets paid, and how.
Payroll & EOR platforms
Add USDC payouts to an existing product without becoming a crypto company. Onboard payees by email; pay the roster; hand your finance team a reconciled ledger.
Marketplaces & gig apps
Pay drivers, creators and freelancers across borders the moment work is accepted. Per-task amounts, memos for exchange deposits, withdrawal to any wallet or exchange.
Agents & automations
Give an agent a scoped client that proposes payouts a human authorizes. Idempotent by design, limited by policy, explained in plain English.
Quickstart
Four calls to a settled payout.
Everything here runs on testnet today with the same USDC issuer as mainnet, so what you test is what you ship.
- 01
Sign in
Magic link or Google. The session cookie is what every call below carries.
POST /api/auth/sign-in/magic-link { "email": "finance@acme.io", "callbackURL": "https://app.acme.io/auth/callback" } - 02
Onboard the payer and a payee
The org gets a treasury wallet; the contractor gets a payout wallet. Both are activated for you.
POST /api/onboarding/client { "company": "Acme", "country": "Kenya" } POST /api/onboarding/contractor { "name": "Kwabena Mensah", "country": "Ghana", "payoutCurrency": "GHS" } - 03
Fund the treasury
Send USDC on Stellar to the treasury address from any wallet or exchange. On testnet, use Circle’s faucet.
GET /api/me → organization.treasuryWallet.publicKey "GBJAZAZF…OJUIY" → balances.usdc "10.0000000" - 04
Pay
One idempotent call. Poll the ledger or, from Phase 1, receive payout.settled.
POST /api/payments/pay { "contractorId": "a1b2c3d4-…", "amount": "2.50", "idempotencyKey": "task-8812" } → { "status": "SETTLED", "txHash": "57dd5365…" }
Pricing
Free to build. Pay when money moves.
No platform fee for the API itself. The flat 0.5% per payout is the same rate the payroll product charges; Stellar’s network fee is passed through at cost.
| Developer | Builder | Enterprise | |
|---|---|---|---|
| Price | $0 | 0.5% per payout | Custom |
| Network | Testnet | Mainnet | Mainnet |
| Payouts | Unlimited test USDC | Pay as money moves | Volume pricing |
| Ledger | Included | Included | Included |
| Webhooks | Phase 1 | Phase 1 | Phase 1 |
| Policy engine | Defaults | Your limits and thresholds | Custom approvals and roles |
| Support | Community | Dedicated, with SLA | |
| Get testnet access | Request access | Talk to us |
Questions, answered plainly.
How the API and the agent behave when money is involved, in plain words.
The REST endpoints for onboarding, wallets, payments and the ledger are live and documented in the OpenAPI spec. Payroll runs and webhooks land in Phase 1; the agent SDK in Phase 3. Access is by request while we are in private beta.
Today with the same cookie session the web app uses, issued by magic link or Google. API keys for server-to-server use arrive with the SDK.
Yes. Point at testnet, fund a treasury from Circle's faucet and every call behaves exactly as on mainnet, down to the same USDC issuer.