API
Base URL https://relay.vesperai.ch/api/v1. Every request carries Authorization: Bearer <api key> from Settings.
Send a template message
POST /api/v1/messages
{"to": "+41 79 123 45 67", "template": "termin_bestaetigung", "language": "de",
"params": ["Max", "Dienstag, 14.10.2026", "09:00", "Haarschnitt"]}
202 {"id": 17, "wa_message_id": "wamid.…", "status": "accepted", …}
Numbers without a country code are read in default_region (default CH). The response status is Meta's acceptance; sent, delivered, read or failed follow by webhook and on GET /api/v1/messages/{id}.
Free text
POST /api/v1/messages
{"to": "+41791234567", "text": "Thanks, see you tomorrow."}
Only delivered inside the 24-hour window after the customer wrote last. Outside it, use a template.
Templates
GET /api/v1/templates
POST /api/v1/templates
{"name": "termin_erinnerung", "language": "de", "category": "UTILITY",
"body": "Hallo {{1}}, Erinnerung: {{2}} um {{3}} Uhr.", "examples": ["Max", "Dienstag", "09:00"]}
Meta reviews every template, usually within minutes. Variables are {{1}}, {{2}}, … without gaps; give one example per variable.
Numbers
GET /api/v1/numbers
Your webhook
Set an https URL in Settings. Every Meta event for your numbers is forwarded as-is (Meta's own JSON shape) with header X-Relay-Signature-256: sha256=HMAC-SHA256(webhook secret, raw body). Answer 2xx within 8 seconds. Delivery statuses, incoming messages and template status updates all arrive this way.
Errors
401 bad key · 409 no number connected · 422 validation · 502 Meta rejected the call, body carries Meta's message.