SupaWave Data API LLM Reference Docs version: 2026-03-28 Index: https://supawave.ai/llms.txt HTML docs: https://supawave.ai/api-docs OpenAPI JSON: https://supawave.ai/api/openapi.json Canonical RPC path: /robot/dataapi/rpc Alias path: /robot/dataapi Token endpoint: /robot/dataapi/token (alias: /robot/token) Auth: Authorization: Bearer Data API tokens: JWT type=data-api-access, audience=data-api, scopes=wave:data:read,wave:data:write Robot API tokens: JWT type=robot-access, audience=robot, scopes=wave:robot:active,wave:data:read,wave:data:write (pass token_type=robot) Transport: HTTP POST JSON-RPC. Request body can be one object or an array. Response body is always an array in request order. Robot Management REST API Base: /api/robots (same Bearer token auth) POST /api/robots — register robot: {"username","description","callbackUrl","tokenExpiry"} → {id, secret, status} GET /api/robots — list owned robots GET /api/robots/{id} — robot details PUT /api/robots/{id}/url — update callback URL: {"url":"..."} PUT /api/robots/{id}/description — update description: {"description":"..."} POST /api/robots/{id}/rotate — rotate secret (returns new secret) POST /api/robots/{id}/verify — test bot PUT /api/robots/{id}/paused — pause/unpause: {"paused":"true|false"} DELETE /api/robots/{id} — soft delete Token acquisition (client_credentials, short-lived example) # Data API token (default) curl -sS \ -X POST https://supawave.ai/robot/dataapi/token \ -H 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'grant_type=client_credentials' \ --data-urlencode 'client_id=robot@example.com' \ --data-urlencode 'client_secret=replace-me' \ --data-urlencode 'expiry=3600' # Active Robot API token (for /robot/rpc) curl -sS \ -X POST https://supawave.ai/robot/dataapi/token \ -H 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'grant_type=client_credentials' \ --data-urlencode 'client_id=robot@example.com' \ --data-urlencode 'client_secret=replace-me' \ --data-urlencode 'token_type=robot' \ --data-urlencode 'expiry=3600' Robot token lifecycle - The robot consumer secret is long-lived until rotation; the JWT is not. - Data API JWTs are signed by the server's current JWT signing key and include typ=data-api-access, sub=, aud=[data-api], scope=[wave:data:read,wave:data:write], exp, and ver=tokenVersion. - The server only issues robot tokens once the robot has a configured callback URL and verified registration state. - If you omit expiry, the server falls back to tokenExpirySeconds from the robot account; prefer expiry=3600 for new integrations. - Refresh the JWT after any HTTP 401 and retry once with a newly issued token. - If tokenVersion changes because the secret was rotated or the robot was paused/deleted, older JWTs stop working immediately. Google AI Studio / Gemini starter prompt Build a SupaWave robot for me. Use these environment variables exactly: SUPAWAVE_BASE_URL=https://supawave.ai SUPAWAVE_API_DOCS_URL=https://supawave.ai/api-docs SUPAWAVE_LLM_DOCS_URL=https://supawave.ai/api/llm.txt SUPAWAVE_DATA_API_URL=https://supawave.ai/robot/dataapi/rpc SUPAWAVE_DATA_API_TOKEN=<1 hour JWT> SUPAWAVE_ROBOT_ID= SUPAWAVE_ROBOT_SECRET= SUPAWAVE_ROBOT_CALLBACK_URL= Minimal common operations - robot.createWavelet - wavelet.appendBlip - wavelet.addParticipant - robot.fetchWave - robot.search Streaming replies - Passive callbacks are single-response; they do not stream robot output by themselves. - Use rpcServerUrl from the passive bundle for follow-on JSON-RPC writes. - Call blip.createChild once, persist data.newBlipId, then send serialized document.modify REPLACE updates with the full accumulated reply text. - Stream into a robot-owned reply blip only, and keep one in-flight update per streamed reply blip. Request envelope { "id": "op-1", "method": "robot.createWavelet", "params": { "waveletData": { "waveId": "example.com!TBD_wave_1" } } } Batch response envelope [ { "id": "op-1", "data": { "waveId": "example.com!w+abc123" } }, { "id": "op-2", "error": { "message": "Invalid id" } } ] Supported methods - robot.notify - robot.notifyCapabilitiesHash - robot.createWavelet - robot.fetchWave - wavelet.appendBlip - wavelet.addParticipant - wavelet.removeParticipant - wavelet.setTitle - blip.createChild - blip.continueThread - blip.delete - document.modify - document.appendMarkup - document.appendInlineBlip - document.insertInlineBlip - document.insertInlineBlipAfterElement - robot.search - robot.fetchProfiles - robot.folderAction - robot.exportSnapshot - robot.exportDeltas - robot.exportAttachment - robot.importDeltas - robot.importAttachment Protocol and internal ===================== robot.notify Summary: Negotiates protocol version and optionally communicates a capabilities hash. Required params: protocolVersion Optional params: capabilitiesHash Component schema: RobotNotifyRequest / RobotNotifyResponse Request skeleton: { "id": "op-1", "method": "robot.notify", "params": { "protocolVersion": "0.22", "capabilitiesHash": "sha256:optional" } } Response skeleton: [ { "id": "op-1", "data": {} } ] Notes: Internal compatibility helper. Successful responses are empty. robot.notifyCapabilitiesHash Summary: Legacy no-op notification entry kept for compatibility with older clients. Required params: capabilitiesHash Optional params: none Component schema: RobotNotifyCapabilitiesHashRequest / RobotNotifyCapabilitiesHashResponse Request skeleton: { "id": "op-1", "method": "robot.notifyCapabilitiesHash", "params": { "capabilitiesHash": "sha256:robot-capabilities" } } Response skeleton: [ { "id": "op-1", "data": {} } ] Notes: Registered today but intended only for legacy support. Wave and conversation ===================== robot.createWavelet Summary: Creates a new conversational wave and returns the real wave, wavelet, and root blip IDs. Required params: waveletData Optional params: message Component schema: RobotCreateWaveletRequest / RobotCreateWaveletResponse Request skeleton: { "id": "op-1", "method": "robot.createWavelet", "params": { "waveletData": { "waveId": "example.com!TBD_wave_1", "waveletId": "example.com!conv+root", "rootBlipId": "TBD_blip_1", "participants": [ "alice@example.com", "bob@example.com" ] }, "message": "created from the Data API" } } Response skeleton: [ { "id": "op-1", "data": { "blipId": "b+root", "message": "created from the Data API", "waveId": "example.com!w+abc123", "waveletId": "example.com!conv+root" } } ] Notes: Use temporary IDs in the request. The success payload contains the real IDs. robot.fetchWave Summary: Fetches wave state for a specific wavelet or returns visible wavelet IDs when returnWaveletIds=true. Required params: waveId Optional params: waveletId, returnWaveletIds, message Component schema: RobotFetchWaveRequest / RobotFetchWaveResponse Request skeleton: { "id": "op-1", "method": "robot.fetchWave", "params": { "waveId": "example.com!w+abc123", "waveletId": "example.com!conv+root", "returnWaveletIds": false, "message": "optional fetch tag" } } Response skeleton: [ { "id": "op-1", "data": { "robotAddress": "helper-bot@example.com", "rpcServerUrl": "https://wave.example.com/robot/dataapi/rpc", "blipId": "b+root", "message": "optional fetch tag", "waveletData": { "waveId": "example.com!w+abc123", "waveletId": "example.com!conv+root", "rootBlipId": "b+root", "title": "Project kickoff" }, "blips": { "b+root": { "blipId": "b+root", "content": "\nWelcome to the wave", "contributors": [ "alice@example.com" ] } }, "threads": { "thread+root": { "id": "thread+root", "blipIds": [ "b+root" ] } } } } ] Notes: When returnWaveletIds=true the server returns waveletIds instead of the waveletData/blips/threads bundle. Fetch bundles include robotAddress and, on current servers, rpcServerUrl. Treat missing threads as {} when reading older payloads. wavelet.appendBlip Summary: Appends a new blip to the root thread of the target conversation. Required params: waveId, waveletId, blipData Optional params: none Component schema: WaveletAppendBlipRequest / WaveletAppendBlipResponse Request skeleton: { "id": "op-1", "method": "wavelet.appendBlip", "params": { "waveId": "example.com!w+abc123", "waveletId": "example.com!conv+root", "blipData": { "blipId": "TBD_blip_2", "content": "\nHello from the API" } } } Response skeleton: [ { "id": "op-1", "data": { "blipId": "b+root", "newBlipId": "b+new" } } ] Notes: Returns a WaveletBlipCreatedEvent payload with the new blip ID. wavelet.addParticipant Summary: Adds a participant to the target wavelet. Required params: waveId, waveletId, participantId Optional params: none Component schema: WaveletAddParticipantRequest / WaveletAddParticipantResponse Request skeleton: { "id": "op-1", "method": "wavelet.addParticipant", "params": { "waveId": "example.com!w+abc123", "waveletId": "example.com!conv+root", "participantId": "bob@example.com" } } Response skeleton: [ { "id": "op-1", "data": { "blipId": "b+root", "participantsAdded": [ "bob@example.com" ], "participantsRemoved": [] } } ] Notes: Returns a WaveletParticipantsChangedEvent payload. wavelet.removeParticipant Summary: Removes a participant from the target wavelet. Required params: waveId, waveletId, participantId Optional params: none Component schema: WaveletRemoveParticipantRequest / WaveletRemoveParticipantResponse Request skeleton: { "id": "op-1", "method": "wavelet.removeParticipant", "params": { "waveId": "example.com!w+abc123", "waveletId": "example.com!conv+root", "participantId": "bob@example.com" } } Response skeleton: [ { "id": "op-1", "data": { "blipId": "b+root", "participantsAdded": [], "participantsRemoved": [ "bob@example.com" ] } } ] Notes: Returns a WaveletParticipantsChangedEvent payload. wavelet.setTitle Summary: Sets the visible title of the target wavelet. Required params: waveId, waveletId, waveletTitle Optional params: none Component schema: WaveletSetTitleRequest / WaveletSetTitleResponse Request skeleton: { "id": "op-1", "method": "wavelet.setTitle", "params": { "waveId": "example.com!w+abc123", "waveletId": "example.com!conv+root", "waveletTitle": "Project kickoff" } } Response skeleton: [ { "id": "op-1", "data": {} } ] Notes: Successful responses are empty. blip.createChild Summary: Creates a reply-thread child blip under the specified parent blip. Required params: waveId, waveletId, blipId, blipData Optional params: none Component schema: BlipCreateChildRequest / BlipCreateChildResponse Request skeleton: { "id": "op-1", "method": "blip.createChild", "params": { "waveId": "example.com!w+abc123", "waveletId": "example.com!conv+root", "blipId": "b+parent", "blipData": { "blipId": "TBD_child_1", "content": "\nChild reply" } } } Response skeleton: [ { "id": "op-1", "data": { "blipId": "b+root", "newBlipId": "b+child" } } ] Notes: Returns a WaveletBlipCreatedEvent payload. blip.continueThread Summary: Appends a new blip to the end of the current thread for the specified blip. Required params: waveId, waveletId, blipId, blipData Optional params: none Component schema: BlipContinueThreadRequest / BlipContinueThreadResponse Request skeleton: { "id": "op-1", "method": "blip.continueThread", "params": { "waveId": "example.com!w+abc123", "waveletId": "example.com!conv+root", "blipId": "b+parent", "blipData": { "blipId": "TBD_thread_1", "content": "\nThread continuation" } } } Response skeleton: [ { "id": "op-1", "data": { "blipId": "b+root", "newBlipId": "b+thread" } } ] Notes: Returns a WaveletBlipCreatedEvent payload. blip.delete Summary: Deletes the specified blip. Required params: waveId, waveletId, blipId Optional params: none Component schema: BlipDeleteRequest / BlipDeleteResponse Request skeleton: { "id": "op-1", "method": "blip.delete", "params": { "waveId": "example.com!w+abc123", "waveletId": "example.com!conv+root", "blipId": "b+old" } } Response skeleton: [ { "id": "op-1", "data": {} } ] Notes: Successful responses are empty. document.modify Summary: Applies a DocumentModifyAction to the target blip content. Required params: waveId, waveletId, blipId, modifyAction Optional params: range, index, modifyQuery Component schema: DocumentModifyRequest / DocumentModifyResponse Request skeleton: { "id": "op-1", "method": "document.modify", "params": { "waveId": "example.com!w+abc123", "waveletId": "example.com!conv+root", "blipId": "b+root", "modifyAction": { "modifyHow": "REPLACE", "values": [ "Updated text" ], "annotationKey": "", "elements": [], "bundledAnnotations": [], "useMarkup": false }, "range": { "start": 1, "end": 8 } } } Response skeleton: [ { "id": "op-1", "data": {} } ] Notes: Use range, index, or modifyQuery to target the document region. To insert an attachment-backed inline image after robot.importAttachment, send modifyHow=INSERT with an IMAGE element whose properties include attachmentId, caption, and optional display-size=small|medium|large. Successful responses are empty. document.appendMarkup Summary: Appends markup to the specified blip. Required params: waveId, waveletId, blipId, content Optional params: none Component schema: DocumentAppendMarkupRequest / DocumentAppendMarkupResponse Request skeleton: { "id": "op-1", "method": "document.appendMarkup", "params": { "waveId": "example.com!w+abc123", "waveletId": "example.com!conv+root", "blipId": "b+root", "content": "

