Self-hosted API docs

SupaWave Data API

Wave's current Data/Robot API is a JWT-protected JSON-RPC transport. The canonical endpoint is /robot/dataapi/rpc; /robot/dataapi stays live as a backward-compatible alias. Responses are always returned as a JSON array in request order.

Overview

This API lets authenticated users and robots create waves, fetch wave state, append or edit blips, manage participants, query search/profile data, and move snapshots, deltas, or attachments in and out of Wave. The server-side Jakarta Data API servlet is the runtime source of truth for the operation inventory published here.

24Supported JSON-RPC methods
JWTBearer-only authentication on the RPC servlet
2Live RPC routes: canonical + alias
v2026-03-28Docs version stamp

Transport model

Every RPC call is an HTTP POST carrying a JSON object or an array of JSON objects. The request envelope is JSON-RPC-like and uses id, method, and params. The response is always a JSON array even when the request body contains a single object.

Canonical path

POST /robot/dataapi/rpc

Alias path

POST /robot/dataapi

Single request body

{
  "id": "op-1",
  "method": "robot.createWavelet",
  "params": {
    "waveletData": {
      "waveId": "example.com!TBD_wave_1"
    }
  }
}

Batch response shape

[
  {
    "id": "op-1",
    "data": {
      "waveId": "example.com!w+abc123"
    }
  },
  {
    "id": "op-2",
    "error": {
      "message": "Invalid id"
    }
  }
]
Compatibility: /robot/dataapi is still active, but new tooling and documentation should use /robot/dataapi/rpc as the canonical path.

Authentication

The RPC servlet accepts only a bearer JWT in the exact header form Authorization: Bearer <token>. The live Jakarta implementation validates the token type data-api-access, audience data-api, and the participant address in the JWT sub claim. There is no cookie or query-parameter fallback for RPC requests.

Required header

Authorization: Bearer $TOKEN

Token endpoint

GET  /robot/dataapi/token
POST /robot/dataapi/token
POST /robot/token (alias)

Token generation walkthrough

Browser/session flow

  • Open https://supawave.ai/robot/dataapi/token while logged in.
  • Select a short-lived expiry such as 3600 seconds. (Browser tokens are always Data API tokens.)
  • Generate the token and copy it into your Authorization header.

Robot client_credentials flow

This is the curl example to use when you need a token from a robot account. The docs intentionally avoid expiry=0 or any never-expiring 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'
Use short-lived tokens. The live token endpoint still supports effectively long-lived tokens when expiry <= 0 or when a robot account is configured with a zero lifetime. That behavior is high-risk and not shown in any example here.
Robot token lifecycle. A robot's consumer secret is long-lived until you rotate it, but the Data API JWT is not. Data API JWTs are signed by the server's current JWT signing key and include sub (robot address), aud=["data-api"], scope=["wave:data:read","wave:data:write"], exp, and ver (the current tokenVersion for that robot).
  • 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 the robot account's tokenExpirySeconds; prefer expiry=3600 for new integrations.
  • Refresh the JWT after any HTTP 401 and retry the RPC call once with a newly issued token.
  • If tokenVersion changes because the secret was rotated or the robot was paused/deleted, older JWTs stop working even before exp.

Build with AI

Google AI Studio / Gemini works best when you give it a short-lived token, the machine-readable docs, and stable environment variable names. Generate a one-hour JWT, paste the prompt below into your preferred LLM, and replace the robot-specific placeholders once you mint the robot secret.

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=<robot@domain>
SUPAWAVE_ROBOT_SECRET=<consumer secret>
SUPAWAVE_ROBOT_CALLBACK_URL=<deployment url>

Read the docs first, prefer minimal JSON payloads, explain security tradeoffs, and keep tokens short-lived.

Recommended env vars

SUPAWAVE_BASE_URL
SUPAWAVE_API_DOCS_URL
SUPAWAVE_LLM_DOCS_URL
SUPAWAVE_DATA_API_URL
SUPAWAVE_DATA_API_TOKEN
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

1. Read rpcServerUrl from the passive bundle
2. blip.createChild and store newBlipId
3. Stream partials with document.modify REPLACE
4. Keep one in-flight update per reply blip
5. Prefer full accumulated text over append-only chunks

Complete end-to-end example

