For the complete documentation index, see llms.txt. This page is also available as Markdown.

Webhooks

Register and manage the endpoint MultiSet delivers lifecycle events to, send test events, rotate the signing secret, and read the delivery log.

These endpoints manage the HTTPS URL that map, map set, and object lifecycle events are delivered to. See Webhooks for the event catalogue, the payload envelope, signature verification, and the retry policy.

One endpoint per account. Registering a second returns 409. Update or delete the existing one instead.

Endpoint management requires the Write scope, deleting requires Delete, and the delivery log requires Query. See Credentials.

Endpoints

Register a webhook endpoint

Registers the URL events are delivered to, and verifies it immediately by POSTing a signed endpoint.verify challenge that your service must echo back. See Verifying your endpoint.

The signing secret is returned once, in this response. It cannot be read back afterwards, only rotated.

Constraints:

  • The account must not already have an endpoint.

  • url must be HTTPS in production, and must not resolve to a private, loopback, or link-local address.

  • Every entry in events must be a known event type or a valid wildcard.

Register a webhook endpoint

post

Registers the URL lifecycle events are delivered to. One endpoint per account.

The endpoint is verified immediately: a signed endpoint.verify event is POSTed to the URL, and your service must reply 200 and echo the challenge value back in the response body. A bare 200 is not enough, because a misconfigured proxy will return that for a URL that reaches nothing.

The signing secret is returned once, here, and cannot be read back afterwards. Store it before you close the response.

Authorizations
AuthorizationstringRequired
Bearer authentication header of the form Bearer <token>.
Body
urlstring · max: 2048Required

HTTPS in production. Private, loopback and link-local addresses are rejected, and the address is re-checked at delivery time.

Example: https://acme.com/multiset-hooks
eventsstring[] · min: 1Required

Event types to receive. Accepts exact names, an entity wildcard (map.*), a state wildcard (*.failed), or * for everything. New event types may appear under an existing wildcard, so your receiver must ignore types it does not recognise.

Example: ["map.*","object.active"]
descriptionstring · max: 200OptionalExample: prod receiver
Responses
201

Endpoint created. verified is false if the challenge failed.

application/json
messagestringOptionalExample: Webhook endpoint created
secretstringOptional

Shown once. Store it now, it cannot be retrieved again.

