API reference

Gossip Developer API

The Gossip API is organised around REST. It has predictable, resource-oriented URLs, returns JSON-encoded responses, and uses standard HTTP verbs, status codes and authentication. The base URL is:

https://api.gossipbuzz.app/v1

One API for realtime chat, live streaming, video and audio calls, the bot & spam Shield, the Gossip social graph, in-app messaging and AI, paid from one prepaid balance. New here? The quickstarts get chat or a live stream running in minutes, and the API reference lists every endpoint, generated from the API itself. You manage keys, webhooks and usage from the developer dashboard.

Authentication

Authenticate by passing your secret API key as a bearer token (Authorization: Bearer gsk_…) or in an X-API-Key header — both are accepted. Create keys in the dashboard under API & Keys; the full secret is shown exactly once at creation and stored only as a hash — if you lose it, revoke and create a new one.

curl https://api.gossipbuzz.app/v1/buzzes \
  -H "Authorization: Bearer gsk_live_••••••••"

All requests must be made over HTTPS. Requests without a valid key return 401 Unauthorized. Never expose a live key in client-side code. Twenty invalid keys from one address in ten minutes locks that address out with 429 for the rest of the window.

Test vs live keys

Keys come in two modes. gsk_test_… keys hit a sandbox with test data and never affect real accounts or spend. gsk_live_… keys hit production. The prefix tells you which mode a key is in at a glance.

Pricing & cost

Reads are free (only bandwidth is metered). You pay per call for writes, OTP, promo messages and AI. Every response returns its cost in the X-Gossip-Cost-Usd header (USD), and daily totals appear under Usage & analytics. Live numbers are at GET /v1/pricing, and the dashboard has an interactive Cost calculator.

Loading prices…

Plans — one account, one prepaid balance; a plan changes the limits, the included usage credit and the support, never a unit price:

Loading prices…

Exceeding the free daily cap returns 429; Pro-only endpoints return 402 on the Free plan. Live keys pay from the account's one prepaid balance — the same one Realtime usage comes off — and only for calls that succeed; with the balance empty a priced call returns 402 PAYMENT_REQUIRED before any work is done. Test keys are metered and never charged. Top up, and see every movement, under Balance & top-up in the dashboard; a plan's monthly credit lands there when its invoice is paid.

Rate limits

A daily request cap applies per key by plan: Free 100/day, Pro 100,000/day, Scale custom. Exceeding it returns 429 Too Many Requests. Track consumption live under Usage & analytics.

Messaging caps (anti-spam, WhatsApp-style):

ParamTypeDescription
OTP per recipient3 / 10 min · 15 / dayPrevents code-bombing one person.
Promo per recipient1 / dayDon't spam the same person.
Promo per sender1,000 / dayTotal promo sends per developer.

Hitting a messaging cap returns 429. Recipients can also turn off promotional messages or block you entirely (then the send records but delivered: false).

Errors

Gossip uses conventional HTTP status codes. 2xx means success, 4xx indicates a problem with the request, and 5xx indicates a server error. Error bodies are JSON:

{
  "error": {
    "type": "invalid_request",
    "message": "Unknown profile username."
  }
}
ParamTypeDescription
200OKRequest succeeded.
401UnauthorizedMissing or invalid API key.
404Not foundThe resource does not exist.
429Rate limitedToo many requests for your tier.
500Server errorSomething went wrong on our end.

List endpoints are cursor-paginated. Pass limit (max 100) and the next_cursor from the previous response as cursor. When next_cursor is null, you have reached the end.

GET /v1/buzzes?author=mohan&limit=20&cursor=b_8f2c…

Core resources

Profiles

Retrieve a public profile by username.

GET/v1/profiles/{username}
{
  "username": "mohan",
  "full_name": "Mohan Singh",
  "category": "personal",
  "followers": 12840,
  "buzzes": 312,
  "verified": true
}

Buzzes

List recent public buzzes, optionally filtered by author, or fetch a single buzz by id.

