Bridgit API
Bridgit: Agentic Android Device Bridge, 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:
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.
- Back or front camera
- Zoom: 0.5× (ultra-wide) up to the phone's maximum (telephoto)
- Flash on or off
- Size: sized for AI (1568 px), thumbnail (512 px), large (2560 px) or original
- Or an exact width or long edge, and JPEG quality
- Full resolution, up to the 50 MP sensor
- As JSON with the picture inside, or as plain JPEG bytes
- Never saved to your gallery
From your laptop: "Is the stove off?" Your agent takes a photo of the kitchen and tells you.
POST /v1/camera/snapshot Idempotency-Key detailsTake a photo now.
POST /v1/camera/snapshot {"camera":"rear","zoom":2}Record a short clip
An agent can record 1 to 120 seconds of audio and get it back as a file.
- Length: 1 to 120 whole seconds
- Comes back as an M4A (AAC) audio file, 44.1 kHz mono
- Not kept on the phone
"Listen to the next 30 seconds of the meeting and give me the action items."
POST /v1/mic/record Idempotency-Key detailsRecord an audio clip.
POST /v1/mic/record {"duration_seconds":5}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.
- Which: any image, the newest screenshot, or the newest camera photo
- Wait up to 55 seconds for the next one you take
- Size: sized for AI (default), thumbnail, large or original
- As JSON or as plain JPEG bytes, with when it was taken and the album
You screenshot an error on your phone; your agent already has it and explains the fix.
GET /v1/image/last detailsThe newest image of a type; with since and wait, waits for the next one.
GET /v1/image/last?type=screenshot
Find photos in your gallery
Agents can list recent images and fetch one at the size they need. Bridgit never edits or deletes anything.
- List the newest 1 to 100 images (no pictures, just details)
- Fetch one image at any of the sizes
- Works with full access or only the photos you picked
"Find the receipt photo from this morning and add it to my expenses."
GET /v1/gallery/photo/{id} detailsOne gallery image, sized for you.
GET /v1/gallery/photo/87567?size=agent
Questions and notices to you
Agents send you a notice, or a question with buttons, choices or a text reply, and get your answer within a second of your tap. They can also read it aloud.
- A notice (one-way) or a question
- Buttons (up to 6), a text reply, a choice list, or a link
- An image with the message
- Normal or urgent; read aloud if you allow it
- Expires after 1 minute to 7 days
- The agent waits for your answer or gets a callback
"Pay this invoice? $11.99" [Pay] [Not now]. You tap Pay on the notification; the agent pays.
POST /v1/interactions Idempotency-Key detailsSend Rahul 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} detailsOne of your interactions; with wait, holds until Rahul answers or closes it.
GET /v1/interactions/12?wait=55
GET /v1/events detailsYour events, oldest first: answers, closes, expiries, switch changes.
GET /v1/events?since=0&wait=55
Rich HTML cards
Instead of plain buttons, an agent can send a small HTML page (charts, forms, choices) that runs safely on the phone with no internet access.
- A small HTML page with its own layout, charts and forms
- Runs on the phone with no internet access
- Sends one answer back to the agent (up to 16 KB of data)
- Images inside the card only (data: images), up to 256 KB of HTML
- Bridgit's own header shows which agent sent it; you can always dismiss it
Your travel agent shows three flights as cards with prices and a map; you tap one to book.
POST /v1/interactions Idempotency-Key detailsSend Rahul 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} detailsOne of your interactions; with wait, holds until Rahul answers or closes it.
GET /v1/interactions/12?wait=55
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.
- Lower half of the screen, scrolls as text arrives
- Pause scrolling to read, then resume
- The agent marks it finished; you close it whenever you like
- Keeps the last 200 KB of text
Claude Code is fixing a bug on your laptop; you watch what it's doing on the phone while you make coffee.
POST /v1/interactions Idempotency-Key detailsSend Rahul 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 detailsAdd 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"}Send a screenshot
An agent sees what's on your screen right now, with no prompt each time; a notification shows every capture.
- A private copy: nothing is saved and there's no flash
- Turn on Bridgit's screenshot service once (Access), then Screenshots in Features
- Same size choices as photos
- At most one every 2 seconds and 60 an hour per agent
"What does this error on my phone mean?" The agent takes a screenshot and reads it.
POST /v1/screen/capture Idempotency-Key detailsWhat's on Rahul's screen right now (D17, no prompt once he's turned it on).
POST /v1/screen/capture?size=agent
Open a link or app
An agent can suggest a link or app; it opens when you tap it.
- Web links, maps, phone numbers (dialler only), email
- Or open an app by name
- Only when you tap it
"Here's the boarding pass" [Open in Wallet].
POST /v1/interactions Idempotency-Key detailsSend Rahul 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"}]}Phone status and context
Battery, network, ringer, Do Not Disturb and screen/lock status. An unlocked interactive screen is reported as in use.
- Battery level and charging
- Screen on/off and lock state
- Ringer, Do Not Disturb and media volume
- Wi-Fi/mobile transport and metered status
- Context: in use when screen is interactive and unlocked; otherwise unknown
Before calling you, an agent checks whether your phone is in use or on silent.
GET /v1/phone/status detailsBattery, network, screen and sound status, with as_of.
GET /v1/phone/status
GET /v1/phone/context detailsScreen and lock context; likely=in_use or unknown, with the rule.
GET /v1/phone/context
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.
- Latitude and longitude (x, y)
- Altitude (z) in metres
- Accuracy in metres, speed and heading
- A fresh fix (up to 15 s) or the last known one at once
- High accuracy or battery-friendly
- Street address, if you turn on address lookup
"How long until I'm home?" The agent checks where you are and the traffic.
GET /v1/location detailsWhere the phone is now, with altitude, speed, heading and the compass.
GET /v1/location
Flash the light
Turn the torch on for up to ten minutes, with automatic off and an owner Stop button.
- On for 1 second to 10 minutes; always turns itself off
- Turn off now
- Ask whether it's on
Your door-camera agent flashes the light so you know someone is at the door.
Phone controls
Do Not Disturb, ringer, volume and brightness, put back as they were afterwards.
- DND: off, priority, alarms or none; none can mute alarms
- Ringer: normal, vibrate or silent; media/ring/alarm volumes
- Brightness level or automatic brightness
- Optional 1–1440 minute restoration; owner Undo
- Later manual changes are preserved
Bedtime routine: your agent turns on Do Not Disturb until 7 am.
POST /v1/phone/dnd Idempotency-Key detailsSet Do Not Disturb, with optional restoration.
POST /v1/phone/dnd
POST /v1/phone/brightness Idempotency-Key detailsSet brightness or automatic brightness.
POST /v1/phone/brightness
POST /v1/phone/undo Idempotency-Key detailsRestore pending timed phone changes, preserving subsequent manual changes.
POST /v1/phone/undo
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.
- History, architecture, environment, food, art, or anything interesting
- Updates every 30 s, 1, 2 or 5 minutes
- Location, heading (compass) and new photos each time
- Ask out loud or type a question
- Pause, skip, end; ends by itself after 4 hours
Pick "Architecture" and walk; when you photograph a church, your agent tells you who built it and why it looks that way.
GET /v1/events detailsYour events, oldest first: answers, closes, expiries, switch changes.
GET /v1/events?since=0&wait=55
POST /v1/speaker/say Idempotency-Key detailsRead 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 detailsPlay 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} detailsOne gallery image, sized for you.
GET /v1/gallery/photo/87567?size=agent
Find my phone
Ring and vibrate for up to a minute, respecting your sound and Do Not Disturb settings.
- Ring and vibrate for 1–60 seconds
- Respects Android sound and Do Not Disturb settings
- Stop from Device tools or the ongoing notification
Phone lost in the sofa: ask any agent to ring it.
POST /v1/phone/ring Idempotency-Key detailsRing and vibrate within Android sound restrictions.
POST /v1/phone/ring
Sensors
Light, pressure, steps, motion and orientation, one reading each.
- Light, pressure and proximity where available
- Steps since reboot (Physical activity grant)
- Fresh rotation-vector orientation and accelerometer values
- Unavailable or stale sensors are reported explicitly
An agent notices it's dark and you're still, and holds non-urgent messages.
Videos and downloads
Find recent videos, take a frame from one, and pick a file from Downloads for an agent.
- List accessible videos
- Retrieve a video up to 40 MB, or a still frame
- Choose individual Downloads files on the phone for one agent
"Get the frame at 0:12 from the video I just took."
Files to your phone
Agents send PDFs, images and other files; they land in the Inbox and can be saved to Downloads.
- 25 MB per file; 100 files / 100 MB total
- Private storage, retained 30 days
- Owner opens, exports to a selected location, or deletes
- No automatic execution or automatic Downloads save
Your accounting agent sends this month's invoice PDF to your phone.
Short video clips
1 to 30 seconds of 720p or 1080p MP4. Audio is off by default and needs a microphone grant.
- 1 to 30 seconds
- Back or front camera
- With or without sound
- 720p or 1080p
"Record the dishwasher noise so I can describe it to the repair shop."
POST /v1/camera/video Idempotency-Key detailsRecord an MP4, returned raw (HTTP: 40 MB maximum; MCP: 6 MB, may stop early).
POST /v1/camera/video
Read text on the phone
Bundled Latin-script text recognition runs on the phone; only the result leaves it.
- Bundled Latin-script recognition
- From an accessible gallery image or supplied image bytes
- Returns recognized text; no cloud recognition
Read the serial number from a photo without uploading the picture.
POST /v1/ocr Idempotency-Key detailsRecognize Latin-script text locally; no image upload.
POST /v1/ocr
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.
- Transcript with the audio, or the transcript only
Dictate a note for 20 seconds; the agent gets the words.
POST /v1/mic/record Idempotency-Key detailsRecord an audio clip.
POST /v1/mic/record {"duration_seconds":5}Screen sharing as a fallback
If you'd rather not turn on Accessibility, approve screen access once, for 1 hour or for 16 hours.
- Allow once, for 1 hour or for 16 hours, or deny
- Stop any time from the status bar
Help your agent debug an app for the next hour.
POST /v1/screen/grant Idempotency-Key detailsRequest owner-approved MediaProjection screen access.
POST /v1/screen/grant
POST /v1/screen/share/capture Idempotency-Key detailsCapture a JPEG using your active owner-approved grant.
POST /v1/screen/share/capture
App usage
Read foreground-time summaries after granting Android Usage access. Android buckets can extend past the requested interval.
- Foreground-time summaries for up to seven days
- Requires Android Usage access
- Android buckets may extend outside the requested interval
Weekly review: "You spent 6 hours in email this week."
GET /v1/usage detailsApp foreground time from Android usage buckets (maximum seven days).
GET /v1/usage
Health Connect
Read permitted steps, sleep and heart-rate source records. No health writes; maximum 100 records per query.
- Read permitted steps, sleep sessions or heart-rate samples
- No writes, background reads, workouts or retained health records
- At most 100 source records and seven days per request
- Source records may overlap; no deduplicated total claim
Your coach agent adjusts tomorrow's plan to last night's sleep.
GET /v1/health/records detailsRead-only steps, sleep or heart-rate source records (maximum 100).
GET /v1/health/records
Read notifications
Read up to 100 active notification texts received since the listener connected. Explicit notification access required; memory only.
- Explicit feature switch and Android notification access
- At most 100 active notifications since listener connection
- RAM only; cleared when disabled, paused or disconnected
- No notification-history archive or long-poll in this build
"Summarise everything that pinged me during the meeting."
GET /v1/notifications detailsUp to 100 active notification texts since service connected; RAM only.
GET /v1/notifications
Copy to clipboard
An agent puts text on your clipboard after you approve it.
- Up to 10000 characters of text
- Every copy requires your foreground Copy tap
- Five-minute approval expiry
- Text is marked sensitive to suppress clipboard previews
Your agent copies the 2-factor backup code so you can paste it.
POST /v1/clipboard Idempotency-Key detailsQueue a five-minute owner approval; never copies until owner taps Copy.
POST /v1/clipboard
GET /v1/clipboard/{id} detailsYour clipboard request: pending, copied, denied or expired.
GET /v1/clipboard/{id}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.
- An MP3, M4A, OGG, WAV or FLAC file (up to 25 MB), or a public https link
- Or text read aloud with the phone's own voice: language, speed and pitch
- Replace what's waiting, stop the current one, or queue
- Never louder than your volume ceiling (default 70 %)
- Silent when your phone is on silent, vibrate, Do Not Disturb or a call
- Stop clears everything
Your reminder agent plays "Time to leave for the airport" in its own voice.
POST /v1/speaker/play Idempotency-Key detailsPlay 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 detailsRead 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"}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.
Say "Bridgit, note" and the next sentence goes to your notes agent.
Not built yet. Spec PRD-09 in docs/bridgit-spec-v2.md describes the planned calls.
Messages, contacts, calendar, calls
Read and, with your approval each time, send.
"Text Sam I'm 10 minutes late" — you approve on the phone.
Not built yet. Spec 8.22, Q1 in docs/bridgit-spec-v2.md describes the planned calls.
Location history and places
Optional history kept on the phone, and "tell me when I get home".
Grok reminds you to water the plants when you arrive home.
Not built yet. Spec CAP-20a, Q14 in docs/bridgit-spec-v2.md describes the planned calls.
How Bridgit works
Add an agent in a minute
Bridgit makes a setup prompt with the agent's own key, the address and the rules. Paste it into any AI agent and it can use the phone straight away.
You add Claude: name it, copy the prompt, paste it into Claude. The screen turns to "Claude connected" as soon as it calls.
POST /v1/pair no key needed detailsFetch 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 detailsThe bridget command-line helper (Python, no secrets inside).
GET /v1/tools/bridget
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.
You pasted Grok's prompt into the wrong chat. Rotate Grok's key; the leaked one is dead in a second.
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.
- Filter by agent, type, endpoint, result, level, time or text
- Follow it live
- Stats per agent and endpoint
- Export as JSONL or CSV
- "All entries" or "only their own" for agents
Codex checks yesterday's log to see why a photo failed; you scroll Activity to see who did what.
GET /v1/log detailsRead the log; with order=asc&since=<id>&wait=55 it follows new entries.
GET /v1/log?agent=me&limit=20
GET /v1/log/stats detailsCounts, 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 detailsEvery matching entry as JSONL or CSV.
GET /v1/log/export?format=csv&agent=me
Agent notes
Agents can write short notes into the log.
Your fridge-check agent writes "milk low" so you see it in Activity.
POST /v1/log Idempotency-Key detailsWrite a note to the agent channel.
POST /v1/log {"message":"checked fridge photo, milk low"}The API explains itself
Agents read a live guide and an OpenAPI file that list what's switched on, every call and every error.
A brand-new agent reads the guide and learns everything without a manual.
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.
Bridgit gains camera zoom; the next time Grok calls, it reads what's new and starts using zoom.
GET /v1/changes detailsWhat's new in the API since a revision you know (API-14).
GET /v1/changes?since=2
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.
- Last screen, up to 5 screenshots and the recent log attached
- "Don't auto-fix" keeps it for a person
- Statuses: new, seen, in progress, fixed, won't fix, duplicate
- You confirm a fix or say it's still broken
The app misbehaves; you report it in 10 seconds. Claude picks it up, fixes it and marks it fixed.
GET /v1/feedback detailsBug reports and feature requests filed on the phone (developer agents only).
GET /v1/feedback?status=new
GET /v1/feedback/{id} detailsOne 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 detailsMove 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 detailsFile 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"}Check for updates
Bridgit finds a new version, checks it really is Bridgit, and lets Android install it after you confirm.
A fix ships; your phone offers the update the next time you open Bridgit.
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.
Going into a meeting: turn off Camera and Microphone from Home in two taps.
Only over Tailscale
Bridgit answers only on your private Tailscale network, never the open internet.
Your agents on your Mac and your server can reach the phone; nobody else can.
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.
- Same key, same switches, same log as the normal API
- Every endpoint the agent may use becomes a tool, with its options
- Photos and screenshots come back as images
Add Bridgit to Claude Code once; from then on "take a photo of my desk" just works.
POST /v1/mcp detailsModel 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"}Inbox
One place for every question, notice, file and share between you and your agents.
See what Grok asked you this morning and what you answered.
Events and callbacks
Agents get told the moment something happens: a question answered, a new screenshot, a switch changed.
Your agent waits for your answer without asking again and again.
GET /v1/events detailsYour events, oldest first: answers, closes, expiries, switch changes.
GET /v1/events?since=0&wait=55
POST /v1/callback/test detailsSend a signed test event to the callback URL Rahul set for you (EVT-05/06).
POST /v1/callback/test
Quick Settings tile
Pause or resume Bridgit from the notification shade.
Pull down, tap Bridgit, and agents can't reach the phone until you tap again.
Per-agent permissions
Choose what each agent may use, for example photos for Claude but not for Grok.
Let your shopping agent see the gallery but never the camera.
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.
Muse, which runs on Meta's servers, takes a photo for you.
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.
- Report your model once:
POST /v1/me {"model","harness"}. - Offer the applet with a question card:
POST /v1/interactionswith buttons, e.g. Start / Not now. Wait for the answer withGET /v1/interactions/{id}?wait=55. - 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. - 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. CheckGET /v1/capabilitiesfirst and ask the owner to switch on what is off. - 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. - 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.
- Write the spec first: a section next to 8.25 City tour in
docs/bridgit-spec-v2.mdwith numbered rules like TOUR-01..07 (what it needs switched on, what is sent to whom, limits). - Session engine: a manager like
TourManagerintour/Tour.kt. One session at a time, one agent, sends<applet>.started(with abriefstring telling the agent what to do),<applet>.tick, owner actions, and<applet>.endedthroughapp.interactions.event(agentId, type, data). Create it inBridgeApp. - Agent API: a
Capabilitymodule likeTourModule(register it incapability/Capability.kt), with anEndpointSpecfor every call inapi/Endpoints.ktand inEndpoints.all. Only the session's own agent may read it. - 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 tores/navigation/nav_main.xml. - Card: add it to
res/layout/fragment_applets.xmlandAppletsFragment, with a running chip. - Tell agents: add an
ApiChangesrevision, a section in the live guide (api/SelfDescription.kt), and a "What can Bridgit do?" card inui/more/WhatCanData.kt. - Bump
versionName/versionCodeinapp/build.gradle.kts, 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/healthIs 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/capabilitiesWhat's switched on and ready, and why not.
Returns: per capability: enabled, ready, blocked_reason, details; callback {set, host}
GET /v1/capabilities
GET /v1/guideThis guide, generated live (Markdown).
Returns: text/markdown
GET /v1/guide
GET /v1/openapi.jsonOpenAPI 3.1 description of every endpoint.
Returns: application/json
GET /v1/openapi.json
GET /v1/changesWhat's new in the API since a revision you know (API-14).
| Query | Type | What |
|---|---|---|
since | integer | The 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 neededThe bridget command-line helper (Python, no secrets inside).
Returns: text/x-python
GET /v1/tools/bridget
POST /v1/pair no key neededFetch your key with a 6-digit code shown on the phone (alternative to the setup prompt).
| Body | Type | What |
|---|---|---|
code * | string | 6-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-KeyTake a photo now.
| Body | Type | What |
|---|---|---|
camera | string | rear (default) or front |
flash | boolean | Fire the flash (default false) |
zoom | number | Zoom ratio, e.g. 0.5 (ultra-wide), 1, 2, 5 (telephoto); the range is in /v1/capabilities after the first photo |
max_width_px | integer | Width limit, 64-20000, or null for full size (default 2048 unless size is given) |
size | string | Preset: agent (1568 px, q85), thumb (512, q75), large (2560, q90), original |
max_edge_px | integer | Long edge limit, 64-20000; overrides the preset |
quality | integer | JPEG quality 40-100 |
raw | integer | 1 = 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-KeyRecord an audio clip.
| Body | Type | What |
|---|---|---|
transcribe | boolean | Use only Android on-device recognition; no cloud fallback |
return_audio | boolean | true by default; false requires transcribe=true |
language | string | Optional offline language, e.g. en-US |
duration_seconds * | integer | Whole 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/gallery/recentNewest gallery images (metadata only).
| Query | Type | What |
|---|---|---|
type | string | any, photo or screenshot |
album | string | Exact album name |
since | string | ISO-8601 UTC added-at lower bound |
until | string | ISO-8601 UTC upper bound |
limit | integer | 1-100, default 20 |
Returns: access_mode, photos[id, taken_at, width_px, height_px, size_bytes, mime, album]
Errors: capability_disabled, permission_denied
GET /v1/gallery/recent?limit=10
GET /v1/gallery/photo/{id}One gallery image, sized for you.
| Query | Type | What |
|---|---|---|
size | string | Preset: agent (1568 px, q85), thumb (512, q75), large (2560, q90), original (agent, thumb, large, original) |
max_edge_px | integer | Long edge limit, 64-20000; overrides the preset |
max_width_px | integer | Width limit, 64-20000 |
quality | integer | JPEG quality 40-100 |
raw | integer | 1 = return the image bytes, details in X-Bridget-* headers |
Returns: taken_at, width_px, height_px, format, size_bytes, data_base64
Errors: capability_disabled, permission_denied, photo_not_found, payload_too_large
GET /v1/gallery/photo/87567?size=agent
GET /v1/image/lastThe newest image of a type; with since and wait, waits for the next one.
| Query | Type | What |
|---|---|---|
type | string | any (default), screenshot or photo (any, screenshot, photo) |
since | string | ISO time or gallery id: only an image added after it |
wait | integer | With since: hold up to this many seconds (max 55) for a new image |
size | string | Preset: agent (1568 px, q85), thumb (512, q75), large (2560, q90), original (agent, thumb, large, original) |
max_edge_px | integer | Long edge limit, 64-20000; overrides the preset |
max_width_px | integer | Width limit, 64-20000 |
quality | integer | JPEG quality 40-100 |
raw | integer | 1 = 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-KeyWhat's on Rahul's screen right now (D17, no prompt once he's turned it on).
| Query | Type | What |
|---|---|---|
size | string | Preset: agent (1568 px, q85), thumb (512, q75), large (2560, q90), original (agent, thumb, large, original) |
max_edge_px | integer | Long edge limit, 64-20000; overrides the preset |
max_width_px | integer | Width limit, 64-20000 |
quality | integer | JPEG quality 40-100 |
raw | integer | 1 = return the image bytes, details in X-Bridget-* headers |
| Body | Type | What |
|---|---|---|
mode | string | private (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/logRead the log; with order=asc&since=<id>&wait=55 it follows new entries.
| Query | Type | What |
|---|---|---|
channel | string | Comma list of audit, diagnostic, agent |
agent | string | Agent name or id; me for you; bridget for Bridgit's own entries |
kind | string | request, setting, agent, pairing, service, note, … |
endpoint | string | Endpoint prefix, e.g. /v1/camera |
result | string | ok, error, or an error code |
level | string | Minimum level: debug, info, warn, error |
since | string | Log id or ISO time (exclusive id) |
until | string | Log id or ISO time |
q | string | Text in message or endpoint |
limit | integer | 1-500, default 100 |
order | string | desc (default) or asc (desc, asc) |
cursor | string | next_cursor from the previous page |
wait | integer | Tail 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/statsCounts, errors and p50/p95 time per agent and endpoint.
| Query | Type | What |
|---|---|---|
since | string | Log 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/exportEvery matching entry as JSONL or CSV.
| Query | Type | What |
|---|---|---|
format | string | jsonl (default) or csv (jsonl, csv) |
channel | string | Comma list of audit, diagnostic, agent |
agent | string | Agent name or id; me for you; bridget for Bridgit's own entries |
kind | string | request, setting, agent, pairing, service, note, … |
endpoint | string | Endpoint prefix, e.g. /v1/camera |
result | string | ok, error, or an error code |
level | string | Minimum level: debug, info, warn, error |
since | string | Log id or ISO time (exclusive id) |
until | string | Log id or ISO time |
q | string | Text in message or endpoint |
Returns: application/x-ndjson or text/csv
GET /v1/log/export?format=csv&agent=me
POST /v1/log Idempotency-KeyWrite a note to the agent channel.
| Body | Type | What |
|---|---|---|
message * | string | Up to 1 KB |
level | string | debug, info (default), warn, error |
data | object | Up to 4 KB of JSON |
Returns: id
Errors: invalid_parameter, rate_limited
POST /v1/log {"message":"checked fridge photo, milk low"}GET /v1/auditDeprecated alias of /v1/log?channel=audit (removed in v3).
| Query | Type | What |
|---|---|---|
limit | integer | 1-500, default 50 |
Returns: entries[] (same shape as /v1/log)
GET /v1/audit?limit=50
GET /v1/feedbackBug reports and feature requests filed on the phone (developer agents only).
| Query | Type | What |
|---|---|---|
status | string | new, seen, in_progress, fixed, wont_fix, duplicate, confirmed, reopened |
kind | string | bug or feature (bug, feature) |
since | string | ISO time: only reports updated after it |
wait | integer | With since: hold up to this many seconds (max 55) for a new or changed report |
limit | integer | 1-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).
| Query | Type | What |
|---|---|---|
size | string | Preset: agent (1568 px, q85), thumb (512, q75), large (2560, q90), original (agent, thumb, large, original) |
max_edge_px | integer | Long edge limit, 64-20000; overrides the preset |
max_width_px | integer | Width limit, 64-20000 |
quality | integer | JPEG 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-KeyMove a report: in_progress, fixed, wont_fix or duplicate (developer agents only; FBK-11a).
| Body | Type | What |
|---|---|---|
status * | string | in_progress, fixed, wont_fix or duplicate |
note | string | Short note shown to Rahul, 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-KeyFile a bug report or feature request yourself (any agent; images from developer agents only).
| Body | Type | What |
|---|---|---|
kind * | string | bug or feature |
description * | string | What happened, up to 10,000 characters |
no_autofix | boolean | true = leave it for a person |
images | array | Developer 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-KeySend Rahul a notice, a question (buttons, text reply, choice, links), an HTML card or a live text panel.
| Body | Type | What |
|---|---|---|
kind * | string | notice (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 * | string | Up to 80 characters |
text | string | Up to 2,000 characters |
image | object | {"gallery_id"} or {"data_base64"}, up to 2 MB |
html | string | kind=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 |
controls | array | Question: 1-6 of {type: button|text|choice|link, id, label, style?, placeholder?, options?, url?, package?}. Notice: links only |
priority | string | normal or urgent |
speak | boolean | Read it aloud on the phone |
expires_in_seconds | integer | 60 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/interactionsYour interactions, newest first.
| Query | Type | What |
|---|---|---|
status | string | pending, seen, answered, dismissed, expired or cancelled |
limit | integer | 1-100, default 50 |
Returns: interactions[]
GET /v1/interactions?status=answered
GET /v1/interactions/{id}One of your interactions; with wait, holds until Rahul answers or closes it.
| Query | Type | What |
|---|---|---|
wait | integer | Hold 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/eventsYour events, oldest first: answers, closes, expiries, switch changes.
| Query | Type | What |
|---|---|---|
since | string | next_cursor from the last call; omit for the last 50 |
wait | integer | With since: hold up to 55 s for a new event |
types | string | Comma 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/streamAdd text to your live text panel (an interaction of kind text); it scrolls on the phone as it arrives.
| Body | Type | What |
|---|---|---|
interaction_id * | string | The panel's interaction_id |
append | string | Text to add, up to 16 KB per call (the panel keeps the last 200 KB) |
done | boolean | true: the stream is finished; the panel stays until Rahul 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/testSend a signed test event to the callback URL Rahul set for you (EVT-05/06).
Returns: delivered, http_status, host
Errors: not_found, callback_failed
POST /v1/callback/test
POST /v1/mcpModel Context Protocol (Streamable HTTP, JSON replies): every endpoint you can use is an MCP tool.
| Body | Type | What |
|---|---|---|
jsonrpc * | string | "2.0" |
method * | string | initialize, tools/list, tools/call, ping |
params | object | For tools/call: {name, arguments} |
id | integer | Request id |
Returns: JSON-RPC result
Errors: invalid_parameter
POST /v1/mcp {"jsonrpc":"2.0","id":1,"method":"tools/list"}GET /v1/locationWhere the phone is now, with altitude, speed, heading and the compass.
| Query | Type | What |
|---|---|---|
fresh | boolean | true (default): a new fix, up to 15 s; false: the last known one at once |
accuracy | string | high (GPS, default) or balanced (high, balanced) |
compass | boolean | Include 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-KeyPlay audio on the phone's speaker: send audio/* bytes as the body, or {"url"} (public https).
| Query | Type | What |
|---|---|---|
replace | string | after_current (default: replace what's queued from you), now, or queue (after_current, now, queue) |
tour_id | string | Narration for your running City tour |
urgent | boolean | Jump the queue (answers to questions) |
text | string | Caption shown on the phone while it plays |
| Body | Type | What |
|---|---|---|
url | string | https:// 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-KeyRead text aloud on the phone (its own text-to-speech).
| Body | Type | What |
|---|---|---|
text * | string | Up to 4,000 characters |
language | string | e.g. en-GB, de-DE |
rate | number | 0.5-2, default 1 |
pitch | number | 0.5-2, default 1 |
replace | string | after_current (default), now, or queue |
tour_id | string | Narration for your City tour |
urgent | boolean | Jump 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/speakerWhat'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/speakerStop your audio and clear your queue.
Returns: stopped
DELETE /v1/speaker
GET /v1/tourYour running City tour, if Rahul 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 Rahul took with Take photo on your tour (n from tour.photo), sized for you.
| Query | Type | What |
|---|---|---|
size | string | Preset: agent (1568 px, q85), thumb (512, q75), large (2560, q90), original (agent, thumb, large, original) |
max_edge_px | integer | Long edge limit, 64-20000; overrides the preset |
max_width_px | integer | Width limit, 64-20000 |
quality | integer | JPEG quality 40-100 |
raw | integer | 1 = 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/tourEnd your City tour.
| Query | Type | What |
|---|---|---|
tour_id | string | Only end this tour (it must be yours and still running) |
Returns: ended
Errors: not_found
DELETE /v1/tour
POST /v1/meTell Rahul which model you are and what runs you; shown on your agent card (AGT-16).
| Body | Type | What |
|---|---|---|
model * | string | Your model, as exact as you know it, e.g. claude-opus-5-5 or gpt-6.1 (1-60 chars) |
harness | string | The 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-KeyRequest owner-approved MediaProjection screen access.
| Body | Type | What |
|---|---|---|
duration_seconds | integer | 0=once, 3600=one hour, 57600=sixteen hours |
Returns: Request owner-approved MediaProjection screen access
POST /v1/screen/grant
GET /v1/screen/grantsYour screen requests and active grant.
Returns: Your screen requests and active grant
GET /v1/screen/grants
DELETE /v1/screen/grantEnd your screen-sharing grant.
Returns: End your screen-sharing grant
DELETE /v1/screen/grant
GET /v1/phone/statusBattery, 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/contextScreen 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-KeySet Do Not Disturb, with optional restoration.
| Body | Type | What |
|---|---|---|
mode * | string | off, priority, alarms or none (none mutes alarms) |
duration_minutes | integer | Optional 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-KeyChange ringer or volume.
| Body | Type | What |
|---|---|---|
ringer_mode | string | normal, vibrate or silent |
volume | object | media/ring/alarm percentages, 0–100 |
duration_minutes | integer | Optional 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-KeySet brightness or automatic brightness.
| Body | Type | What |
|---|---|---|
level | number | 0–1 |
auto | boolean | true enables automatic brightness |
duration_minutes | integer | Optional 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-KeyRestore pending timed phone changes, preserving subsequent manual changes.
Returns: Restore pending timed phone changes, preserving subsequent manual changes
POST /v1/phone/undo
GET /v1/flashlightWhether the torch is on.
Returns: Whether the torch is on
GET /v1/flashlight
POST /v1/flashlight Idempotency-KeySet torch with mandatory auto-off.
| Body | Type | What |
|---|---|---|
on * | boolean | true or false |
auto_off_seconds | integer | 1–600, default 60 |
Returns: Set torch with mandatory auto-off
POST /v1/flashlight
POST /v1/phone/ring Idempotency-KeyRing and vibrate within Android sound restrictions.
| Body | Type | What |
|---|---|---|
duration_seconds | integer | 1–60, default 15 |
Returns: Ring and vibrate within Android sound restrictions
POST /v1/phone/ring
DELETE /v1/phone/ringStop ringing and vibration.
Returns: Stop ringing and vibration
DELETE /v1/phone/ring
GET /v1/sensorsSupported fresh sensor values or explicit unavailable status.
| Query | Type | What |
|---|---|---|
which | string | Comma separated: light,pressure,proximity,steps,orientation,motion |
Returns: Supported fresh sensor values or explicit unavailable status
GET /v1/sensors
GET /v1/notificationsUp 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/usageApp foreground time from Android usage buckets (maximum seven days).
| Query | Type | What |
|---|---|---|
since | string | ISO-8601 UTC |
until | string | ISO-8601 UTC |
Returns: App foreground time from Android usage buckets (maximum seven days)
GET /v1/usage
GET /v1/health/recordsRead-only steps, sleep or heart-rate source records (maximum 100).
| Query | Type | What |
|---|---|---|
type | string | steps, sleep, heart_rate |
since | string | ISO-8601 UTC |
until | string | ISO-8601 UTC |
Returns: Read-only steps, sleep or heart-rate source records (maximum 100)
GET /v1/health/records
POST /v1/clipboard Idempotency-KeyQueue a five-minute owner approval; never copies until owner taps Copy.
| Body | Type | What |
|---|---|---|
text * | string | 1–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-KeyRecord an MP4, returned raw (HTTP: 40 MB maximum; MCP: 6 MB, may stop early).
| Body | Type | What |
|---|---|---|
camera | string | rear or front |
duration_seconds | integer | 1–30, default 10 |
audio | boolean | false by default; true also requires microphone grant |
resolution | string | 720p or 1080p |
Returns: Record an MP4, returned raw (HTTP: 40 MB maximum; MCP: 6 MB, may stop early)
POST /v1/camera/video
GET /v1/gallery/videos/recentAccessible videos and metadata.
| Query | Type | What |
|---|---|---|
limit | integer | 1–100, default 20 |
Returns: Accessible videos and metadata
GET /v1/gallery/videos/recent
GET /v1/gallery/video/{id}Accessible video raw, or a JPEG frame.
| Query | Type | What |
|---|---|---|
frame_at_s | number | Optional frame position in seconds |
Returns: Accessible video raw, or a JPEG frame
GET /v1/gallery/video/{id}POST /v1/ocr Idempotency-KeyRecognize Latin-script text locally; no image upload.
| Body | Type | What |
|---|---|---|
gallery_id | integer | Accessible gallery image (also requires gallery grant) |
data_base64 | string | Image bytes instead of gallery_id |
Returns: Recognize Latin-script text locally; no image upload
POST /v1/ocr
GET /v1/filesYour 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-KeyReceive a file on the phone (25 MB maximum).
| Query | Type | What |
|---|---|---|
filename | string | Filename for raw-body uploads (or name= for HTTP compatibility) |
| Body | Type | What |
|---|---|---|
name * | string | Filename, no path |
mime | string | MIME type |
data_base64 | string | File bytes; or send raw body with ?name=... |
Returns: Receive a file on the phone (25 MB maximum)
POST /v1/files
GET /v1/downloadsYour 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.
| HTTP | Code | Meaning | The agent should |
|---|---|---|---|
| 400 | bad_request | Malformed HTTP or JSON | Fix the request |
| 401 | unauthorized | Key missing or wrong; reason = key_rotated or agent_removed when Bridgit knows | Stop; tell Rahul the key needs replacing |
| 403 | forbidden_source | Caller is not on the tailnet | Check Tailscale |
| 403 | capability_disabled | Master switch off | Tell Rahul which switch (setting field) |
| 403 | permission_denied | Android permission not granted (permission field) | Tell Rahul; the Access screen fixes it |
| 403 | access_needed | Android special access off (setting field) | Tell Rahul; Bridgit also notifies him |
| 403 | pairing_closed | No pairing window open | Ask Rahul to open one |
| 403 | consent_expired | No active screen-sharing grant | Ask for a new owner-approved grant |
| 403 | agent_not_allowed | This agent lacks a capability grant | Ask the owner to change agent permissions |
| 404 | not_found | Unknown endpoint or id | Fix the request |
| 404 | photo_not_found | Gallery item gone or outside access | Refresh the list |
| 409 | sensor_busy | Sensor in use or capture running | Retry once after a few seconds |
| 409 | device_locked | Needs the phone unlocked | Ask Rahul to unlock |
| 413 | payload_too_large | Over 12 MB base64 (40 MB raw) | Ask for a smaller size (photo_id given) |
| 422 | invalid_parameter | Bad value | Fix; never retry unchanged |
| 422 | not_supported | Android doesn't allow this (for example Wi-Fi toggle) | Don't retry |
| 429 | rate_limited | Over a limit (retry_after_s) | Wait |
| 429 | too_many_open | Too many open questions/notices | Wait for answers or cancel some |
| 403 | notifications_required | Bridgit's notifications are off, so captures are refused (PRD-05) | Tell Rahul to turn notifications on |
| 403 | forbidden | Not allowed for this agent (reason, for example developer_only) | Don't retry |
| 409 | in_progress | Same Idempotency-Key still running | Wait, then retry with the same key |
| 409 | conflict | The 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 |
| 409 | idempotency_expired | Same 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 |
| 429 | quota_exceeded | Daily data, file storage or relay job quota used up (limit) | Remove old transfers or wait for retention |
| 429 | too_many_waits | Too many open wait requests (SEC-08a) | Close some waits |
| 502 | callback_failed | Your callback URL didn't accept the test event (http_status or reason field) | Check the receiver; Rahul sees the host in Activity |
| 500 | internal_error | Bridgit bug | Report via POST /v1/feedback |
| 503 | service_start_blocked | Android hasn't given the service this sensor | Ask Rahul to open Bridgit once |
| 504 | capture_timeout | Sensor didn't answer in time | Retry once |
API revisions
Revision 8 (app 1.6.0, 2026-10-29)
- Device context, sensors, flashlight, timed sound/display controls and find-phone ring
/v1/phone/status - Private file transfers, owner-selected Downloads, Android sharing and clipboard approval
/v1/files - On-device OCR and transcription; short video and accessible gallery videos
/v1/ocr - Read-only Health Connect, app usage and opt-in notification text
/v1/health/records - Owner-approved, per-agent MediaProjection screen-sharing grants
/v1/screen/grant - Sensors
/v1/sensors - Flashlight
/v1/flashlight - Phone context
/v1/phone/context - DND
/v1/phone/dnd - Sound
/v1/phone/sound - Brightness
/v1/phone/brightness - Undo timed changes
/v1/phone/undo - Ring
/v1/phone/ring - Shares
/v1/shares - Downloads
/v1/downloads - Clipboard
/v1/clipboard - Video recording
/v1/camera/video - Gallery videos
/v1/gallery/videos/recent - Gallery video bytes
/v1/gallery/video/{id} - Notification reads
/v1/notifications - Usage summaries
/v1/usage - Shared-screen capture
/v1/screen/share/capture - Per-agent capability grants, enforced for HTTP and MCP
/v1/capabilities
Revision 7 (app 1.5.2, 2026-10-27)
- HTML cards: kind=html draws your own card (offline, Bridget.respond(json) answers)
/v1/interactions - Live text panel: kind=text, then stream text into it
/v1/text/stream - Callbacks: Rahul can set a callback URL for you; events are POSTed signed with HMAC-SHA256; send a test
/v1/callback/test - MCP: use Bridgit as an MCP server (Streamable HTTP) with your key
/v1/mcp - Speaker status: playing shows only your own sound; busy and paused added
/v1/speaker - End tour: optional tour_id so you only end the tour you mean
/v1/tour - Screenshot on request: what's on Rahul's screen now, nothing saved (once he turns on Screenshots)
/v1/screen/capture - Gallery with "Select photos" access: photo_not_found and /v1/gallery/recent say how Rahul allows all
/v1/gallery/recent
Revision 6 (app 1.5.2, 2026-10-27)
- Report your model and harness; Rahul sees it on your agent card
/v1/me - City tour brief in tour.started and GET /v1/tour: directions relative to him, nearest interesting places when nothing is left here
/v1/tour - tour.photo: Rahul took a photo for you on the tour; fetch it
/v1/tour/photo/{n}
Revision 5 (app 1.5.0, 2026-10-27)
- Location with altitude, speed, heading and the compass
/v1/location - Play audio or read text aloud on the phone; newer narration replaces what's queued
/v1/speaker/play - Speak text with the phone's own voice
/v1/speaker/say - What's playing; stop your audio
/v1/speaker - City tour: your running tour (tour.started / tour.tick / tour.question / tour.ended events)
/v1/tour
Revision 4 (app 1.5.0, 2026-10-27)
- Interactions: send Rahul a notice or a question with buttons, a text reply, a choice or links; read aloud if you ask
/v1/interactions - Wait for his answer (wait=55), list or cancel your interactions
/v1/interactions/{id} - Events: answers, closes and expiries for you, oldest first, with long-poll
/v1/events
Revision 3 (app 1.4.4, 2026-10-27)
- Camera zoom: "zoom": 0.5 (ultra-wide) to the phone's maximum; range in /v1/capabilities
/v1/camera/snapshot - API revisions: X-Bridget-API-Revision on every reply, X-Bridget-Whats-New until you've caught up, and this list
/v1/changes
Revision 2 (app 1.4.0, 2026-10-27)
- File a bug report or feature request (any agent)
/v1/feedback - Developer agents: list and read reports, move their status
/v1/feedback/{id}/status
Revision 1 (app 1.3.0, 2026-10-27)
- Health, capabilities (enabled / ready / blocked_reason), this guide and OpenAPI
/v1/health - Camera photo with size presets and raw=1
/v1/camera/snapshot - Microphone clip, 1-120 s
/v1/mic/record - Gallery list
/v1/gallery/recent - One gallery photo, any size, raw=1
/v1/gallery/photo/{id} - Newest screenshot or photo; since + wait for the next one
/v1/image/last - Log: query, follow live, stats, export, notes; /v1/audit alias
/v1/log - Idempotency-Key on POSTs; pending (202) schema
- The bridget helper download
/v1/tools/bridget