Example: whsec_8f2b1c9d4e7a6b3f8c2d1e5a9b4c7d0e
verifiedbooleanOptionalExample: true
verificationErrorstringOptionalExample: response did not echo the challenge
post/endpoint
POST /v1/webhook/endpoint HTTP/1.1
Host: api.multiset.ai
Authorization: Bearer YOUR_SECRET_TOKEN
Content-Type: application/json
Accept: */*
Content-Length: 106

{
  "url": "https://acme.com/multiset-hooks",
  "events": [
    "map.*",
    "object.active"
  ],
  "description": "prod receiver"
}
{
  "message": "Webhook endpoint created",
  "endpoint": {
    "_id": "60d5ec49f1b2c8b1f8e4e1a1",
    "accountId": "text",
    "url": "https://acme.com/multiset-hooks",
    "description": "text",
    "events": [
      "map.*",
      "object.active"
    ],
    "status": "pending_verification",
    "verifiedAt": "2026-01-01T00:00:00.000Z",
    "consecutiveFailures": 0,
    "lastSuccessAt": "2026-01-01T00:00:00.000Z",
    "disabledAt": "2026-01-01T00:00:00.000Z",
    "createdAt": "2026-01-01T00:00:00.000Z",
    "updatedAt": "2026-01-01T00:00:00.000Z"
  },
  "secret": "whsec_8f2b1c9d4e7a6b3f8c2d1e5a9b4c7d0e",
  "verified": true,
  "verificationError": "response did not echo the challenge"
}

Get the account's webhook endpoint

Returns the registered endpoint, including its status, consecutiveFailures, and lastSuccessAt, or null if none is registered. The signing secret is never returned.

Get the account's webhook endpoint

get

Returns the registered endpoint, or null if none is registered. The signing secret is never returned.

Authorizations
AuthorizationstringRequired
Bearer authentication header of the form Bearer <token>.
Responses
200

The endpoint, or null if none is registered

application/json
get/endpoint
GET /v1/webhook/endpoint HTTP/1.1
Host: api.multiset.ai
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*
200

The endpoint, or null if none is registered

{
  "endpoint": {
    "_id": "60d5ec49f1b2c8b1f8e4e1a1",
    "accountId": "text",
    "url": "https://acme.com/multiset-hooks",
    "description": "text",
    "events": [
      "map.*",
      "object.active"
    ],
    "status": "pending_verification",
    "verifiedAt": "2026-01-01T00:00:00.000Z",
    "consecutiveFailures": 0,
    "lastSuccessAt": "2026-01-01T00:00:00.000Z",
    "disabledAt": "2026-01-01T00:00:00.000Z",
    "createdAt": "2026-01-01T00:00:00.000Z",
    "updatedAt": "2026-01-01T00:00:00.000Z"
  }
}

Update a webhook endpoint

Change the URL, the subscribed events, the description, or set isActive to false to stop delivery without deleting the endpoint. Send at least one field.

Update a webhook endpoint

put

Change the URL, the subscribed events, the description, or deactivate the endpoint. At least one field is required.

Changing url resets the endpoint to pending_verification, so no events are delivered until verification succeeds again.

Authorizations
AuthorizationstringRequired
Bearer authentication header of the form Bearer <token>.
Path parameters
idstringRequired

The endpoint's _id

Body
urlstring · max: 2048Optional
eventsstring[] · min: 1Optional
descriptionstring · max: 200Optional
isActivebooleanOptional
Responses
200

Updated

application/json
messagestringOptional
put/endpoint/{id}
PUT /v1/webhook/endpoint/{id} HTTP/1.1
Host: api.multiset.ai
Authorization: Bearer YOUR_SECRET_TOKEN
Content-Type: application/json
Accept: */*
Content-Length: 69

{
  "url": "text",
  "events": [
    "text"
  ],
  "description": "text",
  "isActive": true
}
{
  "message": "text",
  "endpoint": {
    "_id": "60d5ec49f1b2c8b1f8e4e1a1",
    "accountId": "text",
    "url": "https://acme.com/multiset-hooks",
    "description": "text",
    "events": [
      "map.*",
      "object.active"
    ],
    "status": "pending_verification",
    "verifiedAt": "2026-01-01T00:00:00.000Z",
    "consecutiveFailures": 0,
    "lastSuccessAt": "2026-01-01T00:00:00.000Z",
    "disabledAt": "2026-01-01T00:00:00.000Z",
    "createdAt": "2026-01-01T00:00:00.000Z",
    "updatedAt": "2026-01-01T00:00:00.000Z"
  }
}

Delete a webhook endpoint

Removes the endpoint. Delivery stops immediately. The delivery log is kept, so you can still audit what was sent before the endpoint was removed.

Delete a webhook endpoint

delete

Removes the endpoint. Delivery stops immediately and the delivery log is retained.

Authorizations
AuthorizationstringRequired
Bearer authentication header of the form Bearer <token>.
Path parameters
idstringRequired
Responses
200

Deleted

No content

delete/endpoint/{id}
DELETE /v1/webhook/endpoint/{id} HTTP/1.1
Host: api.multiset.ai
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*

No content

Re-run endpoint verification

Re-sends the signed challenge. Use it after fixing a receiver whose first verification failed, or to re-enable an endpoint that was auto-disabled after 20 consecutive delivery failures.

A successful verification sets the endpoint back to active and resets consecutiveFailures to zero, so this is the self-service route out of an auto-disable.

Re-run endpoint verification

post