The quickest safe path for a new integration is: get a short-lived token, create a wave, append a root-thread blip, and add a participant. These are separate calls so you can inspect the IDs returned by each step.

1. Get token

# 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'

2. Create wave

curl -sS \
  -X POST https://supawave.ai/robot/dataapi/rpc \
  -H 'Authorization: Bearer $TOKEN' \
  -H 'Content-Type: application/json' \
  --data-binary '[
  {
    "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"
    }
  }
]'

3. Append blip

curl -sS \
  -X POST https://supawave.ai/robot/dataapi/rpc \
  -H 'Authorization: Bearer $TOKEN' \
  -H 'Content-Type: application/json' \
  --data-binary '[
  {
    "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"
      }
    }
  }
]'

4. Add participant

curl -sS \
  -X POST https://supawave.ai/robot/dataapi/rpc \
  -H 'Authorization: Bearer $TOKEN' \
  -H 'Content-Type: application/json' \
  --data-binary '[
  {
    "id": "op-1",
    "method": "wavelet.addParticipant",
    "params": {
      "waveId": "example.com!w+abc123",
      "waveletId": "example.com!conv+root",
      "participantId": "bob@example.com"
    }
  }
]'

Operation reference

Every method below is currently registered in the live Jakarta Data API registry. Unsupported legacy enum values such as wavelet.create are intentionally excluded.

Protocol and internal

robot.notifyRobotNotifyRequest / RobotNotifyResponse

Negotiates protocol version and optionally communicates a capabilities hash.

Auth: bearer JWT Required: protocolVersion Optional: capabilitiesHash

Request body schema

{
  "id": "op-1",
  "method": "robot.notify",
  "params": {
    "protocolVersion": "0.22",
    "capabilitiesHash": "sha256:optional"
  }
}

Response shape

[
  {
    "id": "op-1",
    "data": {}
  }
]

curl example

curl -sS \
  -X POST https://supawave.ai/robot/dataapi/rpc \
  -H 'Authorization: Bearer $TOKEN' \
  -H 'Content-Type: application/json' \
  --data-binary '[
  {
    "id": "op-1",
    "method": "robot.notify",
    "params": {
      "protocolVersion": "0.22",
      "capabilitiesHash": "sha256:optional"
    }
  }
]'
Notes: Internal compatibility helper. Successful responses are empty.

robot.notifyCapabilitiesHashRobotNotifyCapabilitiesHashRequest / RobotNotifyCapabilitiesHashResponse

Legacy no-op notification entry kept for compatibility with older clients.

Auth: bearer JWT Required: capabilitiesHash Optional: none

Request body schema

{
  "id": "op-1",
  "method": "robot.notifyCapabilitiesHash",
  "params": {
    "capabilitiesHash": "sha256:robot-capabilities"
  }
}

Response shape

[
  {
    "id": "op-1",
    "data": {}
  }
]

curl example

curl -sS \
  -X POST https://supawave.ai/robot/dataapi/rpc \
  -H 'Authorization: Bearer $TOKEN' \
  -H 'Content-Type: application/json' \
  --data-binary '[
  {
    "id": "op-1",
    "method": "robot.notifyCapabilitiesHash",
    "params": {
      "capabilitiesHash": "sha256:robot-capabilities"
    }
  }
]'
Notes: Registered today but intended only for legacy support.

Wave and conversation

robot.createWaveletRobotCreateWaveletRequest / RobotCreateWaveletResponse

Creates a new conversational wave and returns the real wave, wavelet, and root blip IDs.

Auth: bearer JWT Required: waveletData Optional: message

Request body schema

{
  "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 shape

[
  {
    "id": "op-1",
    "data": {
      "blipId": "b+root",
      "message": "created from the Data API",
      "waveId": "example.com!w+abc123",
      "waveletId": "example.com!conv+root"
    }
  }
]

curl example

curl -sS \
  -X POST https://supawave.ai/robot/dataapi/rpc \
  -H 'Authorization: Bearer $TOKEN' \
  -H 'Content-Type: application/json' \
  --data-binary '[
  {
    "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"
    }
  }
]'
Notes: Use temporary IDs in the request. The success payload contains the real IDs.

robot.fetchWaveRobotFetchWaveRequest / RobotFetchWaveResponse

