Manage Outgoing Webhooks

Manage outgoing webhook endpoints over the API instead of the Open API → Outgoing Webhooks tab in the CMS. This is the same set of capabilities — create an endpoint, choose the events it subscribes to (optionally filtered to specific walls, forms or achievements, or to completion types), configure authentication and custom headers, send a test delivery, and revoke or deactivate it — so external systems can set up integrations without a human in the CMS.

For the catalog of events and their delivery payloads, see Outgoing Webhooks.

Required scope: read:webhooks, write:webhooks.

Endpoints

GET
/api/open/v1/webhooks

List your webhook endpoints

GET
/api/open/v1/webhooks/{id}

Get a single endpoint

GET
/api/open/v1/webhooks/{id}/secret

Reveal the full signing secret

POST
/api/open/v1/webhooks

Create an endpoint

PUT
/api/open/v1/webhooks/{id}

Update an endpoint

POST
/api/open/v1/webhooks/{id}/revoke

Revoke an endpoint (permanent)

POST
/api/open/v1/webhooks/{id}/toggle

Activate or deactivate an endpoint

POST
/api/open/v1/webhooks/{id}/ping

Send a test delivery

Create

curl -X POST https://customer.monotree.com/api/open/v1/webhooks \
  -H "Authorization: Bearer mono_your_token_here" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "My integration",
    "url": "https://example.com/monotree/webhook",
    "events": ["monotree.post.created", "monotree.user.registered"],
    "filters": { "monotree.post.created": [1, 3] },
    "auth_type": "bearer_token",
    "auth_value": "your-receiving-endpoint-token",
    "custom_headers": { "X-Tenant": "acme" }
  }'

Request body

FieldTypeNotes
namestringRequired. A label for the endpoint, at most 255 characters.
urlstringRequired. The URL deliveries are sent to, at most 2048 characters. It must use https, carry no credentials, and its host must resolve to public addresses only; otherwise 422.
eventsarray of stringsRequired. One or more event names. An unrecognised event returns 422.
filtersobjectOptional. Restricts entity-scoped events to specific entity IDs, and completions to specific types — see Filtering events.
auth_typestringOptional. One of bearer_token, basic_auth, api_key. See Authenticating deliveries.
auth_valuestringOptional. The token, credentials, or API key value for the chosen auth_type, at most 2048 characters.
auth_headerstringThe header name for api_key auth (e.g. X-Api-Key), at most 255 characters. Send it whenever auth_type is api_key: the API accepts an api_key endpoint without it, but every delivery to that endpoint then fails.
custom_headersobjectOptional. Extra headers sent with every delivery, as a { "Header-Name": "value" } map. Each value is a string of at most 2048 characters. A custom header with the same name as the auth header replaces it.

A new endpoint is active immediately and is issued a signing secret. The response masks the secret — fetch the full value once with GET /webhooks/{id}/secret.

Filtering events

Some events are tied to an entity and can be narrowed to specific instances by passing their IDs under filters, keyed by event name. An event with no filter (or a non-filterable event) fires for all matching activity.

EventFilter by
monotree.post.createdWall IDs
monotree.comment.created, monotree.comment.updated, monotree.comment.deletedWall IDs
monotree.formresponse.created, monotree.formresponse.updatedForm IDs
monotree.formresponse.comment.created, monotree.formresponse.comment.deletedForm IDs
monotree.formresponse.alarm_triggeredForm IDs
monotree.achievement.awardedAchievement IDs
monotree.completion.createdCompletion types: course, journey, handbook

Each ID must be an integer, or the request returns 422. IDs are not checked against existing walls, forms or achievements, and filters for an event that is not in events are ignored. Their values are still validated, so an invalid value still returns 422.

monotree.completion.created is filtered on type instead of on IDs. Pass one or more of course, journey and handbook; leave the filter out to receive all three. Any other value, including an ID, returns 422:

{
  "events": ["monotree.completion.created"],
  "filters": { "monotree.completion.created": ["course", "journey"] }
}

All other events (e.g. monotree.user.registered, monotree.onboarding.completed, monotree.announcement.published) are not entity-scoped; any filters supplied for them are ignored, though each value must still be an integer or the request returns 422.

Authenticating deliveries

Beyond the HMAC signature (see Outgoing Webhooks), you can have Monotree add an auth header to every delivery:

auth_typeHeader sentauth_valueauth_header
bearer_tokenAuthorization: Bearer <auth_value>the token—
basic_authAuthorization: Basic <base64(auth_value)>user:password—
api_key<auth_header>: <auth_value>the keythe header name (required)

