Skip to content

Bridgit · Developer guide · Support

Reference snapshot: app 1.6.0, API revision 8, reviewed 29 October 2026. Generated by the app; editorial changes replace the original owner’s name and correct the build-version instructions. Upstream reference. Your paired phone’s live guide is authoritative for its installed build.

Bridgit API

Bridgit: Comprehensive Device Bridge for Android, version 1.6.0, API revision 8. What an AI agent can ask an Android phone to do, and the exact calls. Base URL http://<phone>:8734/v1 on the owner's Tailscale network; every call needs Authorization: Bearer <key> except where noted. A running phone also serves this live at GET /v1/guide and GET /v1/openapi.json.

Supported Agent Requests:

Available now

Take a photo

An agent can take a photo with the front or back camera. Android's green dot and a Bridgit notification show every time.

Options
For example

From your laptop: "Is the stove off?" Your agent takes a photo of the kitchen and tells you.

API
POST /v1/camera/snapshot Idempotency-Key details

Take a photo now.

POST /v1/camera/snapshot {"camera":"rear","zoom":2}
Available now

Record a short clip

An agent can record 1 to 120 seconds of audio and get it back as a file.

Options
For example

"Listen to the next 30 seconds of the meeting and give me the action items."

API
POST /v1/mic/record Idempotency-Key details

Record an audio clip.

POST /v1/mic/record {"duration_seconds":5}
Available now

Your latest screenshot or photo

One call returns the newest screenshot or camera photo, sized for an AI to read. It can also wait for the next one you take.

Options
For example

You screenshot an error on your phone; your agent already has it and explains the fix.

API
GET /v1/image/last details

The newest image of a type; with since and wait, waits for the next one.

GET /v1/image/last?type=screenshot
Available now

Questions and notices to you

Agents send you a notice, or a question with buttons, choices or a text reply, and receive your answer through the API or callback when the connection is available. They can also read it aloud.

Options
For example

"Pay this invoice? $11.99" [Pay] [Not now]. Your reply is returned to the agent. Any payment requires an authorized payment tool and confirmation of the actual result.

API
POST /v1/interactions Idempotency-Key details

Send the owner a notice, a question (buttons, text reply, choice, links), an HTML card or a live text panel.

POST /v1/interactions {"kind":"question","title":"Pay this invoice?","controls":[{"type":"button","id":"yes","label":"Pay","style":"primary"},{"type":"button","id":"no","label":"Not now"}]}
GET /v1/interactions details

Your interactions, newest first.

GET /v1/interactions?status=answered
GET /v1/interactions/{id} details

One of your interactions; with wait, holds until the owner answers or closes it.

GET /v1/interactions/12?wait=55
DELETE /v1/interactions/{id} details

Cancel one of your interactions.

DELETE /v1/interactions/12
GET /v1/events details

Your events, oldest first: answers, closes, expiries, switch changes.

GET /v1/events?since=0&wait=55
Available now

Rich HTML cards

Instead of plain buttons, an agent can send a small HTML page (charts, forms, choices) that runs in an isolated view on the phone without network access.

Options
For example

Your travel agent shows three flights as cards with prices and a map; you tap one to book.

API
POST /v1/interactions Idempotency-Key details

Send the owner a notice, a question (buttons, text reply, choice, links), an HTML card or a live text panel.

POST /v1/interactions {"kind":"question","title":"Pay this invoice?","controls":[{"type":"button","id":"yes","label":"Pay","style":"primary"},{"type":"button","id":"no","label":"Not now"}]}
GET /v1/interactions/{id} details

One of your interactions; with wait, holds until the owner answers or closes it.

GET /v1/interactions/12?wait=55
Available now

Live text panel

An agent streams text into the lower half of the screen and it scrolls as it arrives, like the transcript of an AI session. Pause the scrolling or close it any time.

Options
For example

Claude Code is fixing a bug on your laptop; you watch what it's doing on the phone while you make coffee.

API
POST /v1/interactions Idempotency-Key details

Send the owner a notice, a question (buttons, text reply, choice, links), an HTML card or a live text panel.

POST /v1/interactions {"kind":"question","title":"Pay this invoice?","controls":[{"type":"button","id":"yes","label":"Pay","style":"primary"},{"type":"button","id":"no","label":"Not now"}]}
POST /v1/text/stream details

Add text to your live text panel (an interaction of kind text); it scrolls on the phone as it arrives.

POST /v1/text/stream {"interaction_id":"42","append":"Claude: running the tests now...\n"}
DELETE /v1/interactions/{id} details

Cancel one of your interactions.

DELETE /v1/interactions/12
Available now

Send a screenshot

An agent sees what's on your screen right now, with no prompt each time; a notification shows every capture.

Options
For example

"What does this error on my phone mean?" The agent takes a screenshot and reads it.

API
POST /v1/screen/capture Idempotency-Key details