Fetches wave state for a specific wavelet or returns visible wavelet IDs when returnWaveletIds=true.

Auth: bearer JWT Required: waveId Optional: waveletId, returnWaveletIds, message

Request body schema

{
  "id": "op-1",
  "method": "robot.fetchWave",
  "params": {
    "waveId": "example.com!w+abc123",
    "waveletId": "example.com!conv+root",
    "returnWaveletIds": false,
    "message": "optional fetch tag"
  }
}

Response shape

[
  {
    "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"
          ]
        }
      }
    }
  }
]

curl example

curl -sS \
  -X POST https://supawave.ai/robot/dataapi/rpc \
  -H 'Authorization: Bearer $TOKEN' \
  -H 'Content-Type: application/json' \
  --data-binary '[
  {
    "id": "op-1",
    "method": "robot.fetchWave",
    "params": {
      "waveId": "example.com!w+abc123",
      "waveletId": "example.com!conv+root",
      "returnWaveletIds": false,
      "message": "optional fetch tag"
    }
  }
]'
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.appendBlipWaveletAppendBlipRequest / WaveletAppendBlipResponse

Appends a new blip to the root thread of the target conversation.

Auth: bearer JWT Required: waveId, waveletId, blipData Optional: none

Request body schema

{
  "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 shape

[
  {
    "id": "op-1",
    "data": {
      "blipId": "b+root",
      "newBlipId": "b+new"
    }
  }
]

curl example

curl -sS \
  -X POST https://supawave.ai/robot/dataapi/rpc \
  -H 'Authorization: Bearer $TOKEN' \
  -H 'Content-Type: application/json' \
  --data-binary '[
  {
    "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"
      }
    }
  }
]'
Notes: Returns a WaveletBlipCreatedEvent payload with the new blip ID.

wavelet.addParticipantWaveletAddParticipantRequest / WaveletAddParticipantResponse

Adds a participant to the target wavelet.

Auth: bearer JWT Required: waveId, waveletId, participantId Optional: none

Request body schema

{
  "id": "op-1",
  "method": "wavelet.addParticipant",
  "params": {
    "waveId": "example.com!w+abc123",
    "waveletId": "example.com!conv+root",
    "participantId": "bob@example.com"
  }
}

Response shape

[
  {
    "id": "op-1",
    "data": {
      "blipId": "b+root",
      "participantsAdded": [
        "bob@example.com"
      ],
      "participantsRemoved": []
    }
  }
]

curl example

curl -sS \
  -X POST https://supawave.ai/robot/dataapi/rpc \
  -H 'Authorization: Bearer $TOKEN' \
  -H 'Content-Type: application/json' \
  --data-binary '[
  {
    "id": "op-1",
    "method": "wavelet.addParticipant",
    "params": {
      "waveId": "example.com!w+abc123",
      "waveletId": "example.com!conv+root",
      "participantId": "bob@example.com"
    }
  }
]'
Notes: Returns a WaveletParticipantsChangedEvent payload.

wavelet.removeParticipantWaveletRemoveParticipantRequest / WaveletRemoveParticipantResponse

Removes a participant from the target wavelet.

Auth: bearer JWT Required: waveId, waveletId, participantId Optional: none

Request body schema

{
  "id": "op-1",
  "method": "wavelet.removeParticipant",
  "params": {
    "waveId": "example.com!w+abc123",
    "waveletId": "example.com!conv+root",
    "participantId": "bob@example.com"
  }
}

Response shape

[
  {
    "id": "op-1",
    "data": {
      "blipId": "b+root",
      "participantsAdded": [],
      "participantsRemoved": [
        "bob@example.com"
      ]
    }
  }
]

curl example

curl -sS \
  -X POST https://supawave.ai/robot/dataapi/rpc \
  -H 'Authorization: Bearer $TOKEN' \
  -H 'Content-Type: application/json' \
  --data-binary '[
  {
    "id": "op-1",
    "method": "wavelet.removeParticipant",
    "params": {
      "waveId": "example.com!w+abc123",
      "waveletId": "example.com!conv+root",
      "participantId": "bob@example.com"
    }
  }
]'
Notes: Returns a WaveletParticipantsChangedEvent payload.

wavelet.setTitleWaveletSetTitleRequest / WaveletSetTitleResponse

