Developer portal
Build on Keelstone
One REST API for accounts, payments, FX, and cards. Requests are idempotent by default, webhooks are signed, and the sandbox mirrors production behavior down to settlement timing — so the first payment you ship behaves like the millionth.
$ curl https://api.keelstone.example/v1/ping
Authentication
Every request is authenticated with a bearer key in the Authorization header. Keys are scoped per environment: mk_sandbox_ keys can never move real money, and mk_live_ keys require an approved workspace. Pin a release with the Keelstone-Version header — breaking changes only ship in new dated versions.
curl https://api.keelstone.example/v1/me \
-H "Authorization: Bearer mk_sandbox_4q9zr31kp7v2m8c5x0jw6t1d" \
-H "Keelstone-Version: 2026-05-01"Sandbox key generator
Mint a key shaped exactly like the real thing and use it while you read along. Keys generated here are decorative — demo only, never stored, and not valid against any API.
Payments
Create a payment with POST /v1/payments. Amounts are integers in minor units, and the platform picks the cheapest rail that meets your deadline unless you pin one. Send an Idempotency-Key with every create call — retries with the same key return the original payment instead of paying twice.
curl -X POST https://api.keelstone.example/v1/payments \
-H "Authorization: Bearer $KEELSTONE_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: ord-84312-payout" \
-d '{
"amount": 125000,
"currency": "EUR",
"beneficiary": "ben_8f2k1x",
"rail": "sepa_instant",
"reference": "Invoice INV-2041"
}'Treasury
Read balances across every currency account with GET /v1/balances. Each balance splits into available and pending, both in minor units, so your reconciliation never sees a float. Sweeps, yield allocations, and FX conversions live under the same /v1/treasury namespace.
curl "https://api.keelstone.example/v1/balances?currencies=USD,EUR,GBP" \
-H "Authorization: Bearer $KEELSTONE_API_KEY"Try it live
GET /api/v1/ping
This one is real: the button calls the demo API served by this site and prints the raw response below.
Webhooks
Subscribe an HTTPS endpoint to any event family and Keelstone pushes state changes to you. Every delivery carries a Keelstone-Signature header — an HMAC-SHA256 of the raw body with your per-endpoint secret. Verify it before trusting the payload, and always compare with a timing-safe function. Failed deliveries retry with exponential backoff for 72 hours.
# Register an HTTPS endpoint for the events you care about
curl -X POST https://api.keelstone.example/v1/webhook_endpoints \
-H "Authorization: Bearer $KEELSTONE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/hooks/keelstone",
"events": ["payment.completed", "payment.failed"]
}'Event catalog
Flip the toggles to sketch a subscription set — this table is a local simulation, nothing is saved.
| Event | Description | Status | Simulate |
|---|---|---|---|
payment.completed | A payment settled on the destination rail. | Subscribed | |
payment.failed | A payment was rejected; payload includes a machine-readable failure code. | Subscribed | |
payment.returned | Funds came back after settlement, for example a closed beneficiary account. | Off | |
invoice.paid | An issued invoice was reconciled against an incoming payment. | Off | |
invoice.overdue | An invoice passed its due date without full payment. | Off | |
treasury.sweep.executed | An automated sweep moved idle balance according to your treasury policy. | Off | |
card.authorization.created | A corporate card authorization is pending; respond within two seconds to approve or decline. | Off | |
payout.batch.settled | Every payment in a batch reached a terminal state. | Off |
Errors
Errors are conventional HTTP statuses with a structured JSON body: a stable type, a machine-readable code, a human-readable message, and a request_id you can quote to support. 4xx means fix the request; 5xx means retry with backoff and the same idempotency key.
curl -i https://api.keelstone.example/v1/payments/pay_unknown \
-H "Authorization: Bearer $KEELSTONE_API_KEY"
# HTTP/2 404
# {
# "error": {
# "type": "resource_missing",
# "code": "payment_not_found",
# "message": "No payment found with id pay_unknown.",
# "request_id": "req_7fk2m1qx"
# }
# }Ship it with confidence
Watch every rail and region on the live status page, or browse the FAQ for sandbox limits, webhook retries, and SDK release policy.