Skip to content

Capture Webhook ​

The capture webhook turns a voice note or a piece of text into an Inbox task. Any device, app, or script that can send an HTTP request posts the text, and optionally an audio recording, to your own cloud server. The server creates the task, attaches the audio, and your devices pick both up on the next sync.

This needs the self-hosted cloud server. If you run Mindwtr without a server, capture from the phone share sheet or Siri instead.

The endpoint ​

text
POST /v1/capture

Every request carries the same bearer token as the rest of the API, in an Authorization: Bearer <token> header. The body can be multipart/form-data, application/json with the same field names, or text/plain, where the whole body is the transcription. Only multipart/form-data can carry audio: JSON and plain-text requests are text only, and an audio field inside JSON is ignored. Unknown fields are ignored.

Text only ​

bash
curl -X POST https://your-server.example/v1/capture \
  -H "Authorization: Bearer $MINDWTR_TOKEN" \
  -H "Content-Type: text/plain" \
  --data "Call the dentist about the crown"

Audio with a transcription ​

bash
curl -X POST https://your-server.example/v1/capture \
  -H "Authorization: Bearer $MINDWTR_TOKEN" \
  -F "transcription=Call the dentist about the crown" \
  -F "audio=@note.m4a" \
  -F "recordedAt=1756900000000" \
  -F "client=Pebble Index 01"

Fields ​

FieldWhat it does
transcriptionThe captured text. The first line becomes the task title, and the full text becomes the description. text and title are accepted as other names for the same field.
audioThe recording to attach to the task. It syncs to your devices like any other attachment. It is only read from a multipart/form-data request.
recordedAtWhen the capture happened, as epoch milliseconds or an ISO 8601 timestamp. It becomes the task's creation time when it is valid and not in the future.
clientA short label for the device or app that sent the capture. It is accepted and ignored, so senders such as the Pebble app keep working.
captureIdOptional. A UUID the sender chooses for this capture; it becomes the new task's id. Send the same value again on a retry and the server answers 200 with "replayed": true and adds nothing. A malformed value is rejected with 400.

Send at least one of transcription and audio. The recording can be m4a, mp4, aac, mp3, wav, ogg, or webm.

Responses ​

StatusMeaning
201The task was created. The response body is the new task.
400Neither a transcription nor an audio file was sent.
401The token is missing or wrong.
413The request is over the server's size limit: an audio upload above the attachment limit, or a transcription above the text limit.
415The audio file type is not supported.

Capture-only token ​

A device that only captures should not hold a token that can read, change and delete everything in your account. A capture-only token is a second secret for the same account. The server accepts it on POST /v1/capture and nowhere else.

Create one with your full token. The label is optional. The response shows the token once. The server never stores it in clear, so copy it now.

bash
curl -X POST https://your-server.example/v1/capture-tokens \
  -H "Authorization: Bearer $MINDWTR_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{"label":"Pebble ring"}'
json
{
  "id": "6f1c2d1e-8a4b-4c3e-9f2a-1b2c3d4e5f60",
  "token": "mwc_…",
  "label": "Pebble ring",
  "createdAt": "2026-09-06T10:12:00.000Z"
}

List the tokens on the account. The response has id, label and createdAt for each token, and no secrets.

bash
curl https://your-server.example/v1/capture-tokens \
  -H "Authorization: Bearer $MINDWTR_TOKEN"

Revoke one by its id.

bash
curl -X DELETE https://your-server.example/v1/capture-tokens/<id> \
  -H "Authorization: Bearer $MINDWTR_TOKEN"
  • A capture-only token works only on POST /v1/capture. There it behaves exactly like the full token: same body formats, same responses, same rate limit as the account. Every other route answers 403.
  • An account can hold up to 20 capture-only tokens.
  • In allowlist mode, a capture-only token stops working when the account's full token is removed from the allowlist.

Pebble Index 01 ​

The Pebble Index 01 app sends voice notes in exactly this format, and it lets you add your own request headers. So there is no glue code: you only fill in two settings.

  1. Open the Pebble app on your phone and go to the webhook settings for voice notes
  2. Set the webhook URL to https://your-server.example/v1/capture, with your own server address in place of the example
  3. Add a request header named Authorization with the value Bearer <token>, using a capture-only token from the section above. Your full token also works, but the capture-only token is the safer choice for a device that only records notes
  4. Record a note on the watch. It reaches your Inbox on the next sync, with the transcription as the task and the recording attached

Other devices and automations ​

Nothing here is Pebble-specific. Anything that can make an HTTP POST works the same way:

  • iOS and Apple Watch Shortcuts: a Get contents of URL action, method POST, with the header and a text field. See the Capture from Apple Watch recipe on the Apple Shortcuts page
  • Android automation apps such as Tasker: an HTTP Request action with the same URL and header
  • Home Assistant: a rest_command that posts the text of an automation or a voice assistant result
  • Shell scripts and cron jobs: the curl commands above, with the token in an environment variable

Mindwtr is free, open source, and local-first.
Getting Things Done and GTD are registered trademarks of the David Allen Company. Mindwtr is not affiliated with, endorsed by, or sponsored by the David Allen Company.