Sets the visible title of the target wavelet.

Auth: bearer JWT Required: waveId, waveletId, waveletTitle Optional: none

Request body schema

{
  "id": "op-1",
  "method": "wavelet.setTitle",
  "params": {
    "waveId": "example.com!w+abc123",
    "waveletId": "example.com!conv+root",
    "waveletTitle": "Project kickoff"
  }
}

Response shape

[
  {
    "id": "op-1",
    "data": {}
  }
]

curl example

curl -sS \
  -X POST https://supawave.ai/robot/dataapi/rpc \
  -H 'Authorization: Bearer $TOKEN' \
  -H 'Content-Type: application/json' \
  --data-binary '[
  {
    "id": "op-1",
    "method": "wavelet.setTitle",
    "params": {
      "waveId": "example.com!w+abc123",
      "waveletId": "example.com!conv+root",
      "waveletTitle": "Project kickoff"
    }
  }
]'
Notes: Successful responses are empty.

blip.createChildBlipCreateChildRequest / BlipCreateChildResponse

Creates a reply-thread child blip under the specified parent blip.

Auth: bearer JWT Required: waveId, waveletId, blipId, blipData Optional: none

Request body schema

{
  "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 shape

[
  {
    "id": "op-1",
    "data": {
      "blipId": "b+root",
      "newBlipId": "b+child"
    }
  }
]

curl example

curl -sS \
  -X POST https://supawave.ai/robot/dataapi/rpc \
  -H 'Authorization: Bearer $TOKEN' \
  -H 'Content-Type: application/json' \
  --data-binary '[
  {
    "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"
      }
    }
  }
]'
Notes: Returns a WaveletBlipCreatedEvent payload.

blip.continueThreadBlipContinueThreadRequest / BlipContinueThreadResponse

Appends a new blip to the end of the current thread for the specified blip.

Auth: bearer JWT Required: waveId, waveletId, blipId, blipData Optional: none

Request body schema

{
  "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 shape

[
  {
    "id": "op-1",
    "data": {
      "blipId": "b+root",
      "newBlipId": "b+thread"
    }
  }
]

curl example

curl -sS \
  -X POST https://supawave.ai/robot/dataapi/rpc \
  -H 'Authorization: Bearer $TOKEN' \
  -H 'Content-Type: application/json' \
  --data-binary '[
  {
    "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"
      }
    }
  }
]'
Notes: Returns a WaveletBlipCreatedEvent payload.

blip.deleteBlipDeleteRequest / BlipDeleteResponse

Deletes the specified blip.

Auth: bearer JWT Required: waveId, waveletId, blipId Optional: none

Request body schema

{
  "id": "op-1",
  "method": "blip.delete",
  "params": {
    "waveId": "example.com!w+abc123",
    "waveletId": "example.com!conv+root",
    "blipId": "b+old"
  }
}

Response shape

[
  {
    "id": "op-1",
    "data": {}
  }
]

curl example

curl -sS \
  -X POST https://supawave.ai/robot/dataapi/rpc \
  -H 'Authorization: Bearer $TOKEN' \
  -H 'Content-Type: application/json' \
  --data-binary '[
  {
    "id": "op-1",
    "method": "blip.delete",
    "params": {
      "waveId": "example.com!w+abc123",
      "waveletId": "example.com!conv+root",
      "blipId": "b+old"
    }
  }
]'
Notes: Successful responses are empty.

document.modifyDocumentModifyRequest / DocumentModifyResponse

Applies a DocumentModifyAction to the target blip content.

Auth: bearer JWT Required: waveId, waveletId, blipId, modifyAction Optional: range, index, modifyQuery

Request body schema

{
  "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 shape

[
  {
    "id": "op-1",
    "data": {}
  }
]

curl example

curl -sS \
  -X POST https://supawave.ai/robot/dataapi/rpc \
  -H 'Authorization: Bearer $TOKEN' \
  -H 'Content-Type: application/json' \
  --data-binary '[
  {
    "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
      }
    }
  }
]'
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.appendMarkupDocumentAppendMarkupRequest / DocumentAppendMarkupResponse

Appends markup to the specified blip.

Auth: bearer JWT Required: waveId, waveletId, blipId, content Optional: none

Request body schema

