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/v1One 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):
| Param | Type | Description |
|---|---|---|
| OTP per recipient | 3 / 10 min · 15 / day | Prevents code-bombing one person. |
| Promo per recipient | 1 / day | Don't spam the same person. |
| Promo per sender | 1,000 / day | Total 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."
}
}| Param | Type | Description |
|---|---|---|
| 200 | OK | Request succeeded. |
| 401 | Unauthorized | Missing or invalid API key. |
| 404 | Not found | The resource does not exist. |
| 429 | Rate limited | Too many requests for your tier. |
| 500 | Server error | Something went wrong on our end. |
Pagination
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.
{
"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.
| Param | Type | Description |
|---|---|---|
| author | string | Filter by author username (optional). |
| limit | integer | Page size, 1–100 (default 20). |
| cursor | string | Pagination cursor from next_cursor. |
{
"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.
| Param | Type | Description |
|---|---|---|
| author | string | Filter by author username (optional). |
| limit | integer | Page 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.
| Param | Type | Description |
|---|---|---|
| kind | string | Filter by "photo" or "video" (optional). |
| limit | integer | Page 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
Search public profiles (by username / name) and buzzes (by text). Returns both unless you scope it with type.
| Param | Type | Description |
|---|---|---|
| q | string | The search query (required, 1–100 chars). |
| type | string | Limit to "profiles" or "buzzes" (default: both). |
| limit | integer | Max 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.
[
{ "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).
[
{ "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.
[
{ "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.
[
{ "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.
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.
| Param | Type | Description |
|---|---|---|
| kind | string | Required — "photo" or "video". |
| url | string | Required — the asset URL. |
| thumbnail_url | string | Optional preview image. |
| title | string | Optional title. |
| width, height | integer | Optional pixel dimensions. |
| tags | array | Optional string tags. |
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:
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": "…" }| Param | Type | Description |
|---|---|---|
| gsk_live_… / gsk_test_… | secret key | Server only. Mints credentials, reads usage. Test keys are metered and priced but never charged. |
| pk_live_… / pk_test_… | publishable key | Safe in a client. Only used for the bot & spam shield. |
| shield_secret | string | Server only. Verifies shield tickets with no call back to us. |
Change settings with PATCH /v1/realtime/app:
| Param | Type | Description |
|---|---|---|
| mam | boolean | Keep chat history (message archive). Default false — right for stream chat. New credentials move to the matching chat host. |
| products | string[] | Any of chat, live, calls. |
| max_room_size | integer | 2–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.
| Param | Type | Description |
|---|---|---|
| user_id | string | Required — YOUR user id. |
| name | string | Nickname shown in rooms. |
| ttl_seconds | integer | 60–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": "…" }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.
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.
| Param | Type | Description |
|---|---|---|
| room | string | Required — your room name (letters, digits, - and _). |
| identity | string | Required — YOUR user id. |
| kind | string | live (a broadcast) or call (everyone may publish). Default live. |
| publish | boolean | For live: may this user broadcast? Viewers default to false. |
| ttl_seconds | integer | 60–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.
| Param | Type | Description |
|---|---|---|
| X-Publishable-Key | header | Required — pk_live_… or pk_test_…. |
| subject | string | Required — what is being counted, e.g. a device key. |
| scope | string | Required — what it is counted against, e.g. a stream id. |
{ "ticket": "<payload>.<signature>", "verdict": "ok", "reason": "", "expires_at": 1790000000 }| Param | Type | Description |
|---|---|---|
| ok | verdict | Count it. |
| suspicious | verdict | One address presenting more than 6 viewers on this scope today — do not count it. |
| bot | verdict | Automation by its own user agent (curl, headless browsers, scripts). |
| block | verdict | More than 20 from one address — refuse what it was for. |
| 429 | status | Over 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):
| Param | Type | Description |
|---|---|---|
| days | integer | How 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.
Per day, product and metric: quantity and cost, plus the live total, the price table and your free monthly allowances.
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.
| Param | Type | Description |
|---|---|---|
| name | string | Required — a filename, for your records. |
| content_type | string | Required — e.g. video/mp4. It is SIGNED into the upload URL; the PUT must send exactly this Content-Type. |
| size_bytes | integer | Required — what you are about to send, up to 5 GiB. |
| metadata | object | Optional — 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"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.
| Param | Type | Description |
|---|---|---|
| limit | integer | 1–200 (default 50). |
| cursor | string | `next_cursor` from the previous page. |
| status | string | pending or ready. |
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
| Param | Type | Description |
|---|---|---|
| expires_in | integer | Seconds the URL lives, 60–604800 (default 3600). |
| download | boolean | true 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
| Param | Type | Description |
|---|---|---|
| buzz.created | event | A buzz was published by a subscribed profile. |
| buzz.reaction | event | Someone reacted to a buzz. |
| buzz.comment | event | A new comment was posted. |
| sip.created | event | A new moment was published. |
| follow.created | event | A profile gained a follower. |
| message.received | event | An inbound message was received. |
| otp.delivered | event | An 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
| Param | Type | Description |
|---|---|---|
| to | string | Recipient Gossip profile id or phone (E.164). |
| template | string | Optional 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):
| Param | Type | Description |
|---|---|---|
| to | string | The same recipient you sent to. |
| code | string | The 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.
| Param | Type | Description |
|---|---|---|
| to | string | Recipient Gossip profile id or phone. |
| text | string | The message body (required). |
| via | string | "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.
| Param | Type | Description |
|---|---|---|
| prompt | string | Required — the instruction. |
| system | string | Optional system/style guidance. |
| max_tokens | integer | Optional 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.
| Param | Type | Description |
|---|---|---|
| messages | array | Turns so far: [{ role: "user"|"assistant"|"system", content }]. |
| system | string | Optional persona / instructions. |
| max_tokens | integer | Reply 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.
| Param | Type | Description |
|---|---|---|
| text | string | Required — the text to classify. |
{ "flagged": false, "categories": [], "model": "moderation" }