curl --request GET \
--url https://api.flow.engineer/v1/webhook_endpoints/{webhook_endpoint_id} \
--header 'Authorization: Bearer <token>'const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.flow.engineer/v1/webhook_endpoints/{webhook_endpoint_id}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.flow.engineer/v1/webhook_endpoints/{webhook_endpoint_id}"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.flow.engineer/v1/webhook_endpoints/{webhook_endpoint_id}"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}{
"id": "we_01JB8ZF6P8R0T2W4Y6A8C0E2F4",
"url": "<string>",
"events": [
"message.received"
],
"enabled": true,
"livemode": true,
"created_at": "2023-11-07T05:31:56Z",
"description": "<string>",
"secret": "<string>",
"previous_secret_expires_at": "2023-11-07T05:31:56Z"
}{
"error": {
"type": "authentication",
"message": "No valid API key was given.",
"hint": "Send the header Authorization: Bearer fk_test_... (or fk_live_...); no key yet? Get a test key with curl -X POST https://api.flow.engineer/v1/sandbox/keys",
"doc_url": "https://api.flow.engineer/docs/errors/authentication"
}
}{
"error": {
"type": "invalid_request",
"message": "<string>",
"hint": "Send a template instead: POST /v1/messages with content.type=template.",
"doc_url": "https://api.flow.engineer/docs/errors/outside_window",
"param": "<string>",
"retry_after": 1,
"conversation": "conv_01JB8ZC3K5M7P9R1T3V5X7Z9B1",
"sender": "snd_01JB8Z4Q3V6W0R2N7C5H1M9K4T",
"channel_code": "<string>",
"request_id": "<string>"
}
}{
"error": {
"type": "new_contact_limit",
"message": "This sender has started its 15 new conversations for today.",
"hint": "Retry after 3600 seconds; replies into existing conversations still go.",
"doc_url": "https://api.flow.engineer/docs/errors/new_contact_limit",
"retry_after": 3600,
"sender": "snd_01JB8Z4Q3V6W0R2N7C5H1M9K4T"
}
}{
"error": {
"type": "invalid_request",
"message": "<string>",
"hint": "Send a template instead: POST /v1/messages with content.type=template.",
"doc_url": "https://api.flow.engineer/docs/errors/outside_window",
"param": "<string>",
"retry_after": 1,
"conversation": "conv_01JB8ZC3K5M7P9R1T3V5X7Z9B1",
"sender": "snd_01JB8Z4Q3V6W0R2N7C5H1M9K4T",
"channel_code": "<string>",
"request_id": "<string>"
}
}Get a webhook endpoint
Returns one webhook endpoint. The signing secret is not included.
curl --request GET \
--url https://api.flow.engineer/v1/webhook_endpoints/{webhook_endpoint_id} \
--header 'Authorization: Bearer <token>'const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.flow.engineer/v1/webhook_endpoints/{webhook_endpoint_id}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.flow.engineer/v1/webhook_endpoints/{webhook_endpoint_id}"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.flow.engineer/v1/webhook_endpoints/{webhook_endpoint_id}"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}{
"id": "we_01JB8ZF6P8R0T2W4Y6A8C0E2F4",
"url": "<string>",
"events": [
"message.received"
],
"enabled": true,
"livemode": true,
"created_at": "2023-11-07T05:31:56Z",
"description": "<string>",
"secret": "<string>",
"previous_secret_expires_at": "2023-11-07T05:31:56Z"
}{
"error": {
"type": "authentication",
"message": "No valid API key was given.",
"hint": "Send the header Authorization: Bearer fk_test_... (or fk_live_...); no key yet? Get a test key with curl -X POST https://api.flow.engineer/v1/sandbox/keys",
"doc_url": "https://api.flow.engineer/docs/errors/authentication"
}
}{
"error": {
"type": "invalid_request",
"message": "<string>",
"hint": "Send a template instead: POST /v1/messages with content.type=template.",
"doc_url": "https://api.flow.engineer/docs/errors/outside_window",
"param": "<string>",
"retry_after": 1,
"conversation": "conv_01JB8ZC3K5M7P9R1T3V5X7Z9B1",
"sender": "snd_01JB8Z4Q3V6W0R2N7C5H1M9K4T",
"channel_code": "<string>",
"request_id": "<string>"
}
}{
"error": {
"type": "new_contact_limit",
"message": "This sender has started its 15 new conversations for today.",
"hint": "Retry after 3600 seconds; replies into existing conversations still go.",
"doc_url": "https://api.flow.engineer/docs/errors/new_contact_limit",
"retry_after": 3600,
"sender": "snd_01JB8Z4Q3V6W0R2N7C5H1M9K4T"
}
}{
"error": {
"type": "invalid_request",
"message": "<string>",
"hint": "Send a template instead: POST /v1/messages with content.type=template.",
"doc_url": "https://api.flow.engineer/docs/errors/outside_window",
"param": "<string>",
"retry_after": 1,
"conversation": "conv_01JB8ZC3K5M7P9R1T3V5X7Z9B1",
"sender": "snd_01JB8Z4Q3V6W0R2N7C5H1M9K4T",
"channel_code": "<string>",
"request_id": "<string>"
}
}Authorizations
An API key of one app, sent as Authorization: Bearer <key>. Keys start with
fk_test_ (test mode: sandbox senders and test data only) or fk_live_
(live mode). Keep live keys on your server; never ship them in an app or page.
Headers
The API version to use, as a date. Without it, the version pinned to your app when it was created is used.
"2026-11-01"
Path Parameters
The webhook endpoint's ID.
A webhook endpoint ID, we_ and a ULID.
^we_[0-9A-HJKMNP-TV-Z]{26}$"we_01JB8ZF6P8R0T2W4Y6A8C0E2F4"
Response
The webhook endpoint.
A URL that receives your app's events of the types it subscribes to.
A webhook endpoint ID, we_ and a ULID.
^we_[0-9A-HJKMNP-TV-Z]{26}$"we_01JB8ZF6P8R0T2W4Y6A8C0E2F4"
The HTTPS URL events are posted to.
The event types delivered to this endpoint.
message.received: the contact sent something with content (a button tap arrives asbutton_replycontent).message.sent,message.delivered,message.read,message.failed: the status of your outbound messages.message.failedcarries the error indata.message.error.reaction.added,reaction.removed: the contact reacted to a message.typing.started,typing.stopped: the contact is typing, where the channel reports it.conversation.started: the first inbound message from a new contact, or a sandbox join (Flow itself answers the join; the join message is not amessage.received).conversation.window_closing: WhatsApp only, opt-in. The 24-hour window closes in 1 hour.sender.status_changed: a sender was throttled, flagged, banned or restored, or its WhatsApp quality rating changed.template.status_changed: Meta approved, rejected or paused a template.
message.received, message.sent, message.delivered, message.read, message.failed, reaction.added, reaction.removed, typing.started, typing.stopped, conversation.started, conversation.window_closing, sender.status_changed, template.status_changed Whether events are delivered. Disabled endpoints keep their place; nothing is lost from the log.
Whether the endpoint receives live-mode or test-mode events.
When the endpoint was created.
Your note about the endpoint.
The signing secret (whsec_...). Only in the answers to create and to rotate the secret.
While a secret rotation overlaps, when the previous secret stops signing. Absent when only one secret is active.