{
  "id": "op-1",
  "method": "document.appendMarkup",
  "params": {
    "waveId": "example.com!w+abc123",
    "waveletId": "example.com!conv+root",
    "blipId": "b+root",
    "content": "<p><b>Marked up text</b></p>"
  }
}

Response shape

[
  {
    "id": "op-1",
    "data": {}
  }
]

curl example

curl -sS \
  -X POST https://supawave.ai/robot/dataapi/rpc \
  -H 'Authorization: Bearer $TOKEN' \
  -H 'Content-Type: application/json' \
  --data-binary '[
  {
    "id": "op-1",
    "method": "document.appendMarkup",
    "params": {
      "waveId": "example.com!w+abc123",
      "waveletId": "example.com!conv+root",
      "blipId": "b+root",
      "content": "<p><b>Marked up text</b></p>"
    }
  }
]'
Notes: The content value is parsed as XML/markup. Successful responses are empty.

document.appendInlineBlipDocumentAppendInlineBlipRequest / DocumentAppendInlineBlipResponse

Appends a new inline blip on a new line within the specified parent blip.

Auth: bearer JWT Required: waveId, waveletId, blipId, blipData Optional: none

Request body schema

{
  "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 shape

[
  {
    "id": "op-1",
    "data": {
      "blipId": "b+root",
      "newBlipId": "b+inline"
    }
  }
]

curl example

curl -sS \
  -X POST https://supawave.ai/robot/dataapi/rpc \
  -H 'Authorization: Bearer $TOKEN' \
  -H 'Content-Type: application/json' \
  --data-binary '[
  {
    "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"
      }
    }
  }
]'
Notes: Returns a WaveletBlipCreatedEvent payload.

document.insertInlineBlipDocumentInsertInlineBlipRequest / DocumentInsertInlineBlipResponse

Inserts an inline blip at the provided API text index.

Auth: bearer JWT Required: waveId, waveletId, blipId, index, blipData Optional: none

Request body schema

{
  "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 shape

[
  {
    "id": "op-1",
    "data": {
      "blipId": "b+root",
      "newBlipId": "b+inline"
    }
  }
]

curl example

curl -sS \
  -X POST https://supawave.ai/robot/dataapi/rpc \
  -H 'Authorization: Bearer $TOKEN' \
  -H 'Content-Type: application/json' \
  --data-binary '[
  {
    "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"
      }
    }
  }
]'
Notes: The index must be greater than zero. Returns a WaveletBlipCreatedEvent payload.

document.insertInlineBlipAfterElementDocumentInsertInlineBlipAfterElementRequest / DocumentInsertInlineBlipAfterElementResponse

Inserts an inline blip immediately after the specified element.

Auth: bearer JWT Required: waveId, waveletId, blipId, element, blipData Optional: none

Request body schema

{
  "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 shape

[
  {
    "id": "op-1",
    "data": {
      "blipId": "b+root",
      "newBlipId": "b+inline"
    }
  }
]

curl example

curl -sS \
  -X POST https://supawave.ai/robot/dataapi/rpc \
  -H 'Authorization: Bearer $TOKEN' \
  -H 'Content-Type: application/json' \
  --data-binary '[
  {
    "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"
      }
    }
  }
]'
Notes: The server resolves the actual element location before inserting the inline thread.

Search, profile, and folders

robot.fetchProfilesRobotFetchProfilesRequest / RobotFetchProfilesResponse

Fetches participant profile records for one or more addresses.

Auth: bearer JWT Required: fetchProfilesRequest Optional: none

Request body schema

{
  "id": "op-1",
  "method": "robot.fetchProfiles",
  "params": {
    "fetchProfilesRequest": {
      "participantIds": [
        "alice@example.com",
        "bob@example.com"
      ],
      "language": "en"
    }
  }
}

Response shape

[
  {
    "id": "op-1",
    "data": {
      "fetchProfilesResult": {
        "profiles": [
          {
            "address": "alice@example.com",
            "name": "Alice Example",
            "imageUrl": "/static/images/unknown.jpg",
            "profileUrl": ""
          }
        ]
      }
    }
  }
]

curl example

