← all adapters

whatsapp-style

simulates WhatsApp Business Cloud API (Meta) v21.0

restadapter v0.1.08 routes

verification

VMVM tier — no SDK suite yet· surface 8 · not implemented 5 · differs 7

use it

# add to stunt.yaml
services:
  whatsapp:
    adapter: embedded:whatsapp-style

# then
$ stunt up

The embedded: source extracts this adapter from the binary — no git clone, fully offline.

how to mock the WhatsApp Business Cloud API (Meta) API locally

Install stunt, paste the service block above into stunt.yaml, run stunt up — then point your client at localhost instead of WhatsApp Business Cloud API (Meta). It works offline, keeps state across requests and restarts, and every response is synthetic: the route shapes, status codes, pagination, and webhook delivery follow the real WhatsApp Business Cloud API (Meta) v21.0 surface — the data is fake, the behavior is real.

backing stores

messagestemplatesmediaphone_numbers

api surface (8)

generated from the adapter manifest — exactly what boots, nothing more

8 routes
POST/v21.0/{phone_number_id}/messages
POST/v21.0/{phone_number_id}/register
POST/v21.0/{phone_number_id}/media
GET/v21.0/{media_id}/content
GET/v21.0/{waba_id}/message_templates
POST/v21.0/{waba_id}/message_templates
GET/v21.0/{resource_id}
POST/v21.0/{template_id}

VM-verified behaviors (34)

  • a missing bearer is 401 in the Meta error envelope
  • wrong schemes, bare tokens and unknown bearers answer the same 190
  • every route enforces the same gate
  • the seeded test token dies at its clock-derived 10-year expiry
  • a text send answers Meta's contacts + messages envelope
  • message ids are a zero-padded monotonic sequence
  • a template send is accepted and reads back as type template
  • a send without a usable recipient is a code-131026 400
  • mark-as-read is unmodeled: a status=read body falls into the send path
  • a fresh message reads back sent
  • the status stays sent through the in-flight window
  • delivered is derived at +3s and stays delivered
  • simulate_fail ends at failed (simulator extension, as-is)
  • unknown wamids are a code-803 404
  • each send emits exactly one signed messages webhook
  • no status webhook fires before the terminal window
  • the terminal transition emits the statuses webhook exactly once
  • a multipart upload stores real bytes and reports their digest
  • the content download returns the exact bytes at the stored mime
  • a specific part content-type outranks the filename extension
  • a metadata-only JSON upload has no bytes to download
  • uploads demand messaging_product=whatsapp (code 100)
  • a multipart body without a file part is a 1304 400
  • the seeded phone reads back its registration profile
  • register answers success true and the phone stays readable
  • register on an unknown phone id still succeeds (as-is)
  • an unknown resource id is a code-803 404
  • the seeded welcome_message template lists APPROVED
  • a created template starts PENDING and echoes its payload
  • the approval lifecycle moves PENDING to APPROVED and REJECTED
  • an invalid status target leaves the template unchanged (as-is)
  • unknown template ids are a code-803 404
  • templates page by limit + after cursors
  • a malformed after cursor is a code-100 400

Not implemented (5)

  • Only text and template message types; no image, video, document, or interactive
  • No mark-as-read (status=read) or message reaction sends
  • No business profile, flows, or commerce surfaces
  • No template delete or conversation analytics endpoints
  • No inbound customer-message webhook simulation

Differs from the real API (7)

  • 24-hour customer service window not enforced; free-form sends never fail with 470
  • delivered is clock-derived at a fixed +3s after send, not real carrier delivery
  • simulate_fail:true on send is a simulator extension forcing terminal failed status
  • Template review is client-driven: POST {template_id} flips PENDING to APPROVED/REJECTED
  • mark-as-read is unmodeled: a status=read body falls into the send path
  • register on an unknown phone id still answers success
  • created_at is a fixed constant, not clock-derived
want more of the WhatsApp Business Cloud API (Meta) surface? adapters are YAML + Starlark — the authoring guide covers adding routes, fixtures, and state machines. Open an issue for anything big first, or just file a PR — merged routes ship in the next release.