Partner Program

Partner API

White-label OverSkill's app-generation engine inside your own product. Your editor is the surface; OverSkill is the headless engine underneath. Your platform holds one partner key server-side and provisions an isolated OverSkill workspace per creator; each creator's builds run under their own key, carry their own context, and are branded as yours.

How it works

The full lifecycle is four partner-scoped calls. The partner key never reaches the browser — it only provisions creators server-side.

partner key ──▶ POST /api/v1/partner/teams                       → creator team + creator key
creator key ──▶ POST /api/v1/generation_queue                    → job (context + brand + embed applied)
             ── GET  …/:id/messages · GET …/:id/stream · webhook  → live chat pane + push
             ── (build) → preview_url                             → iframe in your editor
creator key ──▶ POST /api/v1/managed_apps/:id/deploy             → production_url + embed handoff

Authentication

Every partner call authenticates with an API key in the X-API-Key header:

curl -H "X-API-Key: os_your_key_here" \
  https://staging.overskill.com/api/v1/managed_apps

Scopes

Partner flows need apps:write (provision, deploy) and generation:queue (generate) — both are granted by read_write and full_access. read_only has neither.

Scope Grants
read_onlyapps:read, users:read, analytics:read, webhooks:read
read_writeread_only + apps:write, users:write, generation:queue
full_accessread_write + apps:delete, users:delete, webhooks:write

Rate limits

Current enforced limits per API key:

Operation Limit
Queue generation20 / hour
Reads (GET)300 / minute
Writes (POST/PATCH/DELETE)60 / minute
Deploy10 / hour

A 429 response includes a retry_after (seconds). Exceeding a limit never fails a build already in flight.

POSTProvision a creator workspace

Map each of your creators to their own OverSkill team and API key. Call this with the partner key; store the returned creator key server-side.

Endpoint

POST https://staging.overskill.com/api/v1/partner/teams   ·   requires apps:write

Request body

Parameter Type Description
namestring · requiredThe creator team's name.
user_emailstringAn existing OverSkill user to add as team admin. If provided but not found, the team is still created and a warning is returned.
generate_api_keyboolean · default trueMint a scoped key for this creator team. Pass false to skip.
api_key_scopestring · default full_accessScope of the minted key.

Response (201 Created)

{
  "team": { "id": 188, "name": "Priya's Baking Studio",
            "subscription_tier": "free", "credit_tier": "tier_500",
            "created_at": "2026-08-22T18:04:00Z" },
  "user_added": true,
  "warning": null,
  "api_key": { "key": "os_...", "name": "...", "scope": "full_access",
               "note": "Save this key now - it cannot be retrieved later" }
}

POSTQueue a generation

One call injects the creator's context, brands the app, opts it into embedding, and starts the build. Call it with the creator key (needs generation:queue + builder access).

Endpoint

POST https://staging.overskill.com/api/v1/generation_queue

Request body

Parameter Type Description
promptstring · requiredWhat to build (or the next edit).
app_idstringOmit to create a new app; include (team-scoped id) to iterate on an existing one.
partner_contextstring or objectThe creator's world (courses, communities, calls, content, audience). ≤ 48 KB — larger is truncated, never blocks. Objects are rendered as a JSON block. Persisted on the app and reused across turns; injected as a bounded, cached layer framed as data, not instructions.
partner_attributionstring or objectWhite-label badge. Object keys: partner, display_name, powered_by, show_attribution (defaults powered_by:"OverSkill", show_attribution:true). ≤ 2 KB.
partner_frame_ancestorsstring or arrayOrigins allowed to iframe the preview (comma/space/newline-separated, or an array). Each is sanitized; unusable entries are dropped, never blocks the build.
callback_urlstring (URL)Webhook target for terminal events (see Webhooks). http:// accepted in dev only.
metadataobjectYour correlation data, echoed back on webhooks. ≤ 4 KB serialized or it is dropped.
ai_model, thinking_effortstringOptional model + reasoning-effort overrides (low|medium|high|max|xhigh).

Response (202 Accepted)

