Set Flow endpoint destination
Stores the customer’s OWN webhook — the destination we forward each decrypted Flow exchange to. This does NOT touch Meta. Registering endpoint_uri on the Flow is a separate act against a separate system (POST on this same resource); doing it here would silently re-point the Flow of a tenant who already runs their own endpoint, on a request that looked like a rename. What this answers instead is where Meta IS pointing — metaEndpointUri, drift and warnings.
⛔ url must be https://. The body forwarded to it is the END USER’s form answers, decrypted by us out of Meta’s envelope one hop earlier; over http:// that is PII in the clear, and there is no flag that allows it (400 FLOW_ENDPOINT_URL_NOT_HTTPS). The refused URL is not echoed back — it may carry a token in its query string.
⚠️ url is REQUIRED and may be null EXPLICITLY, never by omission. An absent field and a null one mean opposite things — “I sent you a partial body” and “remove the destination” — so an omitted url is 400 FLOW_ENDPOINT_URL_REQUIRED rather than a wipe of a working configuration. "url": null CLEARS the destination and KEEPS the secret; rotateSecret: true is the exit for a secret that leaked.
⚠️ secret comes back on exactly ONE response in the life of a secret: the request that minted it. It is encrypted at rest and there is no read path back, so secret: null means “one already existed and was kept”, not “there is none” — hasSecret answers that.
A truncated body is not read as an empty one: {"url": "https://x" (one missing brace) is 400 FLOW_BODY_INVALID. Only url and rotateSecret are accepted; the number comes from the KEY, so naming it in the body is 400 FLOW_NUMBER_FROM_KEY. Permission flows:manage.
Requires a number-scoped key. A tenant-scoped key must name the number with the x-whatsapp-number-id header, or it gets 403 TENANT_SCOPE_NOT_ALLOWED.
Authorizations
Your ps_ API key
Path Parameters
The local id of the Flow — the id field GET /v1/flows returns, never metaFlowId.
Body
The customer's own https:// webhook. null CLEARS the destination and keeps the signing secret. Required — omitting the field is 400 FLOW_ENDPOINT_URL_REQUIRED, never a wipe.
"https://hooks.acme.com/flows/data-exchange"
Mints a new HMAC signing secret and returns it once. Must be a real boolean — "true" is refused, never coerced (400 FLOW_ENDPOINT_ROTATE_INVALID).
false
Response
Destination stored. secret is present ONLY when this request minted one — a rotation, or the first save on this Flow