Akara exposes an inbound endpoint to create deposit requests and signed outbound webhooks for state changes. All requests and responses are JSON.
Endpoints live under your Supabase Edge Functions host. The exact URL is shown in Dashboard → Integrations:
https://<your-project>.supabase.co/functions/v1Authenticate inbound requests with the API key from Dashboard → Integrations:
Authorization: Bearer akara_YOUR_API_KEYKeys are stored only as a SHA-256 hash — Akara cannot recover a lost key, so regenerate it if it leaks. Regenerating immediately invalidates the previous key.
Have your PMS create a deposit request. Akara emails the guest a secure approval link and shows the request in the merchant dashboard.
POST /functions/v1/pms-webhook| Field | Type | Required | Description |
|---|---|---|---|
guest_email | string | Yes | Guest email — receives the deposit link. |
booking_id | string | No | External booking ID. Used for idempotency (see below). |
guest_name | string | No | Guest name. Defaults to "Guest". |
amount | number | No | Deposit amount. Defaults to 0. |
currency | string | No | ISO currency code. Defaults to "AED". |
| Status | Meaning | Body |
|---|---|---|
201 | Created | { deposit_request_id, deposit_link } |
200 | Idempotent — a request already exists for this booking_id | { deposit_request_id, message } |
400 | Invalid body (e.g. missing guest_email) | { error } |
401 | Missing or invalid API key | { error } |
405 | Method not allowed (use POST) | { error } |
Pass a stable booking_id. If a deposit request already exists for the same workspace and booking_id, Akara returns 200 with the existing deposit_request_id instead of creating a duplicate. Retries are therefore safe.
curl -X POST "https://YOUR_PROJECT.supabase.co/functions/v1/pms-webhook" \
-H "Authorization: Bearer akara_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"booking_id": "bk-12345",
"guest_name": "Jane Doe",
"guest_email": "jane@example.com",
"amount": 1500,
"currency": "AED"
}'Add an endpoint in Dashboard → Webhooks and Akara POSTs a signed JSON event to your URL whenever a selected event occurs. Verify every request with the secret shown when you created the endpoint.
| Header | Description |
|---|---|
Content-Type | application/json |
X-Akara-Event | Event type, e.g. deposit.approved |
X-Akara-Signature | sha256=<hex> — HMAC-SHA256 of the raw body, keyed with your secret |
{
"event": "deposit.approved",
"created_at": "2026-07-23T12:00:00.000Z",
"data": { /* the deposit_requests or claims row, snake_case keys */ }
}| Event | When | data |
|---|---|---|
deposit_request.created | A new deposit request was created | Full deposit_requests row |
deposit.approved | Guest approved the deposit | Row (status Active) |
deposit.disputed | Guest disputed the deposit | Row (status Disputed) |
deposit.released | Merchant released the deposit | Row (status Released) |
deposit.claimed | Merchant claimed the deposit | Row (status Claimed) |
deposit.failed | Payment failed (guest can retry) | Row (status Failed) |
claim.submitted | Merchant submitted a claim | Full claims row |
claim.status_changed | Claim moved to Approved or Rejected | Full claims row |
X-Akara-Signature, which is sha256=<hex>.const crypto = require('crypto')
function verifySignature(rawBody, signatureHeader, secret) {
const expected = 'sha256=' + crypto.createHmac('sha256', secret).update(rawBody).digest('hex')
return crypto.timingSafeEqual(Buffer.from(signatureHeader), Buffer.from(expected))
}
app.post('/webhooks/akara', express.raw({ type: 'application/json' }), (req, res) => {
const sig = req.headers['x-akara-signature']
if (!verifySignature(req.body.toString(), sig, process.env.AKARA_WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature')
}
res.status(200).send('OK')
})import hmac, hashlib
def verify_signature(raw_body: bytes, signature_header: str, secret: str) -> bool:
expected = 'sha256=' + hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(signature_header, expected)200 within a few seconds so Akara doesn’t retry.X-Akara-Event; treat delivery as at-least-once and dedupe.Errors return a JSON body of the shape { "error": "message" }.
| Code | Meaning |
|---|---|
200 | OK / idempotent hit |
201 | Resource created |
400 | Invalid request body |
401 | Missing or invalid API key |
405 | Method not allowed |
500 | Unexpected server error — safe to retry with the same booking_id |