{
  "job_id": "4ebc...",
  "app_id": "OJzZVJ",
  "message_id": 278,
  "status": "queued",
  "estimated_time_seconds": 45,
  "status_url": ".../generation_queue/4ebc...",
  "app_url": ".../account/apps/OJzZVJ/edit",
  "partner_context":        { "applied": true, "bytes": 1454, "truncated": false },
  "partner_attribution":    { "applied": true, "partner": "tagmango", "show_attribution": true },
  "partner_frame_ancestors":{ "applied": true, "origins": ["https://app.tagmango.com"] }
}

Each partner_* echo object is null unless that param was applied on this request. Every response also carries a next_steps hint object.

POSTFork a template (remix)

Start a build from a template or an existing app instead of a blank prompt. Requires apps:write. This is clone-only (no credits spent): it copies files, entity schema, custom endpoints, non-secret env vars, roles and (when the source opts in) public seed data, then deploys a preview — it does not run the AI. Iterate afterward with POST /generation_queue using the new app_id.

POST https://staging.overskill.com/api/v1/managed_apps/remix
{
  "source_app_id": "OJzZVJ",          // any remixable app — a template or your own
  "custom_name": "Priya's Portal",     // optional; defaults to "<name> (Remix)"
  "include_messages": "none"           // optional: "none" (default) | "all", clamped to the source's ceiling
}
// 202 Accepted
{
  "app_id": "Ab12Cd",
  "source_app_id": "OJzZVJ",
  "name": "Priya's Portal",
  "status": "remixing",
  "status_url": ".../managed_apps/Ab12Cd"
}

status is remixing until the clone finishes and a preview deploys, then generated — poll status_url to learn when it's ready. The source must be remixable (its creator's remix toggle on and the app built); otherwise the call returns 422 with a reason.

GETWatch the build

Three ways to follow a build, all team-scoped (apps:read):

  • Poll: GET /generation_queue/:id{ status, progress, message, app, started_at, completed_at }. status ∈ queued · processing · completed · failed · cancelled.
  • Chat-left pane: GET /generation_queue/:id/messages (?limit= 1–200, default 50) → a secret-redacted transcript with a flow tool timeline to render a faithful editor pane.
  • Stream (SSE): GET /generation_queue/:id/streamstatus then progress/completed/failed events (2 s cadence, 5 min timeout).
  • Cancel: DELETE /generation_queue/:id (apps:write) → { cancelled: true, job_id }.

Messages / flow shape

{ "messages": [
    { "role": "user", "content": "..." },
    { "role": "assistant", "status": "generating", "thinking_status": "Building...",
      "content": "Design Direction: ...",
      "flow": [ { "type": "message", "content": "Planning screens..." },
                { "type": "tools", "status": "complete",
                  "tools": [ { "name": "edit-file", "status": "complete" },
                             { "name": "os-search",  "status": "error" } ] } ] } ] }

POSTSteer & control a build

Beyond cancel, a running build can be paused, resumed, and steered — the same controls the OverSkill editor has, so your editor can offer them too. All require apps:write and act on the app's current generation.

  • Pause: POST /managed_apps/:id/pause → the build pauses after its current step. Returns { status: "pause_requested", pause_requested_at }.
  • Resume: POST /managed_apps/:id/resume → continues a paused build from where it left off. Returns { status: "resumed" }; 422 if the build isn't paused.
  • Follow up while running: POST /managed_apps/:id/follow_up { message, mode }mode: "queue" (default) runs the message as its own turn after the current build finishes; mode: "steer" injects it into the running build's next step so the model adapts mid-flight. Requires an in-flight generation (otherwise 422). Returns { queued_message_id, delivery_mode, position, queue_length }.

Pause/resume and mid-flight steering are gated features; where a control isn't enabled for your account the endpoint returns 403 (steer transparently falls back to queue). Ask your OverSkill contact to enable them for your partner account.

POSTPreview & deploy

Preview: once the build produces a dist/ bundle the app has a preview_url (a Cloudflare host). It is iframe-embeddable by the origins you passed in partner_frame_ancestors.

Deploy

