ShrubberyDocs
Sign in

POST /api/v1/inbox

Ingest an external commitment as a Pending_Handshake Shrubbery. The row appears immediately in the assignee's Accord; Inngest fires a Nudge through the assignee's preferred channel. The token owner is recorded as the assigner.

Quick start

curl -X POST https://shrubbery.eu/api/v1/inbox \
  -H "Authorization: Bearer $SHRUBBERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "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"
  }'

A successful response is 201 Created with the new Shrubbery's id.

Reference

Notes

  • Assigner = token owner. Inbox tokens cannot mint rows on behalf of other users. The assignerEmail field exists for human readability of the audit trail; the resolved user must match token.user_id.
  • External mapping uniqueness. Two leads may independently track the same external ticket ((externalSystem, externalId, assigner) is unique, not (externalSystem, externalId) alone). A replay from the same token returns 409 duplicate_external_ref.
  • Nudge fan-out. Inngest's handshakeRequestedEvent fires once per successful insert. Channel selection (email / Teams / Google Chat) is governed by the assignee's notification preferences. Delivery failures are retried by Inngest, not by the inbox route.
  • No partial parsing. If any field fails Zod validation the whole payload is rejected — no fields persist.

Last updated: 17 May 2026