Developers

creator api

Effective Date: v1, a rest api for publishing and managing gather drops with a creator api key

overview

the gather creator api lets a creator's ai agent create, publish and manage drops on the creator's behalf, over plain https and json. it wraps the exact publish pipeline the gather app uses, so a drop published here behaves exactly like a drop a human creates in the app: same validation, same tier caps, same claim mechanics, same supply math. one key acts as one creator, and every drop it publishes is tagged publishedVia: api_key for provenance.

the surface today is sixteen operations: reading your identity and live limits, uploading media (images and gif), creating and publishing drops in all six shapes (direct, pack and choice, each tiered or untiered, with 1-of-1 editions via choice), scheduling, event-gated drops with short-lived qr claim tokens, a reusable card-template library, and full management of what you published: list, read, edit, pause, unpause, delete, and pin a drop to your profile. everything is versioned under /v1; changes within v1 are additive only.

the api is server-side only. there is no cors, and a gth_ key must never ship inside a browser page or a mobile client. call it from your backend, a script, or an agent runtime.

status: early access

the creator api is rolling out gradually. key generation appears in the gather app (settings > ai access) as it is enabled per environment, and the production base url goes live with the public launch. where the api is deployed, publishing itself can still be switched off for an environment: a valid key then gets 503 publishing_disabled from POST /drops while uploads, reads and management keep working. GET /me is always the authoritative answer for what your key and your environment can do right now; do not infer availability from this page.

get a key

the human creator generates the key inside the gather app under settings > ai access. one active key at a time; revoke to rotate. keys cannot be minted or revoked through the api, by design, so a creator can cut off their integration at any moment. revoking takes effect within about a minute everywhere.

the key is shown once at creation and looks like gth_ followed by a long random string. store it like a password.

base url and auth

all endpoints live under a versioned base url. at public launch the base is https://api.gather.fan/v1; before then, use the environment url you were given with your access, of the form https://<api-id>.execute-api.us-east-1.amazonaws.com/v1.

every request except GET /openapi.json sends the key as a bearer token (the Bearer prefix is required) and speaks json:

export GATHER_API="https://<your-environment-base>/v1"
export GATHER_KEY="gth_xxxxxxxx"

curl -sS "$GATHER_API/me" -H "Authorization: Bearer $GATHER_KEY"

a working key returns your creator id, your verification state, and the live limits your drops must fit inside. every response carries an X-Request-Id header; include it whenever you report a problem.

quickstart

six calls from key to live drop:

# 1. confirm the key + read your live limits
curl -sS "$GATHER_API/me" -H "Authorization: Bearer $GATHER_KEY"

# 2. request a presigned upload url per image
curl -sS -X POST "$GATHER_API/uploads" \
  -H "Authorization: Bearer $GATHER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"files":[{"filename":"hero.png","purpose":"card"}]}'

# 3. put the bytes to uploadUrl (replay the returned headers verbatim)
curl -sS -X PUT "<uploadUrl>" \
  -H "Content-Type: image/png" \
  -H "Content-Disposition: attachment" \
  -H "Cache-Control: public, max-age=31536000, immutable" \
  --data-binary @hero.png

# 4. poll until the upload is valid
curl -sS "$GATHER_API/uploads/<uploadId>" -H "Authorization: Bearer $GATHER_KEY"

# 5. create + publish the drop (returns 202 accepted)
curl -sS -X POST "$GATHER_API/drops" \
  -H "Authorization: Bearer $GATHER_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: pub_9f2c7a1b6d4e8035c1af22e9b7d40e6a" \
  -d '{
    "name": "midnight run",
    "type": "direct",
    "perFanLimit": 1,
    "totalSupply": 250,
    "cards": [
      { "name": "night owl",  "rarity": "COMMON",    "imageUrl": "<publicUrl-1>" },
      { "name": "first light","rarity": "RARE",      "imageUrl": "<publicUrl-2>" },
      { "name": "the run",    "rarity": "LEGENDARY", "imageUrl": "<publicUrl-3>" }
    ]
  }'

# 6. poll until status is live or publish_failed
curl -sS "$GATHER_API/drops/<dropId>" -H "Authorization: Bearer $GATHER_KEY"

that is the whole flow. every card carries its own short name (up to 25 utf-8 bytes, it is minted on-chain). on a tiered drop, send totalSupply and the api splits editions across cards by rarity with the same algorithm the app uses; rarer means fewer, every card gets at least one copy, and the supplies always sum exactly to the pool.

what you can do

the sixteen operations, grouped:

  • identity and limits: GET /me, your caps, headroom and per-environment capabilities. read it first, cache it briefly, never hardcode the numbers.
  • media: POST /uploads (batched presigned urls, images and gif) and GET /uploads/{uploadId} (the validation verdict).
  • publishing: POST /drops, the one rationed call: direct, pack or choice, tiered or untiered, scheduled or immediate (end dates up to 365 days out), optionally event-gated, with idempotent retries via Idempotency-Key.
  • card templates: GET /card-templates and POST /card-templates, a reusable library of card art you can publish from without re-uploading.
  • management: GET /drops, GET /drops/{dropId}, PATCH /drops/{dropId} (name, description, cover, schedule), pause, unpause and delete, plus GET /me/pinned-drop, PUT /me/pinned-drop and DELETE /me/pinned-drop for your profile's pinned drop.
  • live events: GET /drops/{dropId}/qr-token, a short-lived qr claim credential for event-gated drops.

the contract

the machine-readable contract is served by the api itself, without a key, at GET /openapi.json. generate clients from it. unknown fields are rejected with 400 invalid_request, never silently dropped, so a request that validates today keeps meaning the same thing tomorrow.

errors arrive in one stable envelope with a machine-readable code and, where useful, a details object naming the exact rule. retry only 429 and 503 temporarily_unavailable, always with the same Idempotency-Key and after the Retry-After. every other code means fix something first. pace yourself at roughly one request per second.

changelog

1.1 (2026-08): the management half. drop editing, pause, unpause, delete and profile pinning; the card-template library; choice drops with per-card supplies and 1-of-1 editions; untiered cards; scheduling with end dates up to 365 days; event gates with qr claim tokens. card names became required (25 utf-8 bytes) and automatic card naming was removed.

1.0 (2026-07): initial release. seven endpoints, image and gif media, direct and pack drops, both supply modes, idempotent publishing, per-key daily caps, and the stuck-drop sweeper.