API Documentation

Base URL: https://api.Remsara.site. All responses are JSON. Endpoints marked 🔒 require Authorization: Bearer <token> from the verify or login call.

Authentication

OTP-first accounts

POST /auth/registeremail, phone. Sends a 6-digit WhatsApp/SMS code. Calling again for an existing account resends the code.
POST /auth/verifyemail, phone, otp. Activates the account, returns { token } (JWT, 7-day expiry).
POST /auth/loginemail, password. For accounts registered with a password.
# register then verify
POST /auth/register  { "email": "you@corp.com", "phone": "+254700000000" }
POST /auth/verify    { "email": "...", "phone": "...", "otp": "123456" }
→ { "token": "eyJhbGci...", "activated": true }
Sandbox notice: while OTP_DEV_MODE=true, register and resend responses include dev_code so you can self-complete verification. This field disappears in production OTP delivery.

Membership

Trial, cooling, activation — £10/month

30-day free trial → 3-day cooling period → £10/month charged in advance. Cancel anytime before billing. The 1% payout fee applies from day one.

POST /membership/signupemail. Starts the trial clock. Idempotent.
GET /membership?email=Returns derived status (trial | cooling | active | cancelled | none), days_left, reference, renewal date.
POST /membership/cancelemail. Cancels; no further membership fees.
POST /membership/payment 🔐email + header X-Admin-Key. Operator confirms fee receipt → activates until next renewal (+30 days).
GET /membership?email=you@corp.com
→ { "status": "trial", "days_left": 27, "reference": "PC-A0A96F59", ... }

Hosted at https://membership-status-Remsara.fbirele.workers.dev. The dashboard polls this every 10 seconds.

Deposits

Funding your treasury — USD, minimum $250

POST /suby/deposit 🔒amount_usd ≥ 250. Returns a unique reference (PC-DEP-######) and payment instructions. Status starts pending.
GET /suby/deposits 🔐Operator list of all deposits.
POST /suby/deposit/received/:id 🔐Operator confirms funds landed → credits treasury balance. Optional gbp_value.
POST /suby/deposit   { "amount_usd": 6000 }
→ { "deposit_id": 9, "reference": "PC-DEP-000009",
     "status": "pending", "instructions": "..." }

Bank rails: Revolut Business — sort 23-01-20 · account 74276923 · IBAN GB20 REVO 2301 2074 2769 23 · BIC REVOGB21. Full details at /bank-details. Always quote your reference.

Transfers & fees

Payouts with a flat 1% fee

POST /transfer/send 🔒amount, recipient. Fee = amount × 1%. Response includes { status, id, amount, fee, total }.
POST /transfer/send   { "amount": 1000, "recipient": "supplier-ke-01" }
→ { "status": "initiated", "id": "po_x", "amount": 1000,
     "fee": 10, "total": 1010 }
POC phase: minimum transfer $250, processed manually by the operations desk. Email help@Remsara.me with amount, recipient, and reference. The endpoint returns a clean 503 naming the missing rail configuration until payout keys are live.

Treasury sweep

Balance → Loadcircle Revolut account

GET /margin/status 🔒Treasury balance, £10,000 sweep threshold, eligibility, rail configuration flag.
POST /margin/sweep 🔒amount in GBP. Rules per infrastructure spec: minimum £1,000, maximum £50,000 per transaction, triggered above £10,000 balance.
GET /margin/status
→ { "balance": 4700, "sweep_threshold": 10000,
     "eligible": false, "rail_configured": false }

Support — Hermes

Deterministic first line, human escalation

POST /support/chat 🔒message. Instant answer for known topics (OTP, payouts, membership, rates, bank details). Unknown questions open a ticket automatically.
POST /support/ticket 🔒subject, body. Creates a tracked ticket.
POST /support/escalate 🔒ticket_id. Applies the ladder: Kenya call centre after 24h, UK after 48h.
GET /support/status/:id 🔒Ticket status and channel.
POST /support/chat   { "message": "i never got my otp" }
→ { "channel": "hermes", "resolved": true, "reply": "Codes expire after 10 minutes..." }

Live FX

Rate board — public, refreshes every 10 seconds

GET /rates/liveNo auth. Corridor FX (USD→KES, GBP→NGN, EUR→GHS), rail fees, Remsara commission, total cost per corridor, timestamp. Cached 30s server-side.
GET https://Remsara.site/rates/live
→ { "fx": { "USD_KES": 129.42, ... },
     "rails": { "mpesa": 0.015, ... },
     "Remsara": { "commission_rate": 0.01, "monthly_fee": 10 },
     "total_cost": { "USD_KES": 0.025, ... },
     "timestamp": "2026-08-22T21:52:40.028Z" }

Errors

Clean failures only

400Validation — below minimums, missing fields. Message states the rule.
401Missing/invalid Bearer token, bad signature, bad operator key.
503Rail not configured — response names the exact missing environment variables.
Webhooks: inbound Suby events are accepted only with an x-suby-signature HMAC-SHA256 header over the raw body. Unsigned requests are rejected at the edge. Endpoints: /webhooks/suby/merchant and /webhooks/suby/payout.