curl -sS \
  -X POST https://supawave.ai/robot/dataapi/rpc \
  -H 'Authorization: Bearer $TOKEN' \
  -H 'Content-Type: application/json' \
  --data-binary '[
  {
    "id": "op-1",
    "method": "robot.fetchProfiles",
    "params": {
      "fetchProfilesRequest": {
        "participantIds": [
          "alice@example.com",
          "bob@example.com"
        ],
        "language": "en"
      }
    }
  }
]'
Notes: The response wraps profiles inside fetchProfilesResult.

robot.folderActionRobotFolderActionRequest / RobotFolderActionResponse

Marks the wave or a specific blip as read or unread for the current user.

Auth: bearer JWT Required: waveId, waveletId, modifyHow Optional: blipId

Request body schema

{
  "id": "op-1",
  "method": "robot.folderAction",
  "params": {
    "waveId": "example.com!w+abc123",
    "waveletId": "example.com!conv+root",
    "modifyHow": "markAsRead",
    "blipId": "b+root"
  }
}

Response shape

[
  {
    "id": "op-1",
    "data": {}
  }
]

curl example

curl -sS \
  -X POST https://supawave.ai/robot/dataapi/rpc \
  -H 'Authorization: Bearer $TOKEN' \
  -H 'Content-Type: application/json' \
  --data-binary '[
  {
    "id": "op-1",
    "method": "robot.folderAction",
    "params": {
      "waveId": "example.com!w+abc123",
      "waveletId": "example.com!conv+root",
      "modifyHow": "markAsRead",
      "blipId": "b+root"
    }
  }
]'
Notes: Supported modifyHow values are markAsRead and markAsUnread.

Export and import

robot.exportSnapshotRobotExportSnapshotRequest / RobotExportSnapshotResponse

Exports a committed wavelet snapshot as raw JSON.

Auth: bearer JWT Required: waveId, waveletId Optional: none

Request body schema

{
  "id": "op-1",
  "method": "robot.exportSnapshot",
  "params": {
    "waveId": "example.com!w+abc123",
    "waveletId": "example.com!conv+root"
  }
}

Response shape

[
  {
    "id": "op-1",
    "data": {
      "rawSnapshot": "{\"waveletId\":\"example.com!conv+root\",\"version\":42}"
    }
  }
]

curl example

curl -sS \
  -X POST https://supawave.ai/robot/dataapi/rpc \
  -H 'Authorization: Bearer $TOKEN' \
  -H 'Content-Type: application/json' \
  --data-binary '[
  {
    "id": "op-1",
    "method": "robot.exportSnapshot",
    "params": {
      "waveId": "example.com!w+abc123",
      "waveletId": "example.com!conv+root"
    }
  }
]'
Notes: The rawSnapshot string contains serialized snapshot JSON.

robot.exportDeltasRobotExportDeltasRequest / RobotExportDeltasResponse

Exports serialized deltas plus the target hashed version.

Auth: bearer JWT Required: waveId, waveletId, fromVersion, toVersion Optional: none

Request body schema

{
  "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 shape

[
  {
    "id": "op-1",
    "data": {
      "rawDeltas": [
        "BASE64_DELTA_BYTES"
      ],
      "targetVersion": "BASE64_HASHED_VERSION_TARGET"
    }
  }
]

curl example

curl -sS \
  -X POST https://supawave.ai/robot/dataapi/rpc \
  -H 'Authorization: Bearer $TOKEN' \
  -H 'Content-Type: application/json' \
  --data-binary '[
  {
    "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"
    }
  }
]'
Notes: Both version parameters are required by the current service implementation.

robot.exportAttachmentRobotExportAttachmentRequest / RobotExportAttachmentResponse

Exports attachment bytes together with the stored file metadata.

Auth: bearer JWT Required: attachmentId Optional: none

Request body schema

{
  "id": "op-1",
  "method": "robot.exportAttachment",
  "params": {
    "attachmentId": "att+123"
  }
}

Response shape

[
  {
    "id": "op-1",
    "data": {
      "attachmentData": {
        "fileName": "design.pdf",
        "creator": "alice@example.com",
        "data": "BASE64_ATTACHMENT_BYTES"
      }
    }
  }
]

curl example

curl -sS \
  -X POST https://supawave.ai/robot/dataapi/rpc \
  -H 'Authorization: Bearer $TOKEN' \
  -H 'Content-Type: application/json' \
  --data-binary '[
  {
    "id": "op-1",
    "method": "robot.exportAttachment",
    "params": {
      "attachmentId": "att+123"
    }
  }
]'
Notes: The attachment data payload includes fileName, creator, and raw bytes.

