Agent Skills / maison-webhooks

Install this skill alone, or read it below. Raw file: SKILL.md · references/tools.md

bash
npx skills add https://docs.maison-labs.com --skill maison-webhooks

Maison — Incoming webhooks

Manage a hotel's incoming webhooks: named inboxes its other systems (survey tools, CRMs, form builders, automation platforms) POST to, which start the agents that list them as inputs. Create, read, update and delete webhooks; add, rename, reveal, rotate and revoke their named keys; read the request log and delivery analytics. Use when wiring an external system to a hotel's agents or diagnosing why a sender's requests are refused.

Part of the Maison public API. Read the maison-public-api skill first for authentication, discovery and transport details (https://docs.maison-labs.com/skills/maison-public-api/SKILL.md).

When to use

  • Give an external system an address to send events to — create_webhook, then list it in the agent's scope.webhookIds.
  • Issue a separate key per sending app, or replace a leaked one — add_webhook_key, rotate_webhook_key, revoke_webhook_key.
  • Find out why a sender's requests fail or what it sent — list_webhook_requests, get_webhook_request, get_webhook_analytics.

Before you start

  1. Send x-api-key: <key> on every call; the key only reaches /api/v1.
  2. GET /api/v1/tools (or MCP tools/list) returns the tools THIS key may run — if a tool below is missing there, you lack a grant; do not retry it.
  3. Client-scoped tools take clientId (a hotel id). whoami lists the ids you can act on.

Tools

ToolWhat it doesRESTNeeds
add_webhook_keyAdd a named key to an api_key webhook — one per sending app, so the request log shows which app called (at most 20 live).POST /api/v1/client/{clientId}/webhook/{webhookId}/keyupdate-client WRITE (client)
create_webhookCreate an incoming webhook: a permanent address (/webhooks/{clientId}/{slug}) other systems POST to.POST /api/v1/client/{clientId}/webhookupdate-client WRITE (client)
delete_webhookSoft-delete a webhook: it stops accepting requests at once, its request log stays readable and its address stays reserved (it cannot be reused).DELETE /api/v1/client/{clientId}/webhook/{webhookId}update-client WRITE (client); destructive
get_webhookFetch one webhook (deleted ones included) with its address, settings, live keys (prefixes only — never a secret) and 24-hour request count.GET /api/v1/client/{clientId}/webhook/{webhookId}update-client READ (client); read-only
get_webhook_analyticsRequest counts for a hotel's webhooks over from–to (inclusive UTC days, at most 92): per day (total, accepted, rejected), per webhook (with the last request time) and per outcome.GET /api/v1/client/{clientId}/webhooks/analyticsupdate-client READ (client); read-only
get_webhook_requestOne logged request with the caller's IP, its stored headers and body (bodies are kept 90 days; after that body is null).GET /api/v1/client/{clientId}/webhook/{webhookId}/request/{requestId}update-client READ (client); read-only
list_webhook_requestsA webhook's request log, newest first: when, status, outcome (accepted or why it was refused), size, the key that authenticated it and how many agent runs it started.GET /api/v1/client/{clientId}/webhook/{webhookId}/requestsupdate-client READ (client); read-only
list_webhooksList a hotel's incoming webhooks with their addresses, live keys (prefixes only, never secrets) and 24-hour request counts, plus how many are deleted (deletedCount).GET /api/v1/client/{clientId}/webhooksupdate-client READ (client); read-only
rename_webhook_keyRename a live key with its current version; the secret does not change.PUT /api/v1/client/{clientId}/webhook/{webhookId}/key/{keyId}update-client WRITE (client)
reveal_webhook_keyReturn a live key's secret (apiKey) again.GET /api/v1/client/{clientId}/webhook/{webhookId}/key/{keyId}/secretupdate-client WRITE (client)
revoke_webhook_keyRevoke a key at once (soft: the request log keeps its name).DELETE /api/v1/client/{clientId}/webhook/{webhookId}/key/{keyId}update-client WRITE (client); destructive
rotate_webhook_keyIssue a new secret for a key, with the key's current version.POST /api/v1/client/{clientId}/webhook/{webhookId}/key/{keyId}/rotateupdate-client WRITE (client)
update_webhookEdit a webhook's name, description, enabled state, access mode or key rotation, with its current version.PUT /api/v1/client/{clientId}/webhook/{webhookId}update-client WRITE (client)

Full input fields for every tool: references/tools.md.

Recommended workflows

Connect a sending system

  1. create_webhook with a name, a slug (the permanent address segment) and an access mode (api_key by default). The response carries the webhook's address and its first key, Default — the key secret is returned once, so hand it to the sender straight away.
  2. Configure the sender to POST to the address with the key in X-Maison-Key (or Authorization: Bearer).
  3. add_webhook_key for each further sending app, so the request log shows which app called.
  4. Point an agent at it: update_agent with the webhook id in scope.webhookIds.
  5. list_webhook_requests to confirm the first request arrived and was accepted.

Rotate or recover a key

  1. reveal_webhook_key returns a live key's secret again (the reveal is recorded in the hotel's activity log; it rotates the key first when automatic rotation is due).
  2. rotate_webhook_key with the key's version issues a new secret; the previous one keeps working for 24 hours so the sender can switch.
  3. revoke_webhook_key stops a key at once.

Tips

  • Automatic rotation is lazy: a due key rotates on its next inbound request or reveal, never on a schedule.
  • Request bodies are kept for 90 days; the log row stays after that with body: null.
  • A webhook does nothing on its own — it starts work only when an enabled agent lists it as an input.

Pitfalls

  • The address (/webhooks/{clientId}/{slug}) never changes; to get a new one, create a new webhook.
  • The last live key of an api_key webhook cannot be revoked (409 last_key); switch the webhook to open access instead.
  • Switching a webhook to open revokes every live key; switching back creates a new Default key, returned once.
  • Never log or echo a key secret back to the user beyond the one hand-off they asked for.
  • Revealing, rotating and adding keys need WRITE on update-client; a READ-only key can list webhooks and the request log but never sees a secret.

Calling conventions

Same tool, three transports — pick whichever your runtime already speaks. Always send x-api-key.

bash
# REST
curl -X POST "https://maison-labs.com/api/v1/client/<clientId>/webhook/<webhookId>/key" -H "x-api-key: $MAISON_API_KEY" -H "content-type: application/json" -d '{ "name": … }'
json
// MCP (https://maison-labs.com/mcp, Streamable HTTP): tools/call
{ "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": { "name": "add_webhook_key", "arguments": { "name": … } } }
json
// A2A (https://maison-labs.com/a2a): tasks/send with a data part
{ "jsonrpc": "2.0", "id": 1, "method": "tasks/send", "params": { "message": { "role": "user", "parts": [{ "type": "data", "data": { "tool": "add_webhook_key", "input": { "name": … } } }] } } }

Errors are the same everywhere: 401 no/invalid key; 403 forbidden with details.missing (the grants you lack — fall back to the composite's parts or stop); 403 not_entitled (the hotel's plan lacks the feature); 404, 409, 413 too_large, 503. Inputs that fail validation return 400 invalid_input with the Zod issues — fix and retry once.