GET/v1/buzzes
ParamTypeDescription
authorstringFilter by author username (optional).
limitintegerPage size, 1–100 (default 20).
cursorstringPagination cursor from next_cursor.
GET/v1/buzzes/{id}
{
  "id": "b_8f2c…",
  "type": "text",
  "text": "Good morning from Kathmandu",
  "reactions": 128,
  "comments": 14,
  "created_at": "2026-06-10T09:21:00Z"
}

Moments

List recent public moments (short videos and stories), optionally filtered by author.

GET/v1/sips
ParamTypeDescription
authorstringFilter by author username (optional).
limitintegerPage size, 1–100 (default 20).
{
  "items": [
    {
      "id": "s_2a9c…",
      "author_id": "p_77f1…",
      "author_username": "mohan",
      "caption": "Sunrise over Api Himal 🌄",
      "media_type": "video",
      "video_url": "https://cdn.gossipbuzz.app/sips/…",
      "thumbnail_url": "https://cdn.gossipbuzz.app/sips/…_thumb",
      "like_count": 240,
      "comment_count": 18,
      "view_count": 5120,
      "created_at": "2026-06-09T05:00:00Z"
    }
  ],
  "next_cursor": null
}

Studio assets

List a creator’s public Studio assets — the photos and videos they’ve saved in Creator Studio for reuse across buzzes and moments. Only persistent (paid) assets are returned; ephemeral free-tier AI generations, forms and notes are never exposed.

GET/v1/profiles/{username}/studio
ParamTypeDescription
kindstringFilter by "photo" or "video" (optional).
limitintegerPage size, 1–100 (default 20).
{
  "items": [
    {
      "id": "sa_4d1f…",
      "kind": "photo",
      "url": "https://cdn.gossipbuzz.app/studio/…",
      "thumbnail_url": "https://cdn.gossipbuzz.app/studio/…_thumb",
      "title": "Sunrise over Api Himal",
      "width": 1920,
      "height": 1080,
      "tags": ["landscape", "sunrise"],
      "created_at": "2026-06-09T04:12:00Z"
    }
  ],
  "next_cursor": null
}

Search public profiles (by username / name) and buzzes (by text). Returns both unless you scope it with type.

GET/v1/search
ParamTypeDescription
qstringThe search query (required, 1–100 chars).
typestringLimit to "profiles" or "buzzes" (default: both).
limitintegerMax results per group, 1–50 (default 20).
{
  "query": "nepal",
  "profiles": [
    { "username": "mohan", "full_name": "Mohan Singh", "verified": true, "followers": 12840 }
  ],
  "buzzes": [
    { "id": "b_8f2c…", "type": "text", "text": "Good morning from Kathmandu" }
  ]
}

About content

Services

A profile’s published Services (from its About → Services section). Returns an empty list if the section isn’t published.

GET/v1/profiles/{username}/services
[
  { "id": "sv_1a…", "name": "Logo design", "duration": "3 days",
    "category": "Design", "accepts_bookings": true }
]

Catalog

Published Catalog items — products with prices, stock and images. Prices are display-only (price_currency is coin or usd).

GET/v1/profiles/{username}/catalog
[
  { "id": "ci_9f…", "name": "Pashmina shawl", "department": "Apparel",
    "price_amount": "2500", "price_currency": "coin", "in_stock": true,
    "images": ["https://cdn.gossipbuzz.app/…"] }
]

FAQs

Published FAQ entries for a profile.

GET/v1/profiles/{username}/faqs
[
  { "id": "fq_3c…", "question": "Do you ship abroad?",
    "answer": "Yes, worldwide via DHL.", "category": "Shipping" }
]

Sections

The list of published About sections a profile has, in display order — useful to know which of the above to fetch.

GET/v1/profiles/{username}/sections
[
  { "id": "ps_…", "kind": "services", "position": 0, "status": "published" },
  { "id": "ps_…", "kind": "catalog",  "position": 1, "status": "published" }
]

Writes

