kenari.dev

Supported endpoints#

kenari forwards only a fixed set of WhatsApp Cloud API calls. A request is forwarded only when its method, path shape and target id all match a row below, and the id belongs to a number or WhatsApp Business Account (WABA) connected to your kenari account.

All paths are relative to the API base URL, https://api.kenari.dev. {version} is a Graph API version in the form v<n>.0 (for example v21.0). kenari sends the version to Meta exactly as you wrote it.

Allow-list#

MethodPathThe id must beNotes
POST/{version}/{phone_number_id}/messagesa phone number on your accountSend any message type. See Sending messages.
PUT/{version}/{phone_number_id}/messagesa phone number on your accountAlso accepted on the messages edge.
POST/{version}/{phone_number_id}/mediaa phone number on your accountUpload media. See Media.
GET/{version}/{media_id}?phone_number_id={phone_number_id}a media id, scoped by a phone number on your accountphone_number_id is required.
DELETE/{version}/{media_id}?phone_number_id={phone_number_id}a media id, scoped by a phone number on your accountphone_number_id is required.
GET/{version}/{waba_id}/message_templatesa WABA on your accountList templates. See Templates.
POST/{version}/{waba_id}/message_templatesa WABA on your accountCreate a template.
DELETE/{version}/{waba_id}/message_templatesa WABA on your accountDelete a template.
GET/{version}/{phone_number_id}a phone number on your accountRead the number's fields.
GET/{version}/{phone_number_id}/whatsapp_business_profilea phone number on your accountRead-only.

The combination matters, not just the path. For example, POST /{version}/{phone_number_id}/messages is allowed, but POST /{version}/{waba_id}/messages is not, and GET on /media is not.

Anything else returns 404#

These all get the same response, 404 with a KenariRoutingException body:

  • a path that isn't /{version}/{id} or /{version}/{id}/{edge}
  • a method other than GET, POST, PUT or DELETE
  • an edge or method that isn't in the table above
  • an id that doesn't belong to your account, including ids owned by someone else

A number or WABA that belongs to you but that you disconnected returns 422 KenariNotConnectedException instead (see Errors).

json
{  "error": {    "message": "Unknown route or object.",    "type": "KenariRoutingException",    "code": 1003,    "fbtrace_id": "req_…"  }}

The 404 is identical whether the route doesn't exist or the id isn't yours, so nobody can use kenari to find out which ids exist.

A path that doesn't match the /{version}/{id}[/{edge}] shape is rejected before your API key is checked, so it returns 404 even with no Authorization header.

What kenari does to a forwarded request#

What happens
AuthorizationYour kn_… key is checked and removed. kenari sends Authorization: Bearer <Meta access token> for the number's WABA.
Other request headersOnly Content-Type and Accept go to Meta, unchanged. Multipart boundaries are kept.
Query stringSent as you wrote it, except that any access_token or appsecret_proof you include is removed. kenari appends its own appsecret_proof.
Request bodyStreamed to Meta byte for byte. It is never parsed or re-serialised. Limit: 100 MB (see Media).
Response status and bodyMeta's status and body come back unchanged.
Response headersOnly these of Meta's headers are passed on: Content-Type, Content-Length, Content-Disposition, X-FB-Trace-Id, X-FB-Rev, X-Business-Use-Case-Usage, X-App-Usage.
Added response headersRateLimit-Limit, RateLimit-Remaining, RateLimit-Reset (see Rate limits) and X-Kenari-Request-Id.

Timeouts#

RequestTimeout for Meta's response
/{phone_number_id}/media and /{media_id}120 seconds
/{phone_number_id}/messages30 seconds
Everything else30 seconds

If Meta doesn't answer in time, kenari returns 503 KenariUpstreamException. kenari never retries a request for you. See Errors.