Run and protect
Best practices
Do
- Use your own ids. Send
externalReffor subaccounts and contacts, and upsert contacts withPUT /v2/contacts/by-external-ref/{externalRef}. - Send an
Idempotency-Keyon every create and send. Build it from your data so a retry is the same operation. See Idempotency. - Use webhooks instead of polling. Polling spends your rate limit and arrives late.
- Branch on
code. Showdetailto people. Codes are stable; messages may improve. - Ignore unknown fields and event types in what you receive. Responses and events gain fields without a new version.
- Use one key per integration, with the scopes it needs. Rotate it from the dashboard.
- Report facts and let triggers choose the message. Marketing can change wording without a deploy.
- Check
readinessafter activating an agent, before you tell your customer it works. - Preview campaigns to see who is skipped.
- Verify webhook signatures with the raw request body.
- Try with
dryRun=truefirst where a route accepts it: nothing is saved or sent. - Treat
202as accepted. Delivery arrives later. - Try with
?dryRun=truewhere a route accepts it. It runs the same checks as the real call and answers200. Nothing is saved or sent, and it does not use yourIdempotency-Key. - Send only documented fields. A request body with an unknown field answers
400 unknown_field. See Versioning.
Avoid
| Avoid | Do this |
|---|---|
| Polling messages every second to see if the agent answered | Subscribe to message.created |
A new random Idempotency-Key on each retry | Reuse the key on every retry of the same operation |
| Free text on WhatsApp after 24 hours of silence | Send a template |
| Template names and variable positions hard-coded in your backend | Report contact events with named data, mapped by a trigger |
Writing as team without taking control | take-control, write, release-control |
| Parsing ids or storing a slug instead of the id | Treat the full id as an opaque string |
| An API key in a browser or mobile app | Call Lelemon from your server only |
| One key with every scope for all your services | One key per service |
| Deleting and recreating an agent to reset it | Restore a previous version |
| Doing the work before answering a webhook | Answer 2xx first, then queue the work |
Limit who can receive messages
The recipient allowlist is a safety net for staging and first launches. While it is on, nothing is sent to anyone outside it.
Entries are phones in E.164, email addresses or domains written @domain. The call replaces the whole list. It needs recipient-allowlist:write.