Delete a buzz or moment

Writes require a real key and act only on your own content — a key can never modify another account. Buzzes and moments are delete-only (creating/editing posts is intentionally not exposed); Studio is fully manageable below.

DELETE/v1/buzzes/{id}
DELETE/v1/sips/{id}
curl -X DELETE https://api.gossipbuzz.app/v1/buzzes/b_8f2c… \
  -H "Authorization: Bearer gsk_live_••••••••"

{ "ok": true, "id": "b_8f2c…" }

Returns 404 if the post doesn’t exist or isn’t yours. Deletes are soft (recoverable by support).

Manage Studio assets

Full CRUD over your own Creator Studio photos & videos. Upload the file to your own storage first, then register the URL here so it can be reused across buzzes and sips.

POST/v1/studio
ParamTypeDescription
kindstringRequired — "photo" or "video".
urlstringRequired — the asset URL.
thumbnail_urlstringOptional preview image.
titlestringOptional title.
width, heightintegerOptional pixel dimensions.
tagsarrayOptional string tags.
PATCH/v1/studio/{id}
DELETE/v1/studio/{id}
curl -X POST https://api.gossipbuzz.app/v1/studio \
  -H "Authorization: Bearer gsk_live_••••••••" \
  -H "Content-Type: application/json" \
  -d '{ "kind": "photo", "url": "https://cdn.you.app/a.jpg",
        "title": "Api Himal", "tags": ["landscape"] }'

Gossip Realtime

Chat, live streaming & calls

Realtime gives your app the chat server and the live/video server that run Gossip itself — the same infrastructure, reached with keys. Your server holds a secret key and mints short-lived credentials for each of your users; your app only ever holds those. Set Realtime up once per app:

POST/v1/realtime/app
curl -X POST https://api.gossipbuzz.app/v1/realtime/app \
  -H "Authorization: Bearer gsk_live_••••••••"

{ "app_id": "…", "publishable_key": "pk_live_…", "mam": false,
  "products": ["chat","live","calls"], "max_room_size": 5000,
  "chat_host": "rt.eja.gossipbuzz.app", "shield_secret": "…" }
ParamTypeDescription
gsk_live_… / gsk_test_…secret keyServer only. Mints credentials, reads usage. Test keys are metered and priced but never charged.
pk_live_… / pk_test_…publishable keySafe in a client. Only used for the bot & spam shield.
shield_secretstringServer only. Verifies shield tickets with no call back to us.

Change settings with PATCH /v1/realtime/app:

ParamTypeDescription
mambooleanKeep chat history (message archive). Default false — right for stream chat. New credentials move to the matching chat host.
productsstring[]Any of chat, live, calls.
max_room_sizeinteger2–100,000.

Chat

Standard XMPP over WebSocket (RFC 7395) — any XMPP library works. Mint a credential per user on your server, hand it to the client, and join rooms the API names. One live credential per user; minting again replaces it.

POST/v1/realtime/chat/tokens
ParamTypeDescription
user_idstringRequired — YOUR user id.
namestringNickname shown in rooms.
ttl_secondsinteger60–86,400 (default 6 hours).
{ "jid": "a3f…c1.viewer-42@rt.eja.gossipbuzz.app", "user": "a3f…c1.viewer-42",
  "domain": "rt.eja.gossipbuzz.app", "password": "…",
  "ws": "wss://eja.gossipbuzz.app:5443/ws", "muc": "muc.rt.eja.gossipbuzz.app",
  "room_prefix": "a3f…c1--", "nickname": "Viewer42", "mam": false, "expires_at": "…" }
POST/v1/realtime/chat/rooms

Returns the full room address for one of your room names ({ "room": "stream-1" } → a3f…c1--stream-1@muc.rt.eja.gossipbuzz.app). Always use the address the API gives you.

DELETE/v1/realtime/chat/tokens/{user_id}

Revoke a user's credential — for a ban or a sign-out. Their next login is refused. Tip: create rooms with muc#roomconfig_whois = anyone so every client can see which user sent a message; the user id is the part of the JID after a…c1.