POST https://staging.overskill.com/api/v1/managed_apps/:id/deploy   ·   requires apps:write · free

Refused with 422 (reason, fix_url) unless the app is deployable — i.e. not a draft and it has a built dist/ bundle.

Response (202 Accepted)

{
  "deployment_id": 129,
  "status": "queued",
  "message": "Production deployment queued",
  "white_label": { "display_name": "TagMango", "powered_by": "OverSkill",
                   "show_attribution": true },
  "embed": {
    "preview_url": "https://preview-ojzzvj.overskill.app",
    "production_url": "https://ojzzvj.overskill.app",
    "frame_ancestors": ["https://app.tagmango.com"],
    "embeddable": true,
    "iframe_snippet": "<iframe src=\"...\" title=\"...\"></iframe>"
  }
}

The same embed (and white_label) block is also on GET /managed_apps/:id?detailed=true — the drop-in handoff for surfacing the finished app back inside your platform. embed is null until the app has a live URL; embeddable is true only when frame_ancestors is non-empty.

Webhooks

Set callback_url on generate to receive a signed POST at each terminal state — instead of polling.

Event When
app.generation.completedBuild finished; includes credits_used + tokens_used.
app.generation.failedError / retries exhausted.
app.generation.blockedBusiness block (e.g. insufficient credits); adds block_type, balance, required_credits so you don't auto-retry.

Payload

POST <callback_url>
X-OverSkill-Signature: sha256=<hmac>

{ "event": "app.generation.completed", "app_id": "OJzZVJ", "app_name": "...",
  "status": "published",
  "urls": { "preview": "...", "production": "...", "editor": "..." },
  "generation": { "message_id": 278, "started_at": "...", "completed_at": "..." },
  "metadata": { "your_correlation_id": "..." },
  "credits_used": 12, "tokens_used": { "input": 40311, "output": 8822 } }

Verify the signature: HMAC-SHA256 over the raw request body, key = OVERSKILL_PLATFORM_TOKEN; reject on mismatch. Delivery retries up to 3× with backoff. http:// callback URLs are accepted in OverSkill dev only.

SSO handoff (optional)

An alternative identity path lets a creator land in OverSkill signed-in from your platform, without a separate signup:

GET https://staging.overskill.com/auth/sso?token=<JWT>

HS256, signed with your partner secret. Required claims: source (your partner slug), email, aud = "overskill-sso", exp, iat, and a unique jti (replay-protected — a token without jti, or a reused one, is rejected). On success OverSkill find-or-creates the user, ensures a team, and signs them in. New partner sources are onboarded server-side (secret env var per partner).

Example integration

fakeMango is the reference partner integration — a small Next.js app that drives this exact flow end to end (auth → provision → inject context → generate → watch → preview → deploy) against the real partner API, with a built-in demo engine so it runs before you have a key. Clone it, set your partner key + API base, and the header flips from Demo engine to Live OverSkill.

Clone & run

git clone <example-repo-url> overskill-partner-example
cd overskill-partner-example
cp .env.example .env.local
npm install && npm run dev   # starts on the demo engine

Minimal .env.local

Leave these blank to run against the built-in demo engine. Fill them in — at minimum the API base + your partner key — and the app switches to Live OverSkill.

OVERSKILL_API_BASE=https://staging.overskill.com/api/v1          # OverSkill API host + /api/v1
OVERSKILL_PARTNER_API_KEY=os_...                 # your partner key (server-side only)
OVERSKILL_PARTNER_SLUG=yourbrand                 # your partner slug
OVERSKILL_PARTNER_EMBED_ORIGINS=https://*.yourbrand.com   # who may iframe previews
OVERSKILL_PUBLIC_BASE=https://overskill.app      # host for preview/production URLs
OVERSKILL_WEBHOOK_SECRET=                         # = OverSkill's OVERSKILL_PLATFORM_TOKEN (verifies webhooks)
OVERSKILL_MOCK=0                                  # 1 = force demo engine even with a key

The partner key is used server-side only — never ship it to the browser. Ask your OverSkill partner contact for access to the example repo and a partner key.