Re-sends the signed challenge. Use it after fixing an endpoint whose first verification failed, or to re-enable one that was auto-disabled after sustained delivery failures. A successful verification resets the failure count.

Authorizations
AuthorizationstringRequired
Bearer authentication header of the form Bearer <token>.
Path parameters
idstringRequired
Responses
200

Verification result

application/json
verifiedbooleanOptional
reasonstringOptionalExample: response did not echo the challenge
responseCodeintegerOptionalExample: 502
post/endpoint/{id}/verify
POST /v1/webhook/endpoint/{id}/verify HTTP/1.1
Host: api.multiset.ai
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*
{
  "verified": true,
  "reason": "response did not echo the challenge",
  "responseCode": 502
}

Send a test event

Delivers a signed sample event synchronously and reports what your endpoint answered: the response code, how long it took, and the first 2KB of the response body. Pass type to choose which event shape to simulate, or omit it for map.active.

Test events carry livemode: false, are never retried, do not count towards consecutiveFailures, and are recorded in the delivery log with isTest: true.

This call returns 200 even when delivery failed, because the API call itself succeeded. Read delivered to find out whether your endpoint accepted the event.

Send a test event

post

Delivers a signed sample event synchronously and reports what your endpoint answered. A test event is never retried, and carries livemode: false so your handler can tell it from a real event. It is recorded in the delivery log with isTest: true.

Authorizations
AuthorizationstringRequired
Bearer authentication header of the form Bearer <token>.
Path parameters
idstringRequired
Body
typestringOptional

Which event shape to simulate. Defaults to map.active.

Example: map.active
Responses
200

The attempt result. Returns 200 even when delivery failed, because the API call itself succeeded. Check delivered.