Live streaming & calls

WebRTC rooms on our LiveKit servers — use any LiveKit client SDK with the URL and token returned. The room name is scoped to your app.

POST/v1/realtime/live/tokens
ParamTypeDescription
roomstringRequired — your room name (letters, digits, - and _).
identitystringRequired — YOUR user id.
kindstringlive (a broadcast) or call (everyone may publish). Default live.
publishbooleanFor live: may this user broadcast? Viewers default to false.
ttl_secondsinteger60–86,400 (default 2 hours).
{ "url": "wss://…", "token": "eyJ…", "room": "a3f…c1_live_show1", "expires_in": 7200 }

Minutes are measured from our servers when each participant leaves, so there is nothing to report from your side.

Bot & spam shield

For counting real viewers when your backend cannot see IP addresses. Your client asks for a ticket with the publishable key; we see its real address and user agent and answer with a signed verdict. Your server checks the ticket with shield_secret — no call back to us.

POST/v1/realtime/shield/ticket
ParamTypeDescription
X-Publishable-KeyheaderRequired — pk_live_… or pk_test_….
subjectstringRequired — what is being counted, e.g. a device key.
scopestringRequired — what it is counted against, e.g. a stream id.
{ "ticket": "<payload>.<signature>", "verdict": "ok", "reason": "", "expires_at": 1790000000 }
ParamTypeDescription
okverdictCount it.
suspiciousverdictOne address presenting more than 6 viewers on this scope today — do not count it.
botverdictAutomation by its own user agent (curl, headless browsers, scripts).
blockverdictMore than 20 from one address — refuse what it was for.
429statusOver 120 tickets a minute from one address — treat like a bot.

Verify: split the ticket on ., compute base64url(HMAC-SHA256(shield_secret, payload)) and compare with the signature; then decode the payload ({a, s, c, v, e} = app, subject, scope, verdict, expiry) and check the subject, the scope and that e is in the future. GET /v1/realtime/shield/report shows each verdict and the busiest addresses. Addresses are stored only as daily-salted hashes.

The report — what the shield has seen for your app, with the busiest addresses (hashed; we never store an address):

GET/v1/realtime/shield/report
ParamTypeDescription
daysintegerHow far back, 1–30 (default 1).
{ "verdicts": { "ok": 1840, "suspicious": 12, "bot": 57, "block": 3 },
  "busiest_addresses": [ { "scope": "stream-42", "address": "9f2c41aa07", "viewers": 22, "hits": 131 } ] }

What it is not: proof of a human. A real browser from real residential addresses passes. What it stops is the cheap attacks — scripts, headless browsers, one address posing as a crowd — which are the common ones. Chat spam (scam links, copy-paste raids, repeats) is best filtered in your client as messages arrive; OnAir does it in every viewer's tab.

Usage & billing

Live usage is charged from a prepaid balance as it happens; when the balance is empty, live credential minting and chat logins return 402 PAYMENT_REQUIRED. Test keys are metered and priced — so you can see what production would cost — and never charged.

GET/v1/realtime/usage?days=30

Per day, product and metric: quantity and cost, plus the live total, the price table and your free monthly allowances.

GET/v1/realtime/balance

Your prepaid balance and the last 50 ledger movements (top-ups, one usage line per app per day).

Realtime pricing

Pay as you go from the Free plan, with a free allowance every month for every app. Video minutes include bandwidth and are priced by quality — 720p, 1080p or 4K, chosen with quality on the token and billed at the higher of that and what the room actually published. Audio calls are their own, cheaper line. Live numbers: GET /v1/pricing → realtime.

Loading prices…

How that compares (their published prices, September 2026): LiveKit Cloud charges $0.0005 per participant-minute plus $0.12/GB bandwidth (≈ $0.0019 for a 720p minute); Agora HD video is $0.00399 per minute; Stream Chat is $0.09 per user on plans from $399/month; Agora Chat is $0.05 per user.

