Inbox Webhook Integration
Overview
The Inbox webhook lets an external system (Jira, Linear, GitHub, or a custom tool) push a commitment directly into Shrubbery as a Pending_Handshake row. The Knight receives a Nudge and sees the row in their Accord without any Lead action in-app. This guide walks through setting up the integration end-to-end.
For the raw API reference, see POST /api/v1/inbox.
Actors
- Lead — mints the API Token, monitors the Garden for incoming rows.
- External System — sends the HTTP call on each relevant event (e.g. issue created, ticket assigned).
- Knight — receives the Nudge and Handshakes in the Accord.
- Squire — not involved. No AI extraction on Inbox rows.
Flow
1. Mint an API Token
- Lead navigates to
/settings→ API Tokens → Generate new token. - Copy the raw token value immediately — it is shown only once.
- Store it as a secret in the external system's webhook configuration (e.g.
SHRUBBERY_TOKENin GitHub Actions, a Jira webhook secret field).
2. Configure the external webhook
Point the external system's outbound webhook at POST https://shrubbery.eu/api/v1/inbox with:
POST /api/v1/inbox HTTP/1.1
Authorization: Bearer <your-token>
Content-Type: application/json
{
"assignerEmail": "lead@example.com",
"assigneeEmail": "knight@example.com",
"description": "Ship the Q3 report",
"deadline": "2026-09-30T17:00:00.000Z",
"externalSystem": "jira",
"externalId": "PROJ-123"
}externalSystem and externalId should identify the source ticket uniquely within the external system. They enable deduplication and power the Sync flow later.
3. Verify the integration
A successful call returns 201 Created with the Shrubbery's id. Confirm by checking:
- The row appears in the Garden under
Pending_Handshake. - The assignee received a Nudge via their preferred channel.
- The Audit Trail shows
created+nudge_sentevents withactor_kind = api_token.
4. Pair with Sync for close events
Once the integration is live, also configure a POST /api/v1/sync call for when the external issue closes. See Sync Webhook Integration.
Edge cases
- Duplicate deliveries — the endpoint is idempotent on
(externalSystem, externalId, assigner). A webhook retry with the same payload returns409 duplicate_external_ref; no duplicate row is created. - Unknown assignee email — if
assigneeEmaildoes not match any Shrubbery user, the request returns422 assignee_not_found. The external system should handle this gracefully (e.g. alert the Lead to add the user first). - Missing deadline —
deadlineis required. If the external system does not provide one, the integration layer should supply a default (e.g. 30 days from creation) rather than omitting the field. - Nudge delivery failure — if Inngest cannot deliver the Nudge (channel misconfigured, transient failure), it retries automatically. The Shrubbery row exists regardless; only the Nudge delivery is retried.
Related concepts
Last updated: 22 June 2026