BubbleBubble/ docs
Bubble API

Documentation

Build with Bubble's API. Every new account gets $3.00 in free credit — no card required to start.

Quickstart

Get an API key, then send your first request.

  1. Sign up at /signup if you don't have an account.
  2. Go to Settings → API keys and create a key. Copy it immediately — you won't be able to see it again.
  3. Send a request:
bash
curl https://grapelabs.us/api/v1/messages \
  -H "Authorization: Bearer bb-YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "bubble-2.0",
    "max_tokens": 1024,
    "messages": [
      { "role": "user", "content": "Hello, Bubble!" }
    ]
  }'

Or try it without writing any code in the Playground.

Authentication

Every request needs your API key in the Authorization header as a bearer token:

text
Authorization: Bearer bb-...

Keys are created and revoked from Settings → API keys. You can create as many named keys as you want (e.g. one for production, one for testing) — revoking one doesn't affect the others.

Keep your key secret. Don't commit it to version control or expose it in client-side code — call the Bubble API from your own backend.

Create a message

POST /api/v1/messages — send a conversation, get a reply back.

ParameterTypeRequiredDescription
messagesarrayYesArray of { role, content } objects. role is "user" or "assistant".
modelstringNo"bubble-2.0" or "pop-2.1" (cosmetic — both use the same model). Defaults to "bubble-2.0".
systemstringNoSystem prompt to steer behavior.
max_tokensnumberNoMax tokens to generate. 1–8192. Defaults to 4096.
streambooleanNoSet true for a server-sent-events stream instead of a single JSON response.

Response shape:

json
{
  "id": "msg_1234567890",
  "model": "bubble-2.0",
  "role": "assistant",
  "content": [
    { "type": "text", "text": "Hi there! How can I help?" }
  ],
  "stop_reason": "end_turn",
  "usage": { "input_tokens": 12, "output_tokens": 9 }
}

Streaming

Set "stream": true to get a server-sent-events stream instead of waiting for the full response:

bash
curl https://grapelabs.us/api/v1/messages \
  -H "Authorization: Bearer bb-YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "bubble-2.0",
    "stream": true,
    "messages": [{ "role": "user", "content": "Write a haiku" }]
  }'

Events sent:

EventData
delta{ "text": "..." } — a chunk of generated text
usage{ "input_tokens": N, "output_tokens": N } — sent once, near the end
done{} — stream finished normally
error{ "message": "..." } — something went wrong

Models

Bubble offers two model names. They're cosmetic — both currently route to the same underlying model, so pick whichever name fits your app.

ModelNotes
bubble-2.0Default. Balanced & dependable.
pop-2.1Fast & punchy framing — same underlying model.

Check usage

GET /api/v1/usage returns your remaining free credit without making a chat request:

bash
curl https://grapelabs.us/api/v1/usage \
  -H "Authorization: Bearer bb-YOUR_KEY"
json
{
  "total_credit_usd": 3.00,
  "spent_usd": 0.0142,
  "remaining_usd": 2.9858
}

Errors

Errors come back as JSON with an HTTP status code and an error object:

json
{
  "error": {
    "message": "Invalid or revoked API key.",
    "type": "authentication_error"
  }
}
StatusTypeMeaning
400invalid_request_errorSomething's wrong with the request body.
401authentication_errorMissing, malformed, or revoked API key.
402insufficient_creditYou've used your free credit.
502api_errorSomething went wrong generating a response. Safe to retry.

Pricing

Every new account starts with $3.00 in free credit. Usage is billed per token:

Per million tokens
Input$3.00
Output$15.00

A typical short exchange (a few hundred tokens in, a few hundred out) costs a small fraction of a cent. Check exact spend any time via GET /api/v1/usage or Settings → API keys.

Code examples

No SDK required — it's a plain JSON REST API. Examples below.

JavaScript

javascript
const res = await fetch("https://grapelabs.us/api/v1/messages", {
  method: "POST",
  headers: {
    "Authorization": "Bearer bb-YOUR_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    model: "bubble-2.0",
    messages: [{ role: "user", content: "Hello!" }],
  }),
});
const data = await res.json();
console.log(data.content[0].text);

Python

python
import requests

res = requests.post(
    "https://grapelabs.us/api/v1/messages",
    headers={"Authorization": "Bearer bb-YOUR_KEY"},
    json={
        "model": "bubble-2.0",
        "messages": [{"role": "user", "content": "Hello!"}],
    },
)
print(res.json()["content"][0]["text"])

Streaming (JavaScript)

javascript
const res = await fetch("https://grapelabs.us/api/v1/messages", {
  method: "POST",
  headers: {
    "Authorization": "Bearer bb-YOUR_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    model: "bubble-2.0",
    stream: true,
    messages: [{ role: "user", content: "Write a haiku" }],
  }),
});

const reader = res.body.getReader();
const decoder = new TextDecoder();
let buffer = "";
while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  buffer += decoder.decode(value, { stream: true });
  const frames = buffer.split("\n\n");
  buffer = frames.pop();
  for (const frame of frames) {
    const dataLine = frame.split("\n").find((l) => l.startsWith("data:"));
    if (!dataLine) continue;
    const data = JSON.parse(dataLine.slice(5));
    if (data.text) process.stdout.write(data.text);
  }
}
Prefer to try requests interactively?Open the Playground
© 2026 GrapeLabs. Bubble is an independent product.