Upload & store

Files — videos, images, audio, documents — on the same key as everything else. The bytes never pass through the API: you reserve an object, PUT the file straight to storage on a signed URL, then confirm it. A multi-gigabyte video costs one small request here.

POST/v1/storage/uploads
ParamTypeDescription
namestringRequired — a filename, for your records.
content_typestringRequired — e.g. video/mp4. It is SIGNED into the upload URL; the PUT must send exactly this Content-Type.
size_bytesintegerRequired — what you are about to send, up to 5 GiB.
metadataobjectOptional — up to 20 string pairs of your own.
{ "object": { "id": "5f1c…", "status": "pending", … },
  "upload_url": "https://…r2.cloudflarestorage.com/…&X-Amz-Signature=…",
  "upload_method": "PUT", "upload_headers": { "Content-Type": "video/mp4" }, "expires_in": 900 }
curl -X PUT --data-binary @clip.mp4 -H "Content-Type: video/mp4" "$UPLOAD_URL"
POST/v1/storage/objects/{id}/complete

Reads the real size from storage and marks the object ready. Until then it cannot be read. Uploads never completed are removed after a day.

GET/v1/storage/objects
ParamTypeDescription
limitinteger1–200 (default 50).
cursorstring`next_cursor` from the previous page.
statusstringpending or ready.
DELETE/v1/storage/objects/{id}

Removes the bytes and the record; any URL already handed out stops working.

What may be stored: images, video (MP4, WebM, QuickTime, Matroska), audio, PDF, JSON, CSV, plain text, WebVTT captions and ZIP. HTML and SVG are refused — a file we serve back must never be a page or a script. Isolation is by key: another app's key gets 404 for your object, and a test key never sees live files. Test keys may hold 1 GB, and test objects are removed after 7 days.

Read & stream

GET/v1/storage/objects/{id}
ParamTypeDescription
expires_inintegerSeconds the URL lives, 60–604800 (default 3600).
downloadbooleantrue makes browsers save the file instead of playing it.

Returns the object with a signed url. Files are private — there is no public link, only one that expires, so mint a fresh URL when a user opens something. The URL answers HTTP Range requests, so a video plays and seeks straight from it:

const r = await fetch(`https://api.gossipbuzz.app/v1/storage/objects/${id}`, {
  headers: { 'X-API-Key': process.env.GOSSIP_KEY },   // on YOUR server
})
const { url } = await r.json()
// hand `url` to the client:  <video src={url} controls />

MP4 and WebM play as they are. Adaptive streaming (HLS renditions) is not part of Storage yet — for live video, use Live & calls.

Storage pricing

Delivery is included — there is no bandwidth or egress charge, however many times a file is watched. You pay for what is kept (metered daily), each upload and each signed URL issued; a video player seeking inside one URL is free.

Loading prices…

Realtime

Webhooks

Register HTTPS endpoints in the dashboard to receive events as they happen. Each webhook has its own signing secret (shown once). Every delivery includes a signature header you should verify before trusting the payload:

X-Gossip-Signature: sha256=HMAC_SHA256(secret, raw_body)

Verify it in your handler (Node example):

import crypto from 'node:crypto'

function verify(rawBody, header, secret) {
  const expected = 'sha256=' + crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex')
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(header))
}

Respond with 2xx within 5 seconds. Non-2xx responses are retried with exponential backoff. Rotate the secret any time — the previous one stops working immediately.

Event types

ParamTypeDescription
buzz.createdeventA buzz was published by a subscribed profile.
buzz.reactioneventSomeone reacted to a buzz.
buzz.commenteventA new comment was posted.
sip.createdeventA new moment was published.
follow.createdeventA profile gained a follower.
message.receivedeventAn inbound message was received.
otp.deliveredeventAn OTP/SMS was delivered.

Messaging

OTP

