Webhooks
Get notified in real time when a farmer you have consent for changes — a new loan, a repayment, a policy, a claim, a harvest, or a credit‑score move. Webhook management is self‑serve and free.
Available events
Subscribe to any subset, or * for all:
| Event | Fires when |
|---|---|
farmer.loan_added |
A loan is recorded for the farmer |
farmer.loan_repaid |
A repayment is recorded |
farmer.loan_defaulted |
A loan is marked defaulted |
farmer.new_insurance_policy |
A policy is issued |
farmer.claim_filed |
A claim is filed |
farmer.claim_settled |
A claim is settled |
farmer.input_purchase |
An input purchase is recorded |
farmer.harvest_record |
A harvest is recorded |
farmer.credit_score_changed |
The farmer's credit score changes |
Register an endpoint
POST /v1/rupa/webhooks
| Field | Type | Required | Description |
|---|---|---|---|
url |
string (https) | yes | Your receiving URL. Must be HTTPS in live mode. |
events |
string[] | no | Events to subscribe to; ["*"] for all. Defaults to all. |
name |
string | no | A label |
curl -X POST https://api.riwe.io/v1/rupa/webhooks \
-H "X-API-KEY: rk_live_YOUR_SECRET" \
-H "Content-Type: application/json" \
-d '{
"url": "https://hooks.yourbank.com/riwe/rupa",
"name": "Prod receiver",
"events": ["farmer.loan_repaid", "farmer.credit_score_changed"]
}'
{
"success": true,
"message": "Webhook endpoint registered. Store the signing secret now — it will not be shown again.",
"data": {
"id": 12,
"url": "https://hooks.yourbank.com/riwe/rupa",
"subscribed_events": ["farmer.loan_repaid", "farmer.credit_score_changed"],
"signing_secret": "whsec_9f2b...<shown once>"
}
}
Important —
The
signing_secret(whsec_…) is returned once. Store it — you use it to verify delivery signatures. If lost, rotate it (below).
Verifying deliveries
Every delivery includes an HMAC signature header:
X-Rupa-Signature: <hex>
The value is HMAC‑SHA256(request_body, signing_secret). Recompute it over the raw
JSON body and compare, constant‑time. Example (Node):
const crypto = require('crypto');
function verify(rawBody, header, secret) {
const expected = crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(header));
}
Manage endpoints
| Method | Path | Purpose |
|---|---|---|
GET |
/v1/rupa/webhooks |
List your endpoints + available_events |
GET |
/v1/rupa/webhooks/{id} |
Show one endpoint |
PUT PATCH |
/v1/rupa/webhooks/{id} |
Update url, name, or events |
DELETE |
/v1/rupa/webhooks/{id} |
Delete an endpoint |
POST |
/v1/rupa/webhooks/{id}/rotate-secret |
Issue a new whsec_… (shown once) |
GET |
/v1/rupa/webhooks/{id}/deliveries |
Recent delivery attempts (status, timestamps) |
# Rotate the signing secret
curl -X POST https://api.riwe.io/v1/rupa/webhooks/12/rotate-secret \
-H "X-API-KEY: rk_live_YOUR_SECRET"
# Inspect recent deliveries (debug failures)
curl https://api.riwe.io/v1/rupa/webhooks/12/deliveries \
-H "X-API-KEY: rk_live_YOUR_SECRET" -H "Accept: application/json"
Best practices
- Respond
2xxquickly; do heavy work asynchronously. - Always verify
X-Rupa-Signaturebefore trusting a payload. - Be idempotent — a delivery may be retried.
- Use the
deliveriesendpoint to diagnose non‑2xxresponses.