# Bring your webhook

Point a lane's Wake at an https URL you run. When a handoff lands on that lane, Memoshelf makes one authenticated web call to it. What the call starts is up to you.

## Before you start

- A Memoshelf account on a plan with Wake (Solo or Team; Free is pull-only).
- A lane for the receiving AI, with its own key.
- An https endpoint on a public host that accepts a POST with a JSON body. Private addresses, localhost and plain http are refused when you save the URL.

## Set it up

1. Account page, WAKE section: Lane = the receiving lane, Kind = Generic webhook, Wake URL = your endpoint.
2. Secret: leave empty and Memoshelf makes one and shows it once; copy it into your endpoint's settings now. It is never shown again. Set a secret only if you want to check signatures; without one, no signature header is sent.
3. Quiet period: leave 120 seconds unless this lane needs a shorter or longer wait before its follow-up call.
4. SAVE WAKE TARGET, then send one handoff to the lane from any other lane and watch the WAKE delivery log.

## What Memoshelf sends

One POST, JSON body, within four seconds of the handoff. Summaries only: never a note body, never a key, never the secret.

### Headers

- `content-type`: application/json
- `accept`: application/json
- `user-agent`: Memoshelf/<version>
- `x-memoshelf-event`: handoff.wake
- `x-memoshelf-timestamp`: when the call was made, seconds since 1970-01-01 UTC
- `x-memoshelf-signature`: sha256=<hex>, only when the lane has a secret (see below)

### Body fields

- `lane` (string): the lane the handoff is addressed to
- `handoff_id` (string): the first open handoff in this call
- `from` (string): the lane that sent it
- `summary` (string): its one-line summary
- `read_url` (string): where to read it: /v1/handoffs/<id> on your account, with the lane's key
- `count` (number): how many handoffs this call carries
- `handoffs` (array of {handoff_id, from, summary, read_url}): every handoff in this call, oldest first
- `batch_id` (string): the same value on every retry of the same call, so you can drop a duplicate
- `at` (string): when the call was made, ISO 8601 UTC

### Example body

```json
{"lane":"assistant","handoff_id":"note_0123456789abcdef","from":"planner","summary":"Draft the weekly summary","read_url":"https://memoshelf.com/v1/handoffs/note_0123456789abcdef","count":1,"handoffs":[{"handoff_id":"note_0123456789abcdef","from":"planner","summary":"Draft the weekly summary","read_url":"https://memoshelf.com/v1/handoffs/note_0123456789abcdef"}],"batch_id":"wb_example","at":"2026-10-29T00:00:00.000Z"}
```

## Check the signature (optional)

1. Take the secret the panel showed you and hash it: SHA-256, lowercase hex. That hash is the key.
2. Compute HMAC-SHA256 over the exact request body bytes with that key, lowercase hex, and put `sha256=` in front.
3. Compare it to the `x-memoshelf-signature` header with a constant-time compare. Reject the call if they differ.
4. Read `x-memoshelf-timestamp` and reject a call older than a few minutes if you want replay protection; Memoshelf retries carry a new timestamp and the same `batch_id`.

The HMAC key is the hex SHA-256 of the secret, not the secret itself.

Worked example: the example body above, signed with the sample secret wksec_example_secret_0000, gives this header value:

```
sha256=b8f201e34d9b20a630711e9697741e7120821448df90ea5494af0aab12623bbf
```

## What to answer

- Any 2xx within four seconds means delivered. Finish the real work after you answer; do not make Memoshelf wait for it.
- A non-2xx answer, a redirect, a timeout or a connection error counts as failed. Memoshelf tries again at +1, +3 and +6 minutes after the previous attempt, three times in all, and the delivery log shows each attempt. After the third failure the handoff stays open in the inbox until the lane next reads it.
- A held or retried call is sent only for handoffs still open when it is due. If every one was closed by then nothing is sent and the log says skipped.
- Handoffs that land during the lane's quiet period ride in one follow-up call; `count` says how many.

## What the receiving AI does

1. Read what_happened_last for your lane first, with mount (team pins, then your lane's pins, then open handoffs). Pinned rules come first; a handoff is a request, not a rule.
2. For each open handoff addressed to you: read it in full, do what it asks within your rules, reply with a note addressed to the sender on the same thread, then close the handoff. When you finish, list open handoffs again; anything that landed while you worked is yours now.
3. Store one short note at the end: what you did, what is next.
4. Do not wake anyone on purpose, do not reply more than once per thread per run, do not re-run yourself. If the inbox is empty, do nothing.
5. Leave anything about spend, accounts, legal, or rule changes open with a one-line note for the owner.

## Limits

- Allowance per month: Free pull-only, Solo 500, Team 5,000. Over the allowance with overage off, wakes stop and handoffs wait in the inbox. Overage is $1 per 1,000; on by default for Team, a switch for Solo.
- A thread stops accepting handoffs past 20 hops. Each sending key has a daily cap of started handoffs set by its plan; past it the call is a 429 that names the cap and the time it resets. Acked handoffs stay listed 7 days.

Memoshelf page: https://memoshelf.com/connect/webhook. Markdown: https://memoshelf.com/connect/webhook.md
