Flexysure Open API
Quote, bind, collect by M-Pesa, issue DMVIC certificates, finance premiums and receive signed webhooks from your own systems.
The Open API is how agency portals, core banking systems, comparison sites and ERPs work with an organisation on Flexysure. Everything a broker does on screen has an endpoint: price a risk across underwriters, save the quote as a policy, send an M-Pesa prompt, issue the motor certificate, offer premium finance, log a prospect or a claim, send an SMS, and give customers their own client area.
Requests and responses are JSON over HTTPS. Money is sent in whole shillings (amount) and returned in shillings plus integer cents (amount_minor). Every response carries an X-Request-Id header; quote it when you contact us.
Base URL
https://flexysure.intrepidprojects.co.ke/api/v1
Version
v1
Endpoints
97
Endpoint groups
Versioning
The version is in the path: /api/v1. Changes within v1 are additive: new endpoints, new optional request fields, new response fields and new webhook events, so build your client to ignore fields it does not know. A change that would break an integration would ship under a new version path. Every release is listed on the changelog.
Authentication
An administrator creates an API client on Settings → API keys, chooses its scopes and copies the secret, which is shown once. Your system exchanges the client id and secret for a bearer token with the OAuth2 client-credentials grant, then sends the token on every call. Tokens last 24 hours; request a new one when a call returns 401.
-
1. Get a token
POST /oauth/token cURL curl -X POST 'https://flexysure.intrepidprojects.co.ke/api/v1/oauth/token' \ -H 'Content-Type: application/json' \ -d '{ "grant_type": "client_credentials", "client_id": "<your client_id>", "client_secret": "<your client_secret>", "scope": "read quote bind pay" }'Response JSON { "access_token": "e3mT…48 characters…", "token_type": "Bearer", "expires_in": 86400, "scope": "read quote bind pay" } -
2. Call the API with it
GET /insurers cURL curl 'https://flexysure.intrepidprojects.co.ke/api/v1/insurers' \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -H 'Accept: application/json'
The token endpoint also accepts a form body, HTTP Basic client authentication, and the body {"key": "…", "passkey": "…"} for systems moving from Insurance Cloud. It allows 10 attempts a minute per IP address. See Authentication for every response.
Scopes
A client is allowed a set of scopes; a token carries all of them or the subset you ask for in scope. * grants every scope. A call outside the token's scopes returns 403 insufficient_scope.
| Scope | Grants | Endpoints |
|---|---|---|
| read | Read reference data, policies, receipts and other records | 23 |
| quote | Price motor, medical, travel and standard products | 6 |
| bind | Save quotes and issue policies | 7 |
| pay | Start M-Pesa payments and read payment status | 5 |
| certificate | Issue, fetch and cancel DMVIC motor certificates | 7 |
| finance | Premium finance: offers, applications, loans and repayments | 9 |
| crm | Prospects and clients | 6 |
| claims | Register and track claims | 3 |
| messaging | Send SMS and read the outbox | 4 |
| portal | Client area on behalf of a customer | 11 |
| webhooks | Register webhook endpoints and read deliveries | 7 |
Idempotency
Writes that create records, move money or change cover (saving a quote or policy, an STK push, a certificate, a claim, an SMS batch) require an Idempotency-Key header: a unique value such as a UUID that you generate per operation. If the connection drops, send the same request with the same key. We return the first response again with Idempotent-Replayed: true instead of doing the work twice.
The same key with a different body is refused with 422 idempotency_key_reused; a missing key is 400 idempotency_key_required. Keys are remembered for 24 hours per API client. Each endpoint's page says whether it needs one.
curl -X POST 'https://flexysure.intrepidprojects.co.ke/api/v1/payment/stk/push' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H 'Idempotency-Key: 7c9e6679-7425-40de-944b-e07fc1f90ae7' \
-H 'Content-Type: application/json' \
-d '{"account": "DN-000123", "phone": "0712345678", "amount": 30175}'
Errors
Every error is an RFC 9457 problem document with content type application/problem+json: type, title, status, detail, a machine-readable code, the request id as instance and, for validation failures, errors by field. Branch on code, not on the wording of detail.
{
"type": "https://flexysure.com/problems/validation_failed",
"title": "Validation failed",
"status": 422,
"detail": "The vehicle.year field is required.",
"code": "validation_failed",
"instance": "9b1d0c4e-2f3a-4b5c-8d6e-7f8091a2b3c4",
"errors": {
"vehicle.year": [
"The vehicle.year field is required."
]
}
}
| Status | Code | When |
|---|---|---|
| 400 | idempotency_key_required | A write that needs an Idempotency-Key was sent without one. |
| 401 | unauthenticated | No bearer token, or it expired or was revoked. |
| 401 | invalid_client | Wrong client id or secret on the token endpoint. |
| 403 | insufficient_scope | The token does not carry the scope the endpoint needs. |
| 403 | agent_denied | X-Agent-Code and X-Agent-Key do not match an agent of the organisation. |
| 404 | not_found | No such record, or it belongs to another organisation or agent. |
| 422 | validation_failed | The body failed validation; errors lists the messages by field. |
| 422 | idempotency_key_reused | The same Idempotency-Key was sent with a different body. |
| 429 | rate_limited | Too many requests; wait for Retry-After seconds. |
| 500 | server_error | Something failed on our side. Quote the instance (request id) to support. |
Pagination
Lists that can grow are paginated with an opaque cursor: pass limit (1–100, default 25) and follow links.next until it is null. Cursors stay correct while new records arrive. The same lists also accept Insurance Cloud style page and per_page, which add total and last_page; prefer the cursor for large exports.
{
"data": [
"\u2026"
],
"meta": {
"limit": 25,
"has_more": true,
"count": 25
},
"links": {
"next": "https://flexysure.intrepidprojects.co.ke/api/v1/claims?limit=25&cursor=eyJpZCI6MTIwfQ"
}
}
{
"data": [
"\u2026"
],
"meta": {
"page": 2,
"per_page": 50,
"total": 312,
"last_page": 7
},
"links": {
"next": "https://flexysure.intrepidprojects.co.ke/api/v1/erp/policies?page=3&per_page=50",
"prev": "https://flexysure.intrepidprojects.co.ke/api/v1/erp/policies?page=1&per_page=50"
}
}
Rate limits
Limits are per minute. Over the limit you get 429 rate_limited with a Retry-After header in seconds. Each endpoint lists its own limit.
| What | Limit |
|---|---|
| Every endpoint (default) | 60 requests a minute per token, unless a different limit is set on the API client |
| Token endpoint | 10 requests a minute per IP address |
| ERP record lists | 5 requests a minute per client |
| Client area details, policies and policy | 5 requests a minute per client |
| Client area statement | 10 requests a minute per client |
Agent headers
One API client can act for many agents. Send X-Agent-Code and X-Agent-Key (set on the agent's profile) and the call runs as that agent: quotes and policies are recorded against them, and lists only show their own clients and policies. Without the headers the call runs with the API client's own visibility. A code and key that do not match return 403 agent_denied. Endpoints that accept the headers say so.
curl -X POST 'https://flexysure.intrepidprojects.co.ke/api/v1/motor/quote' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H 'Accept: application/json' \
-H 'X-Agent-Code: KK01' \
-H "X-Agent-Key: $AGENT_KEY" \
-H 'Content-Type: application/json' \
-d '{
"class": "Motor",
"coverage": "Private",
"scope": "Comprehensive",
"cover_period": "annual",
"year": 2018,
"value": 1000000,
"pll": 4,
"insurer_id": [
1,
2
]
}'
Migrating from Insurance Cloud
46 endpoints keep the paths, field names and response shapes of Insurance Cloud's Open API v1.0, so an existing integration moves over by changing the base URL and the credentials. The token endpoint accepts the key and passkey body, and paginated lists accept page and per_page.
The other 51 are additions, marked Flexysure only throughout these docs: scoped tokens, idempotent writes, policy endorsement and cancellation, payment status, premium finance, claims writes, webhooks and more.
Webhooks are new: subscribe to events instead of polling for payments, activations and certificates.