What's on the owner's screen right now (D17, no prompt once he's turned it on).

POST /v1/screen/capture?size=agent
Available now

Phone status and context

Battery, network, ringer, Do Not Disturb and screen/lock status. An unlocked interactive screen is reported as in use.

Options
For example

Before calling you, an agent checks whether your phone is in use or on silent.

API
GET /v1/phone/status details

Battery, network, screen and sound status, with as_of.

GET /v1/phone/status
GET /v1/phone/context details

Screen and lock context; likely=in_use or unknown, with the rule.

GET /v1/phone/context
Available now

Location details

Where the phone is, on request only: latitude and longitude (x, y), altitude (z), accuracy, speed and heading, and how old the fix is. Address lookup if you turn it on. No tracking unless you choose it.

Options
For example

"How long until I'm home?" The agent checks where you are and the traffic.

API
GET /v1/location details

Where the phone is now, with altitude, speed, heading and the compass.

GET /v1/location
Available now

Flash the light

Turn the torch on for up to ten minutes, with automatic off and an owner Stop button.

Options
For example

Your door-camera agent flashes the light so you know someone is at the door.

API
GET /v1/flashlight details

Whether the torch is on.

GET /v1/flashlight
POST /v1/flashlight Idempotency-Key details

Set torch with mandatory auto-off.

POST /v1/flashlight
Available now

Phone controls

Do Not Disturb, ringer, volume and brightness, put back as they were afterwards.

Options
For example

Bedtime routine: your agent turns on Do Not Disturb until 7 am.

API
POST /v1/phone/dnd Idempotency-Key details

Set Do Not Disturb, with optional restoration.

POST /v1/phone/dnd
POST /v1/phone/sound Idempotency-Key details

Change ringer or volume.

POST /v1/phone/sound
POST /v1/phone/brightness Idempotency-Key details

Set brightness or automatic brightness.

POST /v1/phone/brightness
POST /v1/phone/undo Idempotency-Key details

Restore pending timed phone changes, preserving subsequent manual changes.

POST /v1/phone/undo
Available now

City tour

A guided walk: you pick the kind of tour, and every minute your agent gets where you are, which way you face and the photos you just took. It tells you about what's around you, and you can ask it questions out loud.

Options
For example

Pick "Architecture" and walk; when you photograph a church, your agent tells you who built it and why it looks that way.

API
GET /v1/tour details

Your running City tour, if the owner started one with you (D30).

GET /v1/tour
DELETE /v1/tour details

End your City tour.

DELETE /v1/tour
GET /v1/events details

Your events, oldest first: answers, closes, expiries, switch changes.

GET /v1/events?since=0&wait=55
POST /v1/speaker/say Idempotency-Key details

Read text aloud on the phone (its own text-to-speech).

POST /v1/speaker/say {"text":"On your left is the old town hall, built in 1360.","tour_id":"t123"}
POST /v1/speaker/play Idempotency-Key details

Play audio on the phone's speaker: send audio/* bytes as the body, or {"url"} (public https).

POST /v1/speaker/play (Content-Type: audio/mpeg, body = the MP3)
GET /v1/gallery/photo/{id} details

One gallery image, sized for you.

GET /v1/gallery/photo/87567?size=agent
Available now

Find my phone

Ring and vibrate for up to a minute, respecting your sound and Do Not Disturb settings.

Options
For example

Phone lost in the sofa: ask any agent to ring it.

API
POST /v1/phone/ring Idempotency-Key details

Ring and vibrate within Android sound restrictions.

POST /v1/phone/ring
DELETE /v1/phone/ring details

Stop ringing and vibration.

DELETE /v1/phone/ring
Available now

Sensors

Light, pressure, steps, motion and orientation, one reading each.

Options
For example

An agent notices it's dark and you're still, and holds non-urgent messages.

API
GET /v1/sensors details

Supported fresh sensor values or explicit unavailable status.

GET /v1/sensors
Available now

Videos and downloads

Find recent videos, take a frame from one, and pick a file from Downloads for an agent.

Options
For example

"Get the frame at 0:12 from the video I just took."

API
GET /v1/gallery/videos/recent details

Accessible videos and metadata.

GET /v1/gallery/videos/recent
GET /v1/gallery/video/{id} details

Accessible video raw, or a JPEG frame.

GET /v1/gallery/video/{id}
GET /v1/downloads details

Your downloads transfers, retained 30 days on the phone.

GET /v1/downloads
Available now

Files to your phone

Agents send PDFs, images and other files; they land in the Inbox and can be saved to Downloads.

Options
For example

Your accounting agent sends this month's invoice PDF to your phone.

API
POST /v1/files Idempotency-Key details

Receive a file on the phone (25 MB maximum).

POST /v1/files
GET /v1/files details

Your files transfers, retained 30 days on the phone.

GET /v1/files
Available now

Share to an agent

Share a photo, link or text from any app straight to Grok or Claude.

Options
For example

Share a restaurant link to your agent: "Book this for Friday."

API
GET /v1/shares details

Your shares transfers, retained 30 days on the phone.

GET /v1/shares
GET /v1/shares/{id} details

Read your selected transfer bytes.

GET /v1/shares/{id}
Available now

Short video clips

1 to 30 seconds of 720p or 1080p MP4. Audio is off by default and needs a microphone grant.

Options
For example

"Record the dishwasher noise so I can describe it to the repair shop."

API
POST /v1/camera/video Idempotency-Key details

Record an MP4, returned raw (HTTP: 40 MB maximum; MCP: 6 MB, may stop early).

POST /v1/camera/video
Available now

Read text on the phone

Bundled Latin-script text recognition runs on the phone; only the result leaves it.

Options
For example

Read the serial number from a photo without uploading the picture.

API
POST /v1/ocr Idempotency-Key details

Recognize Latin-script text locally; no image upload.

POST /v1/ocr
Available now

Transcribe clips on the phone

Request transcribe=true on a microphone clip. Requires Android on-device recognition and an installed offline language; no cloud fallback.

Options
For example

Dictate a note for 20 seconds; the agent gets the words.

API
POST /v1/mic/record Idempotency-Key details

Record an audio clip.

POST /v1/mic/record {"duration_seconds":5}
Available now

Screen sharing as a fallback

If you'd rather not turn on Accessibility, approve screen access once, for 1 hour or for 16 hours.

Options
For example

Help your agent debug an app for the next hour.

API
POST /v1/screen/grant Idempotency-Key details

Request owner-approved MediaProjection screen access.

POST /v1/screen/grant
GET /v1/screen/grants details

Your screen requests and active grant.

GET /v1/screen/grants
POST /v1/screen/share/capture Idempotency-Key details

Capture a JPEG using your active owner-approved grant.

POST /v1/screen/share/capture
DELETE /v1/screen/grant details

End your screen-sharing grant.

DELETE /v1/screen/grant
Available now

App usage

Read foreground-time summaries after granting Android Usage access. Android buckets can extend past the requested interval.

Options
For example

Weekly review: "You spent 6 hours in email this week."

API
GET /v1/usage details

App foreground time from Android usage buckets (maximum seven days).

GET /v1/usage
Available now

Health Connect

Read permitted steps, sleep and heart-rate source records. No health writes; maximum 100 records per query.

Options
For example

Your coach agent adjusts tomorrow's plan to last night's sleep.

API
GET /v1/health/records details

Read-only steps, sleep or heart-rate source records (maximum 100).

GET /v1/health/records
Available now

Read notifications

Read up to 100 active notification texts received since the listener connected. Explicit notification access required; memory only.

Options
For example

"Summarise everything that pinged me during the meeting."

API
GET /v1/notifications details

Up to 100 active notification texts since service connected; RAM only.

GET /v1/notifications
Available now

Copy to clipboard

An agent puts text on your clipboard after you approve it.

Options
For example

Your agent copies the 2-factor backup code so you can paste it.

API
POST /v1/clipboard Idempotency-Key details

Queue a five-minute owner approval; never copies until owner taps Copy.

POST /v1/clipboard
GET /v1/clipboard/{id} details

Your clipboard request: pending, copied, denied or expired.

GET /v1/clipboard/{id}
Available now

Play an audio file

An agent sends a sound, a voice message or text to read out, and the phone plays it on its speaker. Newer audio from the same agent replaces what's waiting, so it keeps up with you.

Options
For example

Your reminder agent plays "Time to leave for the airport" in its own voice.

API
POST /v1/speaker/play Idempotency-Key details

Play audio on the phone's speaker: send audio/* bytes as the body, or {"url"} (public https).

POST /v1/speaker/play (Content-Type: audio/mpeg, body = the MP3)
POST /v1/speaker/say Idempotency-Key details

Read text aloud on the phone (its own text-to-speech).

POST /v1/speaker/say {"text":"On your left is the old town hall, built in 1360.","tour_id":"t123"}
GET /v1/speaker details

What's playing, and your queued sounds.

GET /v1/speaker
DELETE /v1/speaker details

Stop your audio and clear your queue.

DELETE /v1/speaker
Needs your OK

Listen for a word on the phone

On-device word spotting while you allow it, sending only what follows the word. Needs a change to the "no always-on listening" rule.

For example

Say "Bridgit, note" and the next sentence goes to your notes agent.

API

Not built yet. Spec PRD-09 in docs/bridgit-spec-v2.md describes the planned calls.

Needs your OK

Messages, contacts, calendar, calls

Read and, with your approval each time, send.

For example

"Text Sam I'm 10 minutes late" — you approve on the phone.

API

Not built yet. Spec 8.22, Q1 in docs/bridgit-spec-v2.md describes the planned calls.

Needs your OK

Location history and places

Optional history kept on the phone, and "tell me when I get home".

For example

Grok reminds you to water the plants when you arrive home.

API

Not built yet. Spec CAP-20a, Q14 in docs/bridgit-spec-v2.md describes the planned calls.

How Bridgit works

Available now

Add an agent in a minute

Bridgit makes a setup prompt with the agent's own key, the address and the rules. Use it with a compatible agent whose HTTP or MCP tools can reach the phone’s Tailscale network.

For example

You add Claude: name it, copy the prompt, paste it into Claude. The screen turns to "Claude connected" as soon as it calls.

API
GET /v1/health details

Is Bridgit up, and which agent you are.

GET /v1/health
POST /v1/pair no key needed details

Fetch your key with a 6-digit code shown on the phone (alternative to the setup prompt).

POST /v1/pair {"code":"482913"}
GET /v1/tools/bridget no key needed details

The bridget command-line helper (Python, no secrets inside).

GET /v1/tools/bridget
Available now

One key per agent

Every agent has its own key. Rotate it or remove the agent in one tap; the old key stops at once and the agent is told why.

For example

You pasted Grok's prompt into the wrong chat. Rotate Grok's key; the leaked one is dead in a second.

API
GET /v1/health details

Is Bridgit up, and which agent you are.

GET /v1/health
Available now

Everything is logged

Every request, switch change and agent note is in Activity on the phone. Agents can read and follow the log too, so they know what they did.

Options
For example

Codex checks yesterday's log to see why a photo failed; you scroll Activity to see who did what.

API
GET /v1/log details

Read the log; with order=asc&since=<id>&wait=55 it follows new entries.

GET /v1/log?agent=me&limit=20
GET /v1/log/{id} details

One log entry.

GET /v1/log/48213
GET /v1/log/stats details

Counts, errors and p50/p95 time per agent and endpoint.

GET /v1/log/stats?since=2026-10-27T00:00:00%2B01:00
GET /v1/log/export details

Every matching entry as JSONL or CSV.

GET /v1/log/export?format=csv&agent=me
Available now

Agent notes

Agents can write short notes into the log.

For example

Your fridge-check agent writes "milk low" so you see it in Activity.

API
POST /v1/log Idempotency-Key details

Write a note to the agent channel.

POST /v1/log {"message":"checked fridge photo, milk low"}
Available now

The API explains itself

Agents read a live guide and an OpenAPI file that list what's switched on, every call and every error.

For example

A brand-new agent reads the guide and learns everything without a manual.

API
GET /v1/guide details

This guide, generated live (Markdown).

GET /v1/guide
GET /v1/openapi.json details

OpenAPI 3.1 description of every endpoint.

GET /v1/openapi.json
GET /v1/capabilities details

What's switched on and ready, and why not.

GET /v1/capabilities
Available now

Agents learn what's new

Every reply says which API revision Bridgit speaks. After an update, agents are told there's something new until they read the list of changes, so they pick up new features by themselves.

For example

Bridgit gains camera zoom; the next time Grok calls, it reads what's new and starts using zoom.

API
GET /v1/changes details

What's new in the API since a revision you know (API-14).

GET /v1/changes?since=2
Available now

Report a bug or ask for a feature

From any screen: the last screen is attached, plus screenshots and the recent log. Developer agents read reports and mark them fixed; you confirm or say it's still broken.

Options
For example

The app misbehaves; you report it in 10 seconds. Claude picks it up, fixes it and marks it fixed.

API
GET /v1/feedback details

Bug reports and feature requests filed on the phone (developer agents only).

GET /v1/feedback?status=new
GET /v1/feedback/{id} details

One report with its text, images, attached log and history (developer agents only; marks a new report seen).

GET /v1/feedback/7
POST /v1/feedback/{id}/status Idempotency-Key details

Move a report: in_progress, fixed, wont_fix or duplicate (developer agents only; FBK-11a).

POST /v1/feedback/7/status {"status":"in_progress","note":"Looking at it"}
POST /v1/feedback Idempotency-Key details

File a bug report or feature request yourself (any agent; images from developer agents only).

POST /v1/feedback {"kind":"bug","description":"image/last returned 500 twice"}
Available now

Check for updates

Bridgit finds a new version, checks it really is Bridgit, and lets Android install it after you confirm.

For example

A fix ships; your phone offers the update the next time you open Bridgit.

Available now

You stay in control

Every feature starts off and has its own switch. Pause listening in one tap. Access shows each Android permission with one button to the right page.

For example

Going into a meeting: turn off Camera and Microphone from Home in two taps.

API
GET /v1/capabilities details

What's switched on and ready, and why not.

GET /v1/capabilities
Available now

Only over Tailscale

Bridgit answers only on your private Tailscale network, never the open internet.

For example

Your agents on your Mac and your server can reach the phone; nobody else can.

Available now

Use Bridgit over MCP

Agents that speak MCP (Claude Code, Codex and others) add Bridgit as a tool server with their own key, and every feature appears as a tool.

Options
For example

Add Bridgit to Claude Code once; from then on "take a photo of my desk" just works.

API
POST /v1/mcp details

Model Context Protocol (Streamable HTTP, JSON replies): every endpoint you can use is an MCP tool.

POST /v1/mcp {"jsonrpc":"2.0","id":1,"method":"tools/list"}
Available now

Inbox

One place for every question, notice, file and share between you and your agents.

For example

See what Grok asked you this morning and what you answered.

API
GET /v1/interactions details

Your interactions, newest first.

GET /v1/interactions?status=answered
GET /v1/files details

Your files transfers, retained 30 days on the phone.

GET /v1/files
GET /v1/shares details

Your shares transfers, retained 30 days on the phone.

GET /v1/shares
Available now

Events and callbacks

Agents get told the moment something happens: a question answered, a new screenshot, a switch changed.

For example

Your agent waits for your answer without asking again and again.

API
GET /v1/events details

Your events, oldest first: answers, closes, expiries, switch changes.

GET /v1/events?since=0&wait=55
POST /v1/callback/test details

Send a signed test event to the callback URL the owner set for you (EVT-05/06).

POST /v1/callback/test
Available now

Quick Settings tile

Pause or resume Bridgit from the notification shade.

For example

Pull down, tap Bridgit, and agents can't reach the phone until you tap again.

Available now

Per-agent permissions

Choose what each agent may use, for example photos for Claude but not for Grok.

For example

Let your shopping agent see the gallery but never the camera.

API
GET /v1/capabilities details

What's switched on and ready, and why not.

GET /v1/capabilities
Needs your OK

Reach Bridgit without Tailscale (relay)

Agents that can't join Tailscale, like hosted assistants, leave jobs in an encrypted mailbox; a push wakes the phone.

For example

Muse, which runs on Meta's servers, takes a photo for you.

API

Not built yet. Spec 4.4, Q10 in docs/bridgit-spec-v2.md describes the planned calls.

Build an applet

An applet is a ready-made session between the owner and one agent, like City tour: the phone sends the agent data on a schedule or when the owner acts, and the agent answers out loud or with a question card. There are two ways to build one. Start with A; do B when the applet works and the owner wants a button for it.

A. Run it from your side (no app change)

Any paired agent can do this today with the calls below.

  1. Report your model once: POST /v1/me {"model","harness"}.
  2. Offer the applet with a question card: POST /v1/interactions with buttons, e.g. Start / Not now. Wait for the answer with GET /v1/interactions/{id}?wait=55.
  3. Keep one loop on GET /v1/events?since=<last id>&wait=55 (60 s timeout). If your harness only acts during a turn, run the wait as a background command so each event wakes you.
  4. Read what the applet needs on a timer you keep: GET /v1/location (with compass), POST /v1/camera/snapshot, GET /v1/image/last?type=photo, POST /v1/mic/record. Check GET /v1/capabilities first and ask the owner to switch on what is off.
  5. Talk back with POST /v1/speaker/say {"text"} (2-4 short spoken sentences; newer narration replaces what is queued) or a question card when you need a choice.
  6. Stop when the owner says so (a Stop button on your card) or after a time limit you announced. Only capture while the applet runs; every capture is shown and logged.

B. Add it to the Bridgit app (a coding agent with the repository)

Copy City tour. Each step names the City tour file to copy from; keep its rules.

  1. Write the spec first: a section next to 8.25 City tour in docs/bridgit-spec-v2.md with numbered rules like TOUR-01..07 (what it needs switched on, what is sent to whom, limits).
  2. Session engine: a manager like TourManager in tour/Tour.kt. One session at a time, one agent, sends <applet>.started (with a brief string telling the agent what to do), <applet>.tick, owner actions, and <applet>.ended through app.interactions.event(agentId, type, data). Create it in BridgeApp.
  3. Agent API: a Capability module like TourModule (register it in capability/Capability.kt), with an EndpointSpec for every call in api/Endpoints.kt and in Endpoints.all. Only the session's own agent may read it.
  4. Screen: a fragment like ui/tour/TourFragment.kt (setup: pick an agent and options, list what is missing; running: big buttons, what was said, End). Add it to res/navigation/nav_main.xml.
  5. Card: add it to res/layout/fragment_applets.xml and AppletsFragment, with a running chip.
  6. Tell agents: add an ApiChanges revision, a section in the live guide (api/SelfDescription.kt), and a "What can Bridgit do?" card in ui/more/WhatCanData.kt.
  7. Use the automatic APK version allocator; every APK build must reserve a fresh version name and code. Do not hardcode or lower the version counter, run ./gradlew testDebugUnitTest (ApiDocsTest checks every endpoint is documented), install, and try it on the phone with a real agent.

Rules every applet keeps: data goes only to the session's agent and only while it runs; the owner can always end it; nothing is kept afterwards except log lines.

All endpoints

GET /v1/health

Is Bridgit up, and which agent you are.

Returns: status, app, app_version, agent, listener_uptime_seconds, battery_level, charging, bind_address, port

GET /v1/health
GET /v1/capabilities

What's switched on and ready, and why not.

Returns: per capability: enabled, ready, blocked_reason, details; callback {set, host}

GET /v1/capabilities
GET /v1/guide

This guide, generated live (Markdown).

Returns: text/markdown

GET /v1/guide
GET /v1/openapi.json

OpenAPI 3.1 description of every endpoint.

Returns: application/json

GET /v1/openapi.json
GET /v1/changes

What's new in the API since a revision you know (API-14).

QueryTypeWhat
sinceintegerThe API revision you last read about; 0 or absent = everything

Returns: api_revision, app_version, changes[revision, app_version, date, items[what, endpoint]], links

GET /v1/changes?since=2
GET /v1/tools/bridget no key needed

The bridget command-line helper (Python, no secrets inside).

Returns: text/x-python

GET /v1/tools/bridget
POST /v1/pair no key needed

Fetch your key with a 6-digit code shown on the phone (alternative to the setup prompt).

BodyTypeWhat
code *string6-digit code from the phone

Returns: key, agent, base_url (once per pairing window)

Errors: pairing_closed, unauthorized, rate_limited

POST /v1/pair {"code":"482913"}
POST /v1/camera/snapshot Idempotency-Key

Take a photo now.

BodyTypeWhat
camerastringrear (default) or front
flashbooleanFire the flash (default false)
zoomnumberZoom ratio, e.g. 0.5 (ultra-wide), 1, 2, 5 (telephoto); the range is in /v1/capabilities after the first photo
max_width_pxintegerWidth limit, 64-20000, or null for full size (default 2048 unless size is given)
sizestringPreset: agent (1568 px, q85), thumb (512, q75), large (2560, q90), original
max_edge_pxintegerLong edge limit, 64-20000; overrides the preset
qualityintegerJPEG quality 40-100
rawinteger1 = return the image bytes, details in X-Bridget-* headers

Returns: captured_at, width_px, height_px, format, size_bytes, data_base64 (or JPEG bytes with raw=1)

Errors: capability_disabled, permission_denied, notifications_required, device_locked, sensor_busy, capture_timeout, service_start_blocked, payload_too_large

POST /v1/camera/snapshot {"camera":"rear","zoom":2}
POST /v1/mic/record Idempotency-Key

Record an audio clip.

BodyTypeWhat
transcribebooleanUse only Android on-device recognition; no cloud fallback
return_audiobooleantrue by default; false requires transcribe=true
languagestringOptional offline language, e.g. en-US
duration_seconds *integerWhole seconds, 1-120

Returns: recorded_at, duration_seconds, format (m4a), sample_rate_hz, size_bytes, data_base64

Errors: capability_disabled, permission_denied, notifications_required, sensor_busy, capture_timeout, service_start_blocked

POST /v1/mic/record {"duration_seconds":5}
GET /v1/image/last

The newest image of a type; with since and wait, waits for the next one.

QueryTypeWhat
typestringany (default), screenshot or photo (any, screenshot, photo)
sincestringISO time or gallery id: only an image added after it
waitintegerWith since: hold up to this many seconds (max 55) for a new image
sizestringPreset: agent (1568 px, q85), thumb (512, q75), large (2560, q90), original (agent, thumb, large, original)
max_edge_pxintegerLong edge limit, 64-20000; overrides the preset
max_width_pxintegerWidth limit, 64-20000
qualityintegerJPEG quality 40-100
rawinteger1 = return the image bytes, details in X-Bridget-* headers

Returns: id, type, taken_at, added_at, album, width_px, height_px, size_bytes, data_base64

Errors: capability_disabled, permission_denied, photo_not_found, too_many_waits

GET /v1/image/last?type=screenshot
POST /v1/screen/capture Idempotency-Key

What's on the owner's screen right now (D17, no prompt once he's turned it on).

QueryTypeWhat
sizestringPreset: agent (1568 px, q85), thumb (512, q75), large (2560, q90), original (agent, thumb, large, original)
max_edge_pxintegerLong edge limit, 64-20000; overrides the preset
max_width_pxintegerWidth limit, 64-20000
qualityintegerJPEG quality 40-100
rawinteger1 = return the image bytes, details in X-Bridget-* headers
BodyTypeWhat
modestringprivate (default): kept in memory, nothing saved

Returns: captured_at, width_px, height_px, format, size_bytes, mode, data_base64 (or raw=1 bytes)

Errors: capability_disabled, access_needed, notifications_required, device_locked, rate_limited, sensor_busy, not_supported, capture_timeout, service_start_blocked, payload_too_large

POST /v1/screen/capture?size=agent
GET /v1/log

Read the log; with order=asc&since=<id>&wait=55 it follows new entries.

QueryTypeWhat
channelstringComma list of audit, diagnostic, agent
agentstringAgent name or id; me for you; bridget for Bridgit's own entries
kindstringrequest, setting, agent, pairing, service, note, …
endpointstringEndpoint prefix, e.g. /v1/camera
resultstringok, error, or an error code
levelstringMinimum level: debug, info, warn, error
sincestringLog id or ISO time (exclusive id)
untilstringLog id or ISO time
qstringText in message or endpoint
limitinteger1-500, default 100
orderstringdesc (default) or asc (desc, asc)
cursorstringnext_cursor from the previous page
waitintegerTail mode: hold up to this many seconds (max 55) for a new entry

Returns: entries[], next_cursor, latest_id

Errors: invalid_parameter, too_many_waits

GET /v1/log?agent=me&limit=20
GET /v1/log/{id}

One log entry.

Returns: the entry

Errors: not_found

GET /v1/log/48213
GET /v1/log/stats

Counts, errors and p50/p95 time per agent and endpoint.

QueryTypeWhat
sincestringLog id or ISO time; default the last 24 h

Returns: by_agent[], by_endpoint[]

GET /v1/log/stats?since=2026-10-27T00:00:00%2B01:00
GET /v1/log/export

Every matching entry as JSONL or CSV.

QueryTypeWhat
formatstringjsonl (default) or csv (jsonl, csv)
channelstringComma list of audit, diagnostic, agent
agentstringAgent name or id; me for you; bridget for Bridgit's own entries
kindstringrequest, setting, agent, pairing, service, note, …
endpointstringEndpoint prefix, e.g. /v1/camera
resultstringok, error, or an error code
levelstringMinimum level: debug, info, warn, error
sincestringLog id or ISO time (exclusive id)
untilstringLog id or ISO time
qstringText in message or endpoint

Returns: application/x-ndjson or text/csv

GET /v1/log/export?format=csv&agent=me
POST /v1/log Idempotency-Key

Write a note to the agent channel.

BodyTypeWhat
message *stringUp to 1 KB
levelstringdebug, info (default), warn, error
dataobjectUp to 4 KB of JSON

Returns: id

Errors: invalid_parameter, rate_limited

POST /v1/log {"message":"checked fridge photo, milk low"}
GET /v1/audit

Deprecated alias of /v1/log?channel=audit (removed in v3).

QueryTypeWhat
limitinteger1-500, default 50

Returns: entries[] (same shape as /v1/log)

GET /v1/audit?limit=50
GET /v1/feedback

Bug reports and feature requests filed on the phone (developer agents only).

QueryTypeWhat
statusstringnew, seen, in_progress, fixed, wont_fix, duplicate, confirmed, reopened
kindstringbug or feature (bug, feature)
sincestringISO time: only reports updated after it
waitintegerWith since: hold up to this many seconds (max 55) for a new or changed report
limitinteger1-100, default 50

Returns: reports[id, number, kind, status, first_line, created_at, updated_at, no_autofix, image_count, filed_by]

Errors: forbidden, invalid_parameter, too_many_waits

GET /v1/feedback?status=new
GET /v1/feedback/{id}

One report with its text, images, attached log and history (developer agents only; marks a new report seen).

QueryTypeWhat
sizestringPreset: agent (1568 px, q85), thumb (512, q75), large (2560, q90), original (agent, thumb, large, original)
max_edge_pxintegerLong edge limit, 64-20000; overrides the preset
max_width_pxintegerWidth limit, 64-20000
qualityintegerJPEG quality 40-100

Returns: report: description, no_autofix, context, images[data_base64], log[], history[]

Errors: forbidden, not_found

GET /v1/feedback/7
POST /v1/feedback/{id}/status Idempotency-Key

Move a report: in_progress, fixed, wont_fix or duplicate (developer agents only; FBK-11a).

BodyTypeWhat
status *stringin_progress, fixed, wont_fix or duplicate
notestringShort note shown to the owner, e.g. "Fix in PR #412" (500 chars)

Returns: the report summary

Errors: forbidden, not_found, invalid_parameter

POST /v1/feedback/7/status {"status":"in_progress","note":"Looking at it"}
POST /v1/feedback Idempotency-Key

File a bug report or feature request yourself (any agent; images from developer agents only).

BodyTypeWhat
kind *stringbug or feature
description *stringWhat happened, up to 10,000 characters
no_autofixbooleantrue = leave it for a person
imagesarrayDeveloper agents only: up to 5 {"data_base64"} images

Returns: id, number, status

Errors: forbidden, invalid_parameter, rate_limited

POST /v1/feedback {"kind":"bug","description":"image/last returned 500 twice"}
POST /v1/interactions Idempotency-Key

Send the owner a notice, a question (buttons, text reply, choice, links), an HTML card or a live text panel.

BodyTypeWhat
kind *stringnotice (one-way), question, html (a card you draw; answer comes from Bridget.respond) or text (a live text panel you stream into with /v1/text/stream)
title *stringUp to 80 characters
textstringUp to 2,000 characters
imageobject{"gallery_id"} or {"data_base64"}, up to 2 MB
htmlstringkind=html: the card's HTML, up to 256 KB. Runs offline: no network, only data:image/* images; call Bridget.respond(json) once (up to 16 KB) to answer
controlsarrayQuestion: 1-6 of {type: button|text|choice|link, id, label, style?, placeholder?, options?, url?, package?}. Notice: links only
prioritystringnormal or urgent
speakbooleanRead it aloud on the phone
expires_in_secondsinteger60 to 604800, default 86400

Returns: interaction_id, status, expires_at

Errors: capability_disabled, notifications_required, invalid_parameter, payload_too_large, too_many_open, photo_not_found

POST /v1/interactions {"kind":"question","title":"Pay this invoice?","controls":[{"type":"button","id":"yes","label":"Pay","style":"primary"},{"type":"button","id":"no","label":"Not now"}]}
GET /v1/interactions

Your interactions, newest first.

QueryTypeWhat
statusstringpending, seen, answered, dismissed, expired or cancelled
limitinteger1-100, default 50

Returns: interactions[]

GET /v1/interactions?status=answered
GET /v1/interactions/{id}

One of your interactions; with wait, holds until the owner answers or closes it.

QueryTypeWhat
waitintegerHold up to this many seconds (max 55) for the answer

Returns: kind, status, answer{button, values}, answered_at, closed_at

Errors: not_found, too_many_waits

GET /v1/interactions/12?wait=55
DELETE /v1/interactions/{id}

Cancel one of your interactions.

Returns: the interaction

Errors: not_found

DELETE /v1/interactions/12
GET /v1/events

Your events, oldest first: answers, closes, expiries, switch changes.

QueryTypeWhat
sincestringnext_cursor from the last call; omit for the last 50
waitintegerWith since: hold up to 55 s for a new event
typesstringComma list, e.g. interaction.answered

Returns: events[id, type, at, data], next_cursor

Errors: invalid_parameter, too_many_waits

GET /v1/events?since=0&wait=55
POST /v1/text/stream

Add text to your live text panel (an interaction of kind text); it scrolls on the phone as it arrives.

BodyTypeWhat
interaction_id *stringThe panel's interaction_id
appendstringText to add, up to 16 KB per call (the panel keeps the last 200 KB)
donebooleantrue: the stream is finished; the panel stays until the owner closes it

Returns: interaction_id, length, status

Errors: not_found, invalid_parameter, conflict, rate_limited

POST /v1/text/stream {"interaction_id":"42","append":"Claude: running the tests now...\n"}
POST /v1/callback/test

Send a signed test event to the callback URL the owner set for you (EVT-05/06).

Returns: delivered, http_status, host

Errors: not_found, callback_failed

POST /v1/callback/test
POST /v1/mcp

Model Context Protocol (Streamable HTTP, JSON replies): every endpoint you can use is an MCP tool.

BodyTypeWhat
jsonrpc *string"2.0"
method *stringinitialize, tools/list, tools/call, ping
paramsobjectFor tools/call: {name, arguments}
idintegerRequest id

Returns: JSON-RPC result

Errors: invalid_parameter

POST /v1/mcp {"jsonrpc":"2.0","id":1,"method":"tools/list"}
GET /v1/location

Where the phone is now, with altitude, speed, heading and the compass.

QueryTypeWhat
freshbooleantrue (default): a new fix, up to 15 s; false: the last known one at once
accuracystringhigh (GPS, default) or balanced (high, balanced)
compassbooleanInclude the compass (default true)

Returns: latitude, longitude, altitude_m, accuracy_m, vertical_accuracy_m, speed_mps, bearing_deg, fix_time, age_s, precision, compass{azimuth_deg, direction, pitch_deg, roll_deg}

Errors: capability_disabled, permission_denied, notifications_required, capture_timeout, service_start_blocked

GET /v1/location
POST /v1/speaker/play Idempotency-Key

Play audio on the phone's speaker: send audio/* bytes as the body, or {"url"} (public https).

QueryTypeWhat
replacestringafter_current (default: replace what's queued from you), now, or queue (after_current, now, queue)
tour_idstringNarration for your running City tour
urgentbooleanJump the queue (answers to questions)
textstringCaption shown on the phone while it plays
BodyTypeWhat
urlstringhttps:// audio file (MP3, M4A, OGG, WAV, FLAC), up to 25 MB

Returns: play_id, position, status

Errors: capability_disabled, notifications_required, invalid_parameter, payload_too_large, rate_limited, not_found

POST /v1/speaker/play (Content-Type: audio/mpeg, body = the MP3)
POST /v1/speaker/say Idempotency-Key

Read text aloud on the phone (its own text-to-speech).

BodyTypeWhat
text *stringUp to 4,000 characters
languagestringe.g. en-GB, de-DE
ratenumber0.5-2, default 1
pitchnumber0.5-2, default 1
replacestringafter_current (default), now, or queue
tour_idstringNarration for your City tour
urgentbooleanJump the queue

Returns: play_id, position, status

Errors: capability_disabled, invalid_parameter, rate_limited, not_found

POST /v1/speaker/say {"text":"On your left is the old town hall, built in 1360.","tour_id":"t123"}
GET /v1/speaker

What's playing, and your queued sounds.

Returns: playing{play_id, agent, text} (yours only, else null), busy (someone else's sound is playing), paused, queued[], quiet

GET /v1/speaker
DELETE /v1/speaker

Stop your audio and clear your queue.

Returns: stopped

DELETE /v1/speaker
GET /v1/tour

Your running City tour, if the owner started one with you (D30).

Returns: tour{tour_id, kinds, interval_s, started_at, ticks, last_tick_at, distance_m, photos_sent, brief} or null

GET /v1/tour
GET /v1/tour/photo/{n}

A photo the owner took with Take photo on your tour (n from tour.photo), sized for you.

QueryTypeWhat
sizestringPreset: agent (1568 px, q85), thumb (512, q75), large (2560, q90), original (agent, thumb, large, original)
max_edge_pxintegerLong edge limit, 64-20000; overrides the preset
max_width_pxintegerWidth limit, 64-20000
qualityintegerJPEG quality 40-100
rawinteger1 = return the image bytes, details in X-Bridget-* headers

Returns: taken_at, width_px, height_px, format, size_bytes, data_base64

Errors: not_found, photo_not_found, payload_too_large

GET /v1/tour/photo/1?size=agent
DELETE /v1/tour

End your City tour.

QueryTypeWhat
tour_idstringOnly end this tour (it must be yours and still running)

Returns: ended

Errors: not_found

DELETE /v1/tour
POST /v1/me

Tell the owner which model you are and what runs you; shown on your agent card (AGT-16).

BodyTypeWhat
model *stringYour model, as exact as you know it, e.g. claude-opus-5-5 or gpt-6.1 (1-60 chars)
harnessstringThe program running you, e.g. Claude Code, Codex CLI, a Python script (1-40 chars)

Returns: agent, model, harness

Errors: invalid_parameter

POST /v1/me {"model":"claude-opus-5-5","harness":"Claude Code"}
POST /v1/screen/grant Idempotency-Key

Request owner-approved MediaProjection screen access.

BodyTypeWhat
duration_secondsinteger0=once, 3600=one hour, 57600=sixteen hours

Returns: Request owner-approved MediaProjection screen access

POST /v1/screen/grant
GET /v1/screen/grants

Your screen requests and active grant.

Returns: Your screen requests and active grant

GET /v1/screen/grants
POST /v1/screen/share/capture Idempotency-Key

Capture a JPEG using your active owner-approved grant.

Returns: Capture a JPEG using your active owner-approved grant

POST /v1/screen/share/capture
DELETE /v1/screen/grant

End your screen-sharing grant.

Returns: End your screen-sharing grant

DELETE /v1/screen/grant
GET /v1/phone/status

Battery, network, screen and sound status, with as_of.

Returns: Battery, network, screen and sound status, with as_of

GET /v1/phone/status
GET /v1/phone/context

Screen and lock context; likely=in_use or unknown, with the rule.

Returns: Screen and lock context; likely=in_use or unknown, with the rule

GET /v1/phone/context
POST /v1/phone/dnd Idempotency-Key

Set Do Not Disturb, with optional restoration.

BodyTypeWhat
mode *stringoff, priority, alarms or none (none mutes alarms)
duration_minutesintegerOptional timed restoration, 1–1440 minutes; null leaves the change in place

Returns: Set Do Not Disturb, with optional restoration

POST /v1/phone/dnd
POST /v1/phone/sound Idempotency-Key

Change ringer or volume.

BodyTypeWhat
ringer_modestringnormal, vibrate or silent
volumeobjectmedia/ring/alarm percentages, 0–100
duration_minutesintegerOptional timed restoration, 1–1440 minutes; null leaves the change in place

Returns: Change ringer or volume

POST /v1/phone/sound
POST /v1/phone/brightness Idempotency-Key

Set brightness or automatic brightness.

BodyTypeWhat
levelnumber0–1
autobooleantrue enables automatic brightness
duration_minutesintegerOptional timed restoration, 1–1440 minutes; null leaves the change in place

Returns: Set brightness or automatic brightness

POST /v1/phone/brightness
POST /v1/phone/undo Idempotency-Key

Restore pending timed phone changes, preserving subsequent manual changes.

Returns: Restore pending timed phone changes, preserving subsequent manual changes

POST /v1/phone/undo
GET /v1/flashlight

Whether the torch is on.

Returns: Whether the torch is on

GET /v1/flashlight
POST /v1/flashlight Idempotency-Key

Set torch with mandatory auto-off.

BodyTypeWhat
on *booleantrue or false
auto_off_secondsinteger1–600, default 60

Returns: Set torch with mandatory auto-off

POST /v1/flashlight
POST /v1/phone/ring Idempotency-Key

Ring and vibrate within Android sound restrictions.

BodyTypeWhat
duration_secondsinteger1–60, default 15

Returns: Ring and vibrate within Android sound restrictions

POST /v1/phone/ring
DELETE /v1/phone/ring

Stop ringing and vibration.

Returns: Stop ringing and vibration

DELETE /v1/phone/ring
GET /v1/sensors

Supported fresh sensor values or explicit unavailable status.

QueryTypeWhat
whichstringComma separated: light,pressure,proximity,steps,orientation,motion

Returns: Supported fresh sensor values or explicit unavailable status

GET /v1/sensors
GET /v1/notifications

Up to 100 active notification texts since service connected; RAM only.

Returns: Up to 100 active notification texts since service connected; RAM only

GET /v1/notifications
GET /v1/usage

App foreground time from Android usage buckets (maximum seven days).

QueryTypeWhat
sincestringISO-8601 UTC
untilstringISO-8601 UTC

Returns: App foreground time from Android usage buckets (maximum seven days)

GET /v1/usage
GET /v1/health/records

Read-only steps, sleep or heart-rate source records (maximum 100).

QueryTypeWhat
typestringsteps, sleep, heart_rate
sincestringISO-8601 UTC
untilstringISO-8601 UTC

Returns: Read-only steps, sleep or heart-rate source records (maximum 100)

GET /v1/health/records
POST /v1/clipboard Idempotency-Key

Queue a five-minute owner approval; never copies until owner taps Copy.

BodyTypeWhat
text *string1–10000 characters

Returns: Queue a five-minute owner approval; never copies until owner taps Copy

POST /v1/clipboard
GET /v1/clipboard/{id}

Your clipboard request: pending, copied, denied or expired.

Returns: Your clipboard request: pending, copied, denied or expired

GET /v1/clipboard/{id}
POST /v1/camera/video Idempotency-Key

Record an MP4, returned raw (HTTP: 40 MB maximum; MCP: 6 MB, may stop early).

BodyTypeWhat
camerastringrear or front
duration_secondsinteger1–30, default 10
audiobooleanfalse by default; true also requires microphone grant
resolutionstring720p or 1080p

Returns: Record an MP4, returned raw (HTTP: 40 MB maximum; MCP: 6 MB, may stop early)

POST /v1/camera/video
POST /v1/ocr Idempotency-Key

Recognize Latin-script text locally; no image upload.

BodyTypeWhat
gallery_idintegerAccessible gallery image (also requires gallery grant)
data_base64stringImage bytes instead of gallery_id

Returns: Recognize Latin-script text locally; no image upload

POST /v1/ocr
GET /v1/files

Your files transfers, retained 30 days on the phone.

Returns: Your files transfers, retained 30 days on the phone

GET /v1/files
GET /v1/files/{id}

Read your selected transfer bytes.

Returns: Read your selected transfer bytes

GET /v1/files/{id}
DELETE /v1/files/{id}

Delete your transfer.

Returns: Delete your transfer

DELETE /v1/files/{id}
POST /v1/files Idempotency-Key

Receive a file on the phone (25 MB maximum).

QueryTypeWhat
filenamestringFilename for raw-body uploads (or name= for HTTP compatibility)
BodyTypeWhat
name *stringFilename, no path
mimestringMIME type
data_base64stringFile bytes; or send raw body with ?name=...

Returns: Receive a file on the phone (25 MB maximum)

POST /v1/files
GET /v1/shares

Your shares transfers, retained 30 days on the phone.

Returns: Your shares transfers, retained 30 days on the phone

GET /v1/shares
GET /v1/shares/{id}

Read your selected transfer bytes.

Returns: Read your selected transfer bytes

GET /v1/shares/{id}
DELETE /v1/shares/{id}

Delete your transfer.

Returns: Delete your transfer

DELETE /v1/shares/{id}
GET /v1/downloads

Your downloads transfers, retained 30 days on the phone.

Returns: Your downloads transfers, retained 30 days on the phone

GET /v1/downloads
GET /v1/downloads/{id}

Read your selected transfer bytes.

Returns: Read your selected transfer bytes

GET /v1/downloads/{id}
DELETE /v1/downloads/{id}

Delete your transfer.

Returns: Delete your transfer

DELETE /v1/downloads/{id}

Errors

Errors are {"error","message","request_id"} with these codes.

HTTPCodeMeaningThe agent should
400bad_requestMalformed HTTP or JSONFix the request
401unauthorizedKey missing or wrong; reason = key_rotated or agent_removed when Bridgit knowsStop; tell the owner the key needs replacing
403forbidden_sourceCaller is not on the tailnetCheck Tailscale
403capability_disabledMaster switch offTell the owner which switch (setting field)
403permission_deniedAndroid permission not granted (permission field)Tell the owner; the Access screen fixes it
403access_neededAndroid special access off (setting field)Tell the owner; Bridgit also notifies him
403pairing_closedNo pairing window openAsk the owner to open one
403consent_expiredNo active screen-sharing grantAsk for a new owner-approved grant
403agent_not_allowedThis agent lacks a capability grantAsk the owner to change agent permissions
404not_foundUnknown endpoint or idFix the request
404photo_not_foundGallery item gone or outside accessRefresh the list
409sensor_busySensor in use or capture runningRetry once after a few seconds
409device_lockedNeeds the phone unlockedAsk the owner to unlock
413payload_too_largeOver 12 MB base64 (40 MB raw)Ask for a smaller size (photo_id given)
422invalid_parameterBad valueFix; never retry unchanged
422not_supportedAndroid doesn't allow this (for example Wi-Fi toggle)Don't retry
429rate_limitedOver a limit (retry_after_s)Wait
429too_many_openToo many open questions/noticesWait for answers or cancel some
403notifications_requiredBridgit's notifications are off, so captures are refused (PRD-05)Tell the owner to turn notifications on
403forbiddenNot allowed for this agent (reason, for example developer_only)Don't retry
409in_progressSame Idempotency-Key still runningWait, then retry with the same key
409conflictThe interaction isn't in a state for this (for example a text panel that's closed or finished)Read it with GET /v1/interactions/{id}; start a new one if needed
409idempotency_expiredSame Idempotency-Key already done, but its media result is no longer kept (SEC-13)Don't repeat; use a new key only if you really want a new capture
429quota_exceededDaily data, file storage or relay job quota used up (limit)Remove old transfers or wait for retention
429too_many_waitsToo many open wait requests (SEC-08a)Close some waits
502callback_failedYour callback URL didn't accept the test event (http_status or reason field)Check the receiver; the owner sees the host in Activity
500internal_errorBridgit bugReport via POST /v1/feedback
503service_start_blockedAndroid hasn't given the service this sensorAsk the owner to open Bridgit once
504capture_timeoutSensor didn't answer in timeRetry once

API revisions

Revision 8 (app 1.6.0, 2026-10-29)

Revision 7 (app 1.5.2, 2026-10-27)

Revision 6 (app 1.5.2, 2026-10-27)

Revision 5 (app 1.5.0, 2026-10-27)

Revision 4 (app 1.5.0, 2026-10-27)

Revision 3 (app 1.4.4, 2026-10-27)

Revision 2 (app 1.4.0, 2026-10-27)

Revision 1 (app 1.3.0, 2026-10-27)