Sharet API docs
Collect from customers, pay anyone, split a payment and settle in batches, in Kenyan shillings, through one API. Every account has a fixed Sharet ID and every settlement is tied to it.
https://sharet.africa/api/v1 · JSON in, JSON out · amounts are strings like "1500.00" · currency KES · fiat only.
Quickstart
- Create a sandbox key (
sk_test_…) in Developers › API keys and give it the scopes you need. - Check it works:
- Pay someone in the sandbox (no real money moves):
When you're ready, verify your business and create a live key (sk_live_…) with your servers' IP addresses.
Sharet IDs and @names
Every person and business has a Sharet ID, like SH-4K7Q2M. It never changes and is never reused, and every settlement, webhook and statement is tied to it. An @name (like @mwangihardware) is the alias people see and type; you can send it, and we always resolve it to the Sharet ID and return that. Renaming an @name never redirects money.
Names come back shortened (Akinyi W.) so lookups can't be used to collect people's full names. GET /accounts/me returns your own Sharet ID, @name, verification level, balance and the key's scopes.
Keys, scopes and IPs
Send your key as Authorization: Bearer sk_…. A business's keys act for the business's own Sharet wallet; we keep only a fingerprint, so copy a key when it's shown.
| Scope | Lets the key |
|---|---|
read | Look things up (every key has it) |
collect | Create and cancel payment requests |
payout | Send payments and batches, retry splits |
connect | Ask people to connect their accounts |
- Sandbox and live are separate.
sk_test_keys never move real money;sk_live_keys need a verified business. - Live payouts need an IP allow-list: list your servers' addresses or ranges on the key. Calls from anywhere else get
ip_not_allowed. - Large batches need a second person: live batches over KES 500,000 wait in Dashboard › API approvals for someone else from your business.
Requests and retries
- Idempotency: every call that moves money (and creating a payment request) takes an
Idempotency-Keyheader, 8–80 characters, one per payment. Retrying with the same key returns the first answer (withIdempotent-Replay: true) and never pays twice. Refusals aren't remembered, so you can fix the problem and retry with the same key. - Amounts are strings with two decimals and no separators, in whole shillings:
"35000.00". - Errors are
application/problem+jsonwith a stabletype; see Errors. - Sandbox and live data are separate: a key only sees objects from its own environment.
- Pauses: if Sharet pauses payments for safety, money calls answer
423; nothing moves and you can retry later.
Quotes
See the exact fee and total before paying. Nothing moves.
Destinations (to): {"sharet_id": "SH-…"} or {"handle": "@name"} (free and instant), {"type": "mpesa"|"airtel"|"tkash", "phone": "0722 000 904"}, {"type": "till", "till": "512334"}, {"type": "paybill", "paybill": "247247", "account": "…"}, {"type": "bank", "bank": "equity", "account": "…"} (PesaLink; banks: equity, kcb, ncba, imbank, coop, absa, stanbic, family).
Payments out
POST /payments (scope payout, Idempotency-Key) pays from your account's wallet. The response includes the fee, total and status: paid straight away for Sharet accounts, paying while M-PESA or the bank works, then paid, failed or refunded (a failed payout's money comes back to your wallet). Follow it with GET /payments/{id} or a webhook.
Payment requests
POST /payment-requests (scope collect, Idempotency-Key) asks someone to pay you and returns a pay link (pay_url). They pay from their Sharet wallet (signed in, with their PIN, free) or by an M-PESA prompt to any phone. The money lands in your wallet. No call can take money from someone's wallet without them approving it.
If you name a payer, only that Sharet account can pay from a wallet. GET /payment-requests/{id} shows the status (open, paid, expired, cancelled); POST /payment-requests/{id}/cancel closes it.
Split settlement
Add splits to a payment request and, once it's paid, every leg is paid from your wallet to the recipients' Sharet IDs together or not at all. Legs are percentages or fixed amounts in whole shillings; what isn't in a leg (your "self" share and rounding) stays with you.
Legs go to Sharet accounts only (up to 10, each account once). If a leg can't be paid, none are, the money stays in your wallet and settlement.failed says why; fix it and retry with POST /payment-requests/{id}/settle.
Batch settlements
POST /settlements (scope payout, Idempotency-Key) pays up to 500 items in one call. Every item is checked first: if any is wrong, nothing is paid and errors lists them by index. Each item is then paid like POST /payments; a refused item is recorded as failed without stopping the others.
Live batches over KES 500,000 return 202 awaiting_approval and run once a different person from your business approves them in Dashboard › API approvals.
Connected accounts
Platforms (like a property manager) can collect and settle for their users, in their users' own Sharet accounts, with their consent.
POST /connect/links(scopeconnect) with{"scopes": ["collect", "payout"], "reference": "landlord-17", "return_url": "https://…"}returns a link, valid 7 days.- The person opens it, signs in, reads exactly what you may do, and approves with their PIN (or declines). They come back to your
return_urlwith?connection=…&status=active. - Act for them by adding
Sharet-Account: SH-…to your calls, only within what they approved; their own limits apply. Sharet ↔ Sharet is free; sending outside Sharet is charged. - List them with
GET /connect/accounts; either side can disconnect at any time (POST /connect/accounts/{id}/disconnect, or Account › Connected apps).
Webhooks
Register an endpoint with POST /webhooks {"url": "https://…", "events": [...]}; the response includes a whsec_… secret, shown once. Events: payment.paid, payment.failed, payment.refunded, payment_request.paid, payment_request.expired, settlement.completed, settlement.failed, settlement.awaiting_approval, account.connected, account.disconnected.
Every delivery is signed. Check the signature before trusting it, ignore repeats by id, answer 2xx quickly, and confirm with a GET when it matters. We retry for 24 hours.
Errors
Errors are application/problem+json: {"type": "https://sharet.africa/docs/errors#…", "title": "…", "status": 422, "detail": "…"}, sometimes with errors by field. Use type in your code; show detail to people.
| type | Status | Meaning |
|---|---|---|
invalid_api_key | 401 | The key is missing, wrong or switched off. |
missing_scope | 403 | The key doesn't have the scope this call needs. Add it under Access in Developers › API keys. |
ip_allow_list_required | 403 | A live key needs its server addresses listed before it can pay out. |
ip_not_allowed | 403 | This live key pays out only from its listed addresses. The response says which IP we saw. |
business_not_verified | 403 | Live money needs a verified business. Use a sk_test_ key meanwhile. |
not_connected | 403 | The Sharet-Account you sent hasn't connected to your business, or has disconnected. |
not_allowed_by_account | 403 | The connected person didn't allow this (e.g. you asked to pay out, they allowed only collect). |
not_an_approver | 403 | Batches must be approved by a different person from the same business. |
account_not_found | 404 | No Sharet account has that @name or Sharet ID. |
payment_not_found | 404 | No payment with that id for this key's account and environment. |
payment_request_not_found | 404 | No payment request with that id for this key's account and environment. |
settlement_not_found | 404 | No settlement with that id for this key's account and environment. |
webhook_not_found | 404 | No webhook endpoint with that id. |
connection_not_found | 404 | No connection with that id. |
idempotency_key_reused | 409 | That Idempotency-Key was used for a different request. |
in_progress | 409 | The first request with this Idempotency-Key is still running. Try again shortly. |
idempotency_key_required | 428 | Money calls need an Idempotency-Key header (8–80 characters). |
invalid_amount | 422 | Amounts are strings in whole shillings, at least KES 10, e.g. "1500.00". |
destination_required | 422 | Send "to" with a sharet_id, a handle, or a type. |
invalid_destination | 422 | The phone, till, paybill or bank details aren't valid. "errors" says which field. |
own_account | 422 | You can't pay or request from your own account. |
payment_refused | 422 | The payment engine refused it: not enough money, over a limit, or payouts paused. "detail" explains. |
invalid_items | 422 | Some batch items need fixing; nothing was paid. "errors" lists them by index. |
invalid_splits | 422 | The split legs don't add up, repeat an account, or are out of range. |
outside_split_not_available | 422 | Split legs go to Sharet accounts only; recipients can send outside themselves. |
invalid_payer | 422 | The payer's phone isn't a valid Kenyan mobile number. |
invalid_channels | 422 | channels must be "sharet", "mpesa" or both. |
invalid_scopes | 422 | Connect links ask for "collect", "payout" or both. |
invalid_return_url | 422 | return_url must be a public https:// address. |
invalid_webhook_url | 422 | Webhook URLs must be public https:// addresses. |
Sandbox
- Use
sk_test_keys: same endpoints, simulated money, nothing touches real balances. - The M-PESA number
0700 000 002always fails; every other destination succeeds. - Sandbox pay links show Simulate paid and Simulate cancel buttons.
- Webhooks fire in the sandbox too, to endpoints registered with a test key.
Pricing
Sharet ↔ Sharet is always free, including splits and connected accounts. Outside payouts are priced from two tables: a fee by movement type and amount, then a discount by your outside payouts this month. Every quote and payment shows the fee, the tariff version and your discount before money moves. Sharet's own companies are priced one tier up.
Limits
- 60 requests a minute per key to start; batches up to 500 items; splits up to 10 legs.
- Payment limits follow the paying account's verification: verified businesses have business limits; connected people keep their own.
- Kenyan shillings only for now; Tanzania is next after the Kenya pilot.
Questions? Talk to us, or request sandbox access.
Payments for Kenya and East Africa. Nairobi.
Sharet Africa Ltd is not a bank. Payment services are provided with Cashia (Kashia Services Limited), licensed by the Central Bank of Kenya as a payment service provider. Check on CBK's licensed directory
Customer money is held in a separate trust account. Fees, rates and limits are shown in the app before you confirm.