robot.importDeltasRobotImportDeltasRequest / RobotImportDeltasResponse

Imports serialized deltas into the target wavelet and reports the first imported version.

Auth: bearer JWT Required: waveId, waveletId, rawDeltas Optional: none

Request body schema

{
  "id": "op-1",
  "method": "robot.importDeltas",
  "params": {
    "waveId": "example.com!w+abc123",
    "waveletId": "example.com!conv+root",
    "rawDeltas": [
      "BASE64_DELTA_BYTES"
    ]
  }
}

Response shape

[
  {
    "id": "op-1",
    "data": {
      "importedFromVersion": 42
    }
  }
]

curl example

curl -sS \
  -X POST https://supawave.ai/robot/dataapi/rpc \
  -H 'Authorization: Bearer $TOKEN' \
  -H 'Content-Type: application/json' \
  --data-binary '[
  {
    "id": "op-1",
    "method": "robot.importDeltas",
    "params": {
      "waveId": "example.com!w+abc123",
      "waveletId": "example.com!conv+root",
      "rawDeltas": [
        "BASE64_DELTA_BYTES"
      ]
    }
  }
]'
Notes: The server can return an error if the current wavelet version changes during import.

robot.importAttachmentRobotImportAttachmentRequest / RobotImportAttachmentResponse

Stores attachment bytes in the target wavelet context.

Auth: bearer JWT Required: waveId, waveletId, attachmentId, attachmentData Optional: none

Request body schema

{
  "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 shape

[
  {
    "id": "op-1",
    "data": {}
  }
]

curl example

curl -sS \
  -X POST https://supawave.ai/robot/dataapi/rpc \
  -H 'Authorization: Bearer $TOKEN' \
  -H 'Content-Type: application/json' \
  --data-binary '[
  {
    "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"
      }
    }
  }
]'
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.

Errors and status codes

Invalid or missing JWT

HTTP/1.1 401 Unauthorized

Malformed JSON body

HTTP/1.1 400 Bad Request
Unable to parse Json to list of OperationRequests

Per-operation failure

[
  {
    "id": "op-1",
    "error": {
      "message": "Invalid id"
    }
  }
]

Token endpoint JSON error

{
  "error": "invalid_client",
  "error_description": "Robot credentials were rejected"
}

Versioning and compatibility

The runtime Data API is currently unversioned. This documentation set is version stamped at 2026-03-28 so clients can see which contract snapshot they were built against. Future breaking changes should introduce a versioned runtime path rather than silently changing semantics in place.

Robot Management API

REST API for programmatic robot management. All endpoints require a Authorization: Bearer <token> header with a data-api-access JWT.

Base path: /api/robots

MethodPathDescription
GET/api/robotsList all robots owned by the authenticated user
POST/api/robotsRegister a new robot. Body: {"username","description","callbackUrl","tokenExpiry"}
GET/api/robots/{id}Get robot details
PUT/api/robots/{id}/urlUpdate callback URL. Body: {"url":"..."}
PUT/api/robots/{id}/descriptionUpdate description. Body: {"description":"..."}
POST/api/robots/{id}/rotateRotate consumer secret (returns new secret)
POST/api/robots/{id}/verifyTest bot (fetches capabilities from callback URL)
PUT/api/robots/{id}/pausedPause/unpause. Body: {"paused":"true|false"}
DELETE/api/robots/{id}Soft delete (pauses robot, clears callback URL)

Registration example

curl -X POST https://supawave.ai/api/robots \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"username":"my-bot","description":"My robot","tokenExpiry":3600}'

Response

{"id":"my-bot@domain","secret":"...","status":"active","callbackUrl":"","description":"My robot","tokenExpirySeconds":3600,"createdAt":"..."}

Legacy and unsupported notes

  • robot.createWavelet is the supported create method. wavelet.create is not part of the live Jakarta Data API registry.
  • Legacy OAuth 1.0 code has been removed. All robot API authentication uses JWT Bearer tokens.
  • Public docs here are scoped to the 24 methods in the live Jakarta registry, not the full shared OperationType enum.