An API that can do everything the app can.
Scoped keys, idempotent writes, cursor pagination, signed webhooks and a generated OpenAPI 3.1 document — described once in a typed route table, so the reference you read, the validation that rejects your request, the MCP tools an agent calls and three automation-platform connectors all come from the same source.
- No enterprise gate
- Idempotency-Key on every write
- HMAC-signed webhooks
At a glance
What you are working with
Three ways in
Pick the one that matches what you are building
The REST API
A scoped gg_live_ key and a bearer header. Import the OpenAPI document at gongongai.com/api/openapi and generate a client, or call it with curl.
The MCP server
Eleven tools at /api/mcp. Claude and ChatGPT connect through an OAuth 2.1 consent screen — no pasted key. Local clients that read an mcp.json can send an API key instead. How it connects.
Automation platforms
n8n, Make and Zapier connect today the generic way — an HTTP request node with your key, and a webhook trigger for events. Purpose-built connector packages exist and are described below; none is in a vendor directory yet.
Quickstart
Schedule a cross-platform post in one call
curl -X POST https://gongongai.com/api/v1/posts \
-H "Authorization: Bearer $GONGONG_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: launch-note-2026-09-05" \
-d '{
"content": "The calendar now publishes itself.",
"targets": [
{ "socialAccountId": "cml3x9k2b0004s7q1f8w2h6ta" },
{ "socialAccountId": "cml3x9k2b0007s7q1a1n4d9pe" }
],
"schedule": { "mode": "BEST_TIME" }
}'// 202 Accepted. A 40-minute podcast is not a request/response,
// so the run is queued and the response carries the job, not the angles.
const response = await fetch('https://gongongai.com/api/v1/ai/repurpose', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.GONGONG_API_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': crypto.randomUUID(),
},
body: JSON.stringify({
source: { type: 'ARTICLE', url: 'https://example.com/blog/how-we-ship' },
platforms: ['X', 'LINKEDIN', 'INSTAGRAM'],
angles: 3,
saveAsDrafts: true,
}),
});
const { job } = await response.json();
// Then either poll GET /v1/ai/jobs/{job.id}, or — better — subscribe to
// the ai.job.completed webhook and never poll at all.Authentication
Hashed, workspace-scoped API keys
Scopes
- posts:read
- posts:write
- media:read
- media:write
- accounts:read
- accounts:write
- analytics:read
- inbox:read
- inbox:write
- ai:generate
- webhooks:manage
A key carries only the scopes you grant it. A call missing one is rejected with forbidden before any work happens. The same vocabulary is what an OAuth connector asks for on the consent screen — there is no parallel permission system for agents.
Rules that matter
- Create keys in Automation → API keys. The plaintext value is shown once; only a hash is stored.
- Keys are workspace-scoped — one key can never read another workspace.
- A cross-tenant identifier returns 404, never 403; existence is not leaked.
- Each key has its own rate limit and last-used timestamp; GET /v1/usage reports the calls, credits and published posts for the whole organisation.
- Revocation takes effect on the next request, not the next hour.
Reference
Every endpoint, grouped
Posts
Create, schedule, publish and retry cross-platform posts.
| Method | Path | What it does | Scopes |
|---|---|---|---|
| post | /v1/postsAccepts Idempotency-Key | Create a post | posts:write |
| get | /v1/posts | List posts | posts:read |
| get | /v1/posts/{id} | Get a post | posts:read |
| patch | /v1/posts/{id}Accepts Idempotency-Key | Update a post | posts:write |
| delete | /v1/posts/{id}Accepts Idempotency-Key | Cancel a post | posts:write |
| post | /v1/posts/{id}/scheduleAccepts Idempotency-Key | Schedule a post | posts:write |
| post | /v1/posts/{id}/publishAccepts Idempotency-Key | Publish a post now | posts:write |
| post | /v1/posts/{id}/retryAccepts Idempotency-Key | Retry failed targets | posts:write |
Accounts
Read connected social accounts and disconnect them.
| Method | Path | What it does | Scopes |
|---|---|---|---|
| get | /v1/accounts | List connected accounts | accounts:read |
| post | /v1/accounts/{id}/disconnectAccepts Idempotency-Key | Disconnect an account | accounts:write |
Media
Presigned direct uploads and the workspace media library.
| Method | Path | What it does | Scopes |
|---|---|---|---|
| post | /v1/media/upload-urlAccepts Idempotency-Key | Create a presigned upload URL | media:write |
| post | /v1/media/{id}/completeAccepts Idempotency-Key | Finish an upload | media:write |
| get | /v1/media | List media assets | media:read |
AI
Text, repurposing, image and video generation plus job polling.
| Method | Path | What it does | Scopes |
|---|---|---|---|
| post | /v1/ai/generateAccepts Idempotency-Key | Generate post drafts | ai:generate |
| post | /v1/ai/repurposeAccepts Idempotency-Key | Repurpose a source | ai:generate |
| post | /v1/ai/imageAccepts Idempotency-Key | Generate images | ai:generate, media:write |
| post | /v1/ai/videoAccepts Idempotency-Key | Generate a video | ai:generate, media:write |
| get | /v1/ai/jobs/{id} | Get an AI job | ai:generate |
Analytics
Cross-account rollups, per-post drill-downs and best-time heatmaps.
| Method | Path | What it does | Scopes |
|---|---|---|---|
| get | /v1/analytics/overview | Analytics overview | analytics:read |
| get | /v1/analytics/posts/{id} | Per-post analytics | analytics:read |
| get | /v1/analytics/best-times | Best posting times | analytics:read |
Inbox
Unified comments, mentions, reviews and DMs, and replies to them.
| Method | Path | What it does | Scopes |
|---|---|---|---|
| get | /v1/inbox | List engagements | inbox:read |
| post | /v1/inbox/{id}/replyAccepts Idempotency-Key | Reply to an engagement | inbox:write |
Scheduling
Queues, rotation slots and next-free-slot resolution.
| Method | Path | What it does | Scopes |
|---|---|---|---|
| get | /v1/queues | List queues | posts:read |
| post | /v1/schedule/next-slot | Resolve the next free slot | posts:read |
Workspaces
Workspaces the calling API key can reach.
| Method | Path | What it does | Scopes |
|---|---|---|---|
| get | /v1/workspaces | List workspaces | accounts:read |
Usage
Plan entitlements, AI credit consumption and warning thresholds.
| Method | Path | What it does | Scopes |
|---|---|---|---|
| get | /v1/usage | Get plan usage | analytics:read |
Webhooks
Register and remove signed event subscriptions, as a connector does unattended.
| Method | Path | What it does | Scopes |
|---|---|---|---|
| get | /v1/webhooks | List webhook subscriptions | webhooks:manage |
| post | /v1/webhooksAccepts Idempotency-Key | Register a webhook subscription | webhooks:manage |
| delete | /v1/webhooks/{id}Accepts Idempotency-Key | Remove a webhook subscription | webhooks:manage |
The document, not a copy of it
Reliability
Idempotency, pagination and rate limits
Idempotency
Send Idempotency-Key on any write. The first response is stored and replayed for 24 hours, so a retry after a timeout cannot double-post. Separately, each post-and-account pair carries one stable key for the whole publish attempt. Mastodon accepts it as a platform header and de-duplicates on its side; everywhere else it is the correlation id our own pipeline de-duplicates on, so an ambiguous timeout resolves to one post rather than two.
Pagination
List routes are cursor-paginated. Pass the returned cursor back as cursor; an absent cursor means the end, not an empty page.
Rate limits
A key runs at 120 requests a minute on the trial and up to 3,000 on Agency; you can set a lower ceiling on any individual key. Your organisation has a shared ceiling of twice the per-key number across every key it holds, so a second key is not a second allowance. AI, ingestion and upload endpoints spend a per-workspace budget on top. A throttled call returns 429 rate_limited with Retry-After rather than a bare rejection. The counter is keyed on the caller, not the protocol: one API key used over both REST and MCP spends a single bucket, so switching protocol cannot double its quota. An OAuth connector is a different caller — keyed on the grant — and carries its own budget alongside your keys.
{
"error": {
"code": "rate_limited",
"message": "Too many requests for this API key.",
"details": { "retryAfterSec": 12, "limit": 120, "windowSec": 60 },
"requestId": "req_9f2c1e"
}
}Error codes
- bad_requestHTTP 400
- unauthorizedHTTP 401
- forbiddenHTTP 403
- not_foundHTTP 404
- conflictHTTP 409
- rate_limitedHTTP 429
- unprocessableHTTP 422
- payment_requiredHTTP 402
- internalHTTP 500
- not_implementedHTTP 501
Webhooks
Events you can build on
- post.publishedA target went live on its platform.
- post.failedA target exhausted its retries or hit a permanent error.
- comment.receivedA new comment, reply, mention or review landed in the inbox.
- dm.receivedA new direct message landed in the inbox.
- approval.requestedA post was sent for review.
- analytics.weekly_readyThe weekly analytics rollup and learnings finished.
- account.disconnectedA social account lost its credentials or was disconnected.
- ai.job.completedA queued generation job reached a terminal state.
import { createHmac, timingSafeEqual } from 'node:crypto';
// The raw request bytes, never the re-serialized JSON: JSON.stringify of a
// parsed body produces different bytes and the digest will never match.
export function verify(rawBody: string, header: string, secret: string) {
const parts = Object.fromEntries(
header.split(',').map((pair) => pair.split('=', 2) as [string, string]),
);
const age = Math.abs(Math.floor(Date.now() / 1000) - Number(parts.t));
if (!Number.isFinite(age) || age > 300) return false; // replay window
const expected = createHmac('sha256', secret)
.update(`${parts.t}.${rawBody}`)
.digest('hex');
return timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
}How the signature is built
- Every delivery carries x-gongong-signature: t=<unix>,v1=<hex> — an HMAC-SHA256 over "<t>.<rawBody>", the exact bytes we sent.
- Anything older than 300 seconds is a replay and should be rejected.
- Parse the header as a list and accept a match against any v1= value. Rotating a secret today switches it immediately — deploy the new secret to your receiver before you roll it, or deliveries signed with the old one will fail verification.
- Our own verifier compares every candidate with no early return, so the comparison time does not leak how much of a forged digest was right.
- Configure endpoints in Automation → Webhooks, or from /v1/webhooks if your integration subscribes unattended.
Fire a signed test before you write a handler
Automation platforms
n8n, Zapier and Make — what is real, and what is not listed yet
Status, stated plainly
n8n
Beta, unpublishedA community-node package: an action node covering 13 operations across posts, AI, the inbox, accounts and analytics, plus a trigger node that registers its own webhook when you activate a workflow and removes it when you switch it off. The trigger needs an n8n reachable at a public https address; a self-hosted install can poll on a Schedule Trigger instead.
Today: Build it from a checkout of integrations/n8n and npm link it into ~/.n8n/custom. Both nodes appear in the node panel after a restart. 38 tests, no network needed.
Not yet published to npm or listed in n8n’s community-node index.
Zapier
Beta, unpublishedA Zapier CLI app: five REST-hook triggers (post published, post failed, new comment or mention, account disconnected, AI job completed), seven actions and six searches, with the same signature check as the n8n trigger before a delivery becomes a Zap run.
Today: Run it from integrations/zapier against your own Zapier developer account with zapier push, and it is private to that account.
Not submitted to Zapier’s app review, so it is not in the Zap directory.
Make
Beta, unpublishedA Make custom-app definition — a connection, thirteen action and search modules and five instant triggers, as JSON that Make interprets server-side. Every field is mappable from an earlier module, and each module declares what it hands the next one.
Today: Import integrations/make/src with the Make Apps Editor or its VS Code extension into your own Make account.
Not submitted for a Make public listing.
One difference worth knowing before you choose
The n8n and Zapier triggers verify the full HMAC on every delivery before a workflow runs. The Make app cannot: Make's webhook expressions expose only the parsed body, and an HMAC recomputed from re-serialized JSON never matches the digest over the original bytes. That app rejects any delivery arriving without a signature header and otherwise relies on Make's own model — a long, random, per-scenario URL that is never published. If cryptographic verification matters for a given workflow, use n8n or Zapier for it.
Get a key before you write a line of code
The trial includes the full API and MCP surface for fourteen days, with no card and no sales call.
No credit card · Cancel anytime · Every plan includes the API and the MCP server