application/json
deliveredbooleanOptionalExample: true
eventIdstringOptionalExample: evt_test_01JB8Z9K
responseCodeintegerOptionalExample: 200
responseTimeMsintegerOptionalExample: 342
errorKindstring · enumOptionalPossible values:
responseBodystringOptional
post/endpoint/{id}/test
POST /v1/webhook/endpoint/{id}/test HTTP/1.1
Host: api.multiset.ai
Authorization: Bearer YOUR_SECRET_TOKEN
Content-Type: application/json
Accept: */*
Content-Length: 21

{
  "type": "map.active"
}
{
  "delivered": true,
  "eventId": "evt_test_01JB8Z9K",
  "responseCode": 200,
  "responseTimeMs": 342,
  "errorKind": "timeout",
  "responseBody": "text"
}

Rotate the signing secret

Returns a new secret once. The previous secret stops verifying immediately, so deploy the new one first, or accept a short window of signature failures. Failed deliveries in that window are retried, so nothing is lost if you rotate and redeploy promptly.

Rotate the signing secret

post

Returns a new signing secret once. The previous secret stops verifying immediately, so deploy the new one before rotating, or accept a short window of signature failures.

Authorizations
AuthorizationstringRequired
Bearer authentication header of the form Bearer <token>.
Path parameters
idstringRequired
Responses
200

New secret

application/json
messagestringOptional
secretstringOptionalExample: whsec_9c1d3f8a2b6e4d7c1a9f5b3e8d2c6a4f
post/endpoint/{id}/rotate-secret
POST /v1/webhook/endpoint/{id}/rotate-secret HTTP/1.1
Host: api.multiset.ai
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*
{
  "message": "text",
  "secret": "whsec_9c1d3f8a2b6e4d7c1a9f5b3e8d2c6a4f"
}

List webhook deliveries

Delivery history for the account. Filter by event type, delivery status, a date range, or resourceId to see every event raised for one map, map set, or object.

The event payload is omitted here to keep responses small. Fetch a single delivery to read it.

status

Meaning

queued

Accepted, first attempt not yet made

delivered

Your endpoint returned a 2xx

retrying

An attempt failed, another is scheduled at nextRetryAt

exhausted

All five attempts failed, it will not be tried again

cancelled

Not delivered, for example the endpoint was deleted mid-chain

List webhook deliveries

get

Delivery history for the account, newest first. The event payload is omitted here to keep the response small, fetch a single delivery to read it.

Authorizations
AuthorizationstringRequired
Bearer authentication header of the form Bearer <token>.
Query parameters
pageinteger · min: 1OptionalDefault: 1
limitinteger · min: 1 · max: 100OptionalDefault: 25
typestringOptional

Filter by event type

Example: map.active
statusstring · enumOptionalPossible values:
resourceIdstringOptional

Everything that happened to one map, map set, or object

eventIdstringOptional
fromstring · date-timeOptional
tostring · date-timeOptional
Responses
200

Paged deliveries

application/json
totalintegerOptionalExample: 142
pageintegerOptionalExample: 1
limitintegerOptionalExample: 25
get/delivery
GET /v1/webhook/delivery HTTP/1.1
Host: api.multiset.ai
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*
200

Paged deliveries

{
  "total": 142,
  "page": 1,
  "limit": 25,
  "deliveries": [
    {
      "eventId": "evt_1a0636bc890d38c1f72d2b9d122",
      "type": "map.active",
      "entity": "map",
      "resourceId": "6710c22dee25fb59e9f3c67b",
      "occurredAt": "2026-01-01T00:00:00.000Z",
      "status": "queued",
      "attempts": 1,
      "responseCode": 200,
      "responseTimeMs": 342,
      "responseBody": "text",
      "errorKind": "timeout",
      "nextRetryAt": "2026-01-01T00:00:00.000Z",
      "deliveredAt": "2026-01-01T00:00:00.000Z",
      "isTest": true,
      "history": [
        {
          "at": "2026-01-01T00:00:00.000Z",
          "code": 503,
          "errorKind": "text",
          "ms": 1
        }
      ],
      "createdAt": "2026-01-01T00:00:00.000Z"
    }
  ]
}

Get one delivery

Returns the full record for one event, including the exact payload that was sent and one history entry per attempt with its response code, error kind, and timing.

Get one delivery, including its payload

get

Returns the full delivery record, with the data block that was sent to your endpoint.

Authorizations
AuthorizationstringRequired
Bearer authentication header of the form Bearer <token>.
Path parameters
eventIdstringRequired

The event id, also sent as the Multiset-Event-Id header

Responses
200

The delivery record

application/json
get/delivery/{eventId}
GET /v1/webhook/delivery/{eventId} HTTP/1.1
Host: api.multiset.ai
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*
{
  "delivery": {
    "eventId": "evt_1a0636bc890d38c1f72d2b9d122",
    "type": "map.active",
    "entity": "map",
    "resourceId": "6710c22dee25fb59e9f3c67b",
    "occurredAt": "2026-01-01T00:00:00.000Z",
    "status": "queued",
    "attempts": 1,
    "responseCode": 200,
    "responseTimeMs": 342,
    "responseBody": "text",
    "errorKind": "timeout",
    "nextRetryAt": "2026-01-01T00:00:00.000Z",
    "deliveredAt": "2026-01-01T00:00:00.000Z",
    "isTest": true,
    "history": [
      {
        "at": "2026-01-01T00:00:00.000Z",
        "code": 503,
        "errorKind": "text",
        "ms": 1
      }
    ],
    "createdAt": "2026-01-01T00:00:00.000Z",
    "payload": {}
  }
}

Error kinds

When a delivery fails, errorKind says how, which is usually enough to tell a configuration problem from an outage:

errorKind

Cause

timeout

No response within 10 seconds

dns

The hostname did not resolve

tls

Certificate or handshake failure

conn_refused

Nothing listening on the port

http_4xx

Your endpoint rejected the request, a signature check failing looks like this

http_5xx

Your endpoint errored

redirect_refused

The endpoint returned a redirect, which is never followed

network

Anything else at the transport layer

Last updated

Was this helpful?