Send an in-app verification code, then verify what the user entered. The code is delivered to the recipient as a “Gossip OTP” push (no carrier SMS needed) and is never returned to you. … per code; available on every plan, including Free. Codes expire after 5 minutes.

1. Send

POST/v1/otp/send
ParamTypeDescription
tostringRecipient Gossip profile id or phone (E.164).
templatestringOptional template key.
curl -X POST https://api.gossipbuzz.app/v1/otp/send \
  -H "Authorization: Bearer gsk_live_••••••••" \
  -d '{"to":"+9779800000000"}'

{ "id": "ot_…", "status": "sent", "channel": "in_app", "cost_usd": 0.0001, "delivered": true }

2. Verify the code the user typed back to you (free):

POST/v1/otp/verify
ParamTypeDescription
tostringThe same recipient you sent to.
codestringThe 6-digit code the user entered.
curl -X POST https://api.gossipbuzz.app/v1/otp/verify \
  -H "Authorization: Bearer gsk_live_••••••••" \
  -d '{"to":"+9779800000000","code":"123456"}'

{ "verified": true }

Promo messages

Send an in-app promotional message, WhatsApp/Instagram-style. Choose the channel with via: profile lands in the recipient's profile chat as your profile name (creator/Instagram-style); account lands in their contact chat as your account/business name (WhatsApp-Business-style). Defaults by your account type (business → account, personal → profile). … per message; Pro.

Every recipient controls this: they can turn off promotional messages or block your account, and per-user rate caps + spam protection apply. If the recipient has opted out, the response is delivered: false with a reason.

POST/v1/promo/send
ParamTypeDescription
tostringRecipient Gossip profile id or phone.
textstringThe message body (required).
viastring"profile" or "account" (optional; defaults by account type).
curl -X POST https://api.gossipbuzz.app/v1/promo/send \
  -H "Authorization: Bearer gsk_live_••••••••" \
  -H "Content-Type: application/json" \
  -d '{ "to": "p_77f1…", "text": "20% off this week 🎉", "via": "profile" }'

{ "id": "pr_…", "status": "sent", "channel": "profile", "cost_usd": 0.01, "delivered": true }

AI

Generate text

Generate drafts, captions and replies. Pro plan + a configured AI provider (returns 402 without Pro, 503 if AI is unconfigured). … per call.

POST/v1/ai/generate
ParamTypeDescription
promptstringRequired — the instruction.
systemstringOptional system/style guidance.
max_tokensintegerOptional cap (default 300, max 2000).
curl -X POST https://api.gossipbuzz.app/v1/ai/generate \
  -H "Authorization: Bearer gsk_live_••••••••" \
  -H "Content-Type: application/json" \
  -d '{ "prompt": "Write a 1-line caption for a sunrise over Api Himal." }'

{ "text": "First light over the hills this morning 🌄", "model": "…", "cost_milli": 5000 }

Chat bot

Build a conversational bot — pass the message history and get the assistant's next reply. Keep your own conversation state and send the recent turns each call. Pro plan + a configured provider. … per call.

POST/v1/ai/chat
ParamTypeDescription
messagesarrayTurns so far: [{ role: "user"|"assistant"|"system", content }].
systemstringOptional persona / instructions.
max_tokensintegerReply cap (default 500, max 2000).
curl -X POST https://api.gossipbuzz.app/v1/ai/chat \
  -H "Authorization: Bearer gsk_live_••••••••" \
  -H "Content-Type: application/json" \
  -d '{ "system": "You are a helpful Gossip support bot.",
        "messages": [{ "role": "user", "content": "How do I create a key?" }] }'

{ "reply": "Open the dashboard → API & Keys → New app…", "role": "assistant",
  "model": "…", "cost_usd": 0.01 }

Moderate text

Classify text for unsafe content before you publish or store it. … per call. Pro plan required.

POST/v1/ai/moderate
ParamTypeDescription
textstringRequired — the text to classify.
{ "flagged": false, "categories": [], "model": "moderation" }

Ready to build?

Create your first key and hit the sandbox in minutes.

Open dashboard