Update

PUT accepts the same fields as create; only what you send is changed, with two exceptions:

  • Events and filters are replaced together. Sending events replaces the endpoint's event rules with the events and filters in the same request; events without filters removes any filters. filters sent without events is ignored.
  • Authentication is replaced as a set, and only when the request contains auth_type. Send auth_type, auth_value and, for api_key, auth_header together. auth_value or auth_header sent without auth_type is ignored, and auth_type sent alone clears the stored value. Send "auth_type": null to remove authentication.

Sending custom_headers replaces all custom headers; send null to remove them.

curl -X PUT https://customer.monotree.com/api/open/v1/webhooks/42 \
  -H "Authorization: Bearer mono_your_token_here" \
  -H "Content-Type: application/json" \
  -d '{ "events": ["monotree.announcement.published"] }'

Response

{
  "data": {
    "id": 42,
    "name": "My integration",
    "url": "https://example.com/monotree/webhook",
    "is_active": true,
    "events": ["monotree.post.created", "monotree.user.registered"],
    "filters": { "monotree.post.created": [1, 3] },
    "auth_type": "bearer_token",
    "custom_headers": { "X-Tenant": "••••" },
    "secret": "a1b2c3d4...",
    "total_deliveries": 0,
    "last_used_at": null,
    "revoked_at": null,
    "created_at": "2026-06-09T10:00:00+02:00",
    "updated_at": "2026-06-09T10:00:00+02:00"
  }
}
FieldTypeNotes
eventsarrayDistinct event names the endpoint subscribes to.
filtersobjectEntity IDs per event, for entity-scoped events only. For monotree.completion.created the values are type tokens (strings) instead of IDs.
custom_headersobject or nullHeader names only — values are masked as ••••.
secretstringA hint (first 8 characters). Fetch the full secret with GET /webhooks/{id}/secret.
is_activebooleanfalse when deactivated with toggle or revoked. A revoked endpoint receives no event deliveries even if this is true, so check revoked_at as well.
total_deliveriesintegerAn approximate usage counter of the deliveries sent to the endpoint, pings included. Don't rely on it as an exact count.
last_used_atdatetime or nullWhen a delivery (pings included) was last sent to the endpoint. null if none has been sent.
revoked_atdatetime or nullWhen the endpoint was revoked, if ever. A non-null value means the endpoint receives no event deliveries.

Revealing the secret

Returns the full HMAC signing secret so you can verify delivery signatures.

curl https://customer.monotree.com/api/open/v1/webhooks/42/secret \
  -H "Authorization: Bearer mono_your_token_here"
{ "data": { "secret": "a1b2c3d4e5f6..." } }

Activate / deactivate

POST /webhooks/{id}/toggle flips is_active. A deactivated endpoint stops receiving event deliveries but keeps its configuration and history, so you can switch it back on later. Toggling does not undo a revoke: on a revoked endpoint it still flips is_active, but the endpoint stays revoked and receives no events.

Revoke

POST /webhooks/{id}/revoke permanently deactivates the endpoint: it sets is_active to false and records revoked_at. An endpoint receives event deliveries only when is_active is true and revoked_at is null, and nothing undoes a revoke, neither toggle nor PUT. The record is kept and its delivery logs are kept for 90 days; there is no hard delete — this mirrors the CMS.

An endpoint also stops with the token that created it: revoking or deleting the token revokes the endpoint, and while the token is expired the endpoint receives no event deliveries. Endpoints created in the CMS, and endpoints that already existed before v0.59.0, keep running whatever the state of a token.

Test delivery

POST /webhooks/{id}/ping sends one signed delivery to the endpoint URL right away, using its current secret, auth, and custom headers. It is sent once, without retries, and works on a deactivated or revoked endpoint too. The body is the usual envelope with "event": "monotree.test" and "payload": { "message": "This is a test webhook." }.

The call answers 200 whatever the receiver did, so read ok:

{ "ok": true, "status": "delivered" }
{ "ok": false, "status": "failed", "status_code": 500, "error": "The receiver answered HTTP 500" }
FieldNotes
oktrue when the receiver answered 2xx.
statusdelivered or failed.
status_codeOnly on a failure: the receiver's HTTP status, or null when it gave none (timeout, refused connection, refused URL). Left out when the test could not be sent at all because of an error on Monotree's side; error then says so.
errorOnly on a failure: the reason, for example The receiver answered HTTP 500, The receiver could not be reached, a connection error, a refused URL such as The webhook url must point at a public address., or No delivery result was recorded when the attempt left no result to read (status_code is then null).