Marked up text

" } } Response skeleton: [ { "id": "op-1", "data": {} } ] Notes: The content value is parsed as XML/markup. Successful responses are empty. document.appendInlineBlip Summary: Appends a new inline blip on a new line within the specified parent blip. Required params: waveId, waveletId, blipId, blipData Optional params: none Component schema: DocumentAppendInlineBlipRequest / DocumentAppendInlineBlipResponse Request skeleton: { "id": "op-1", "method": "document.appendInlineBlip", "params": { "waveId": "example.com!w+abc123", "waveletId": "example.com!conv+root", "blipId": "b+root", "blipData": { "blipId": "TBD_inline_1", "content": "\nInline details" } } } Response skeleton: [ { "id": "op-1", "data": { "blipId": "b+root", "newBlipId": "b+inline" } } ] Notes: Returns a WaveletBlipCreatedEvent payload. document.insertInlineBlip Summary: Inserts an inline blip at the provided API text index. Required params: waveId, waveletId, blipId, index, blipData Optional params: none Component schema: DocumentInsertInlineBlipRequest / DocumentInsertInlineBlipResponse Request skeleton: { "id": "op-1", "method": "document.insertInlineBlip", "params": { "waveId": "example.com!w+abc123", "waveletId": "example.com!conv+root", "blipId": "b+root", "index": 12, "blipData": { "blipId": "TBD_inline_2", "content": "\nInline details" } } } Response skeleton: [ { "id": "op-1", "data": { "blipId": "b+root", "newBlipId": "b+inline" } } ] Notes: The index must be greater than zero. Returns a WaveletBlipCreatedEvent payload. document.insertInlineBlipAfterElement Summary: Inserts an inline blip immediately after the specified element. Required params: waveId, waveletId, blipId, element, blipData Optional params: none Component schema: DocumentInsertInlineBlipAfterElementRequest / DocumentInsertInlineBlipAfterElementResponse Request skeleton: { "id": "op-1", "method": "document.insertInlineBlipAfterElement", "params": { "waveId": "example.com!w+abc123", "waveletId": "example.com!conv+root", "blipId": "b+root", "element": { "type": "IMAGE", "properties": { "url": "https://example.test/image.png" } }, "blipData": { "blipId": "TBD_inline_3", "content": "\nElement follow-up" } } } Response skeleton: [ { "id": "op-1", "data": { "blipId": "b+root", "newBlipId": "b+inline" } } ] Notes: The server resolves the actual element location before inserting the inline thread. Search, profile, and folders ============================ robot.search Summary: Executes a wave search for the authenticated participant. Required params: query Optional params: index, numResults Component schema: RobotSearchRequest / RobotSearchResponse Request skeleton: { "id": "op-1", "method": "robot.search", "params": { "query": "in:inbox", "index": 0, "numResults": 10 } } Response skeleton: [ { "id": "op-1", "data": { "searchResults": { "query": "in:inbox", "digests": [ { "title": "Project kickoff", "waveId": "wave://example.com/w+abc123", "snippet": "Welcome to the wave" } ] } } } ] Notes: Index defaults to 0 and numResults defaults to 10 when omitted. robot.fetchProfiles Summary: Fetches participant profile records for one or more addresses. Required params: fetchProfilesRequest Optional params: none Component schema: RobotFetchProfilesRequest / RobotFetchProfilesResponse Request skeleton: { "id": "op-1", "method": "robot.fetchProfiles", "params": { "fetchProfilesRequest": { "participantIds": [ "alice@example.com", "bob@example.com" ], "language": "en" } } } Response skeleton: [ { "id": "op-1", "data": { "fetchProfilesResult": { "profiles": [ { "address": "alice@example.com", "name": "Alice Example", "imageUrl": "/static/images/unknown.jpg", "profileUrl": "" } ] } } } ] Notes: The response wraps profiles inside fetchProfilesResult. robot.folderAction Summary: Marks the wave or a specific blip as read or unread for the current user. Required params: waveId, waveletId, modifyHow Optional params: blipId Component schema: RobotFolderActionRequest / RobotFolderActionResponse Request skeleton: { "id": "op-1", "method": "robot.folderAction", "params": { "waveId": "example.com!w+abc123", "waveletId": "example.com!conv+root", "modifyHow": "markAsRead", "blipId": "b+root" } } Response skeleton: [ { "id": "op-1", "data": {} } ] Notes: Supported modifyHow values are markAsRead and markAsUnread. Export and import ================= robot.exportSnapshot Summary: Exports a committed wavelet snapshot as raw JSON. Required params: waveId, waveletId Optional params: none Component schema: RobotExportSnapshotRequest / RobotExportSnapshotResponse Request skeleton: { "id": "op-1", "method": "robot.exportSnapshot", "params": { "waveId": "example.com!w+abc123", "waveletId": "example.com!conv+root" } } Response skeleton: [ { "id": "op-1", "data": { "rawSnapshot": "{\"waveletId\":\"example.com!conv+root\",\"version\":42}" } } ] Notes: The rawSnapshot string contains serialized snapshot JSON. robot.exportDeltas Summary: Exports serialized deltas plus the target hashed version. Required params: waveId, waveletId, fromVersion, toVersion Optional params: none Component schema: RobotExportDeltasRequest / RobotExportDeltasResponse Request skeleton: { "id": "op-1", "method": "robot.exportDeltas", "params": { "waveId": "example.com!w+abc123", "waveletId": "example.com!conv+root", "fromVersion": "BASE64_HASHED_VERSION_START", "toVersion": "BASE64_HASHED_VERSION_END" } } Response skeleton: [ { "id": "op-1", "data": { "rawDeltas": [ "BASE64_DELTA_BYTES" ], "targetVersion": "BASE64_HASHED_VERSION_TARGET" } } ] Notes: Both version parameters are required by the current service implementation. robot.exportAttachment Summary: Exports attachment bytes together with the stored file metadata. Required params: attachmentId Optional params: none Component schema: RobotExportAttachmentRequest / RobotExportAttachmentResponse Request skeleton: { "id": "op-1", "method": "robot.exportAttachment", "params": { "attachmentId": "att+123" } } Response skeleton: [ { "id": "op-1", "data": { "attachmentData": { "fileName": "design.pdf", "creator": "alice@example.com", "data": "BASE64_ATTACHMENT_BYTES" } } } ] Notes: The attachment data payload includes fileName, creator, and raw bytes. robot.importDeltas Summary: Imports serialized deltas into the target wavelet and reports the first imported version. Required params: waveId, waveletId, rawDeltas Optional params: none Component schema: RobotImportDeltasRequest / RobotImportDeltasResponse Request skeleton: { "id": "op-1", "method": "robot.importDeltas", "params": { "waveId": "example.com!w+abc123", "waveletId": "example.com!conv+root", "rawDeltas": [ "BASE64_DELTA_BYTES" ] } } Response skeleton: [ { "id": "op-1", "data": { "importedFromVersion": 42 } } ] Notes: The server can return an error if the current wavelet version changes during import. robot.importAttachment Summary: Stores attachment bytes in the target wavelet context. Required params: waveId, waveletId, attachmentId, attachmentData Optional params: none Component schema: RobotImportAttachmentRequest / RobotImportAttachmentResponse Request skeleton: { "id": "op-1", "method": "robot.importAttachment", "params": { "waveId": "example.com!w+abc123", "waveletId": "example.com!conv+root", "attachmentId": "att+123", "attachmentData": { "fileName": "design.pdf", "creator": "alice@example.com", "data": "BASE64_ATTACHMENT_BYTES" } } } Response skeleton: [ { "id": "op-1", "data": {} } ] Notes: Successful responses are empty. After import, insert an attachment-backed inline image with document.modify using an IMAGE element whose properties include attachmentId, caption, and optional display-size. Short end-to-end example 1. Get token -> POST /robot/dataapi/token with expiry=3600. 2. Create wave -> robot.createWavelet. 3. Append blip -> wavelet.appendBlip. 4. Add participant -> wavelet.addParticipant. Error conventions - 401 for missing or invalid bearer tokens. - 400 for malformed JSON request bodies. - 200 with per-operation error items for execution failures. - Token endpoint errors return HTTP status plus JSON {error, error_description?}. Passive robot event model ========================= Robots receive JSON-RPC event bundles via POST to their callbackUrl. Declare which events to receive in capabilities.xml (served at /_wave/capabilities.xml). Supported passive events WAVELET_SELF_ADDED, WAVELET_SELF_REMOVED, WAVELET_PARTICIPANTS_CHANGED, WAVELET_TITLE_CHANGED, WAVELET_BLIP_CREATED, WAVELET_BLIP_REMOVED, DOCUMENT_CHANGED, ANNOTATED_TEXT_CHANGED, BLIP_CONTRIBUTORS_CHANGED, BLIP_EDITING_DONE, WAVELET_TAGS_CHANGED, FORM_BUTTON_CLICKED, FORM_VALUE_CHANGED BLIP_EDITING_DONE — Detecting when a user finished editing a blip Subscribe to BLIP_EDITING_DONE to receive a single event when all editing sessions on a blip have completed (all user/d/ annotations have end timestamps). This is the recommended event for AI bots that need to wait for the user to finish typing before generating a response. Example capabilities.xml: Java handler: case BLIP_EDITING_DONE: handleBlip(BlipEditingDoneEvent.as(event).getBlip(), event.getModifiedBy()); break; DOCUMENT_CHANGED fires on every keystroke delta. If you only need to respond after the user is done editing, use BLIP_EDITING_DONE instead. Compatibility notes - Use /robot/dataapi/rpc for new integrations. - /robot/dataapi remains live for compatibility. - /llms-full.txt is the canonical LLM-friendly reference path. - /api/llm.txt remains live as a backward-compatible alias. - Do not advertise wavelet.create as the current public API. All auth uses JWT Bearer tokens. - Fetch and callback bundles include robotAddress. - Current servers also include rpcServerUrl; use it instead of hardcoding /robot/dataapi/rpc or /robot/rpc when present. - Treat missing threads as {} when talking to older bundle payloads.