Pikes API Reference

Base URL: https://pikes.ai

There are two ways into Pikes programmatically, and they run the same tools over the same account:

Use it for Auth
MCP serverPOST/mcp Agent clients (Claude, ChatGPT connectors, anything speaking MCP) OAuth 2.1, or an API key as a bearer token
REST tool callsPOST/mcp/tools/:toolName Your own orchestration layer; no MCP client needed API key
Product-shot endpointsPOST/api/product-shot One-shot product photography from a file upload API key

Every call runs as a Pikes user and spends that user's credits. There is no team- or org-level credential today; see Workspace scoping before you plan around it.

These facts and the tool catalogue below are written by server/__tests__/api-surface-probe.js from a live server — see Verifying this document.


Authentication#

OAuth 2.1 (MCP clients)#

Standard discovery — point a compliant MCP client at https://pikes.ai/mcp and it will find everything itself:

Endpoint Purpose
POST/mcp/oauth/register Dynamic client registration (RFC 7591)
POST/mcp/oauth/authorize Authorization code
POST/mcp/oauth/token Token exchange / refresh
POST/mcp/oauth/revoke Revocation

PKCE is required (S256). Grants: authorization_code, refresh_token. Scopes: generate_image, edit_image, expand_image, read_images.

API keys (headless)#

Keys look like psk_…, are stored only as a SHA-256 hash, and are accepted two ways:

text
Authorization: Bearer psk_…
x-api-key: psk_…

Create one in the app under Settings → API (or Settings → Claude / MCP for a key you'll paste into an MCP client), or over the API. Key management is authenticated by the user's session JWT, never by a key — a key cannot mint or revoke keys.

bash
# Create
curl -X POST https://pikes.ai/api/keys \
  -H "Authorization: Bearer <SUPABASE_SESSION_JWT>" \
  -H "Content-Type: application/json" \
  -d '{"name": "orchestrator"}'

# → { "success": true, "key": { "id": "...", "name": "orchestrator",
#     "keyPrefix": "psk_754fed7b...", "rawKey": "psk_…", "createdAt": "..." } }

rawKey is returned once. Store it then; it cannot be read back.

bash
curl https://pikes.ai/api/keys -H "Authorization: Bearer <JWT>"          # list (metadata only)
curl -X DELETE https://pikes.ai/api/keys/<keyId> -H "Authorization: Bearer <JWT>"   # revoke

Listing returns id, name, key_prefix, created_at, last_used_at, revoked — never key material. Revoking a key you don't own returns 404.

Scope difference worth knowing: API-key calls carry generate_image, edit_image, expand_image. OAuth additionally carries read_images.


REST tool calls#

POST/mcp/tools/:toolName — the whole tool catalogue as ordinary HTTP. The body is the tool's arguments; no JSON-RPC envelope.

bash
curl -X POST https://pikes.ai/mcp/tools/generate_image \
  -H "x-api-key: psk_…" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Amber supplement bottle on warm marble, soft window light",
    "aspectRatio": "4:5",
    "model": "consistency_pro",
    "resolution": "2K"
  }'

Responses come back in MCP content-block form. The payload is JSON encoded inside text:

json
{ "content": [ { "type": "text", "text": "{\"success\":true,\"images\":[…]}" } ] }

Tool-level failures return HTTP 200 with "isError": true and the reason in the same block — check isError, not just the status code:

json
{ "content": [ { "type": "text", "text": "{\"success\":false,\"error\":\"Could not fetch account info\"}" } ], "isError": true }

Missing or bad credentials return 401:

json
{ "error": "Unauthorized",
  "message": "OAuth token or API key required. Authorize at /mcp/oauth/authorize or use x-api-key header" }

MCP transport#

Discovery is open on purpose: initialize and tools/list answer without credentials, so a client can inspect the catalogue before anyone authorizes it. Executing a tool always needs one.

bash
curl -X POST https://pikes.ai/mcp \
  -H "Authorization: Bearer psk_…" -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

Claude Code, for reference:

bash
claude mcp add --transport http pikes-ai https://pikes.ai/mcp

Tool catalogue#

29 tools, as reported by tools/list.

Image and video

Tool Description
generate_image Generate a new image from scratch using a text prompt. Use this when the user wants to create a completely new image without any input images.
edit_image Edit or modify existing images based on instructions. Supports single image editing AND multi-image combining (e.g. placing a product into a scene). For single image: pass imageUrl. For combining images: pass imageUrls — first image is the product/main subject, last image is the scene/context, middle images are style references. Provide exactly one of imageUrl or imageUrls. This replaces the old remix_images tool.
expand_image Extend or outpaint an image's canvas to a new aspect ratio or size. The expansion is content-aware but NOT steerable: the underlying model (Ideogram Reframe) fills the new canvas from the source image alone — there is no directional control and no prompt guidance. Use edit_image if the user wants specific new content added around the image.
animate_image Animate a still image into a short video. Picks between several models via the model param:
remove_background Remove the background from a product image, returning a transparent PNG. Use this when the user wants to isolate a product, cut out the background, or get a transparent version of an image.
upload_image Upload an image to get a publicly accessible URL for use with edit_image, expand_image, etc.

Async jobs

Tool Description
submit_image_job Start an image/video generation ASYNCHRONOUSLY and return a jobId immediately (does NOT wait for the render). Use this instead of generate_image/edit_image when you want to avoid long waits/timeouts on 4K or video, run several jobs in parallel, or build a pipeline. After submitting, poll get_image_job with the returned jobId until status is "completed", then use the result URLs (e.g. feed one into another submit_image_job with tool="edit_image"). For tool="animate_image", pick the video model via videoModel (NOT model) and use duration/resolution/endImageUrl/generateAudio/videoUrls/audioUrls as with the sync animate_image tool. Credits are charged once, when the job runs.
get_image_job Retrieve a job submitted with submit_image_job. Returns status ("processing" | "completed" | "failed" | "timed_out"), progress, and — when completed — the result images/videos with downloadable URLs. Poll until status is "completed" (or "failed"/"timed_out"). On "completed", results[] contains { assetId, url, width, height, aspectRatio, assetType }.

Products, brand and account

Tool Description
get_product_images Search the user's saved product library and return image URLs. Call this tool IMMEDIATELY — without asking the user first — whenever they mention a product by name or reference (e.g. "the t-shirt", "my sneakers", "the coffee bag", "possible t shirt", "that product"). Do NOT ask the user to upload an image or confirm — just call this tool. The returned URLs can be passed directly to edit_image.
fetch_products_from_website Fetch product images directly from a brand's website. Use this when the user gives a website URL or domain, or asks to grab/import/pull products FROM a site (e.g. "grab the products from acme.com"). Do NOT use it for products already in the user's library — use get_product_images for those; if get_product_images finds nothing and the user has mentioned their website, call this. Works only on Shopify-powered stores (most DTC brands are); non-Shopify sites return a no-products error. By default it also saves the found products into the user's product library; set save_to_library to false only if the user explicitly wants a look without importing. Returns product titles and image URLs you can pass straight to edit_image.
get_all_context Retrieve all context files (brand knowledge, guidelines, campaign rules, etc.) with full content. Use when the injected context was truncated or you need inactive files. Context files are the user's persistent brand knowledge base.
update_context Update or create a context file. Context files store persistent brand knowledge (voice, memory, colors, campaign rules, audience info, etc.). If a file with this name exists, its content is replaced. If not, a new file is created. When updating, rewrite the full content with your changes incorporated.
get_account_info Get the user's account information including credits remaining, subscription plan, and usage. Use when the user asks about their account, credits, or usage.

Boards

Tool Description
list_boards List the user's image boards. Use this BEFORE add_images_to_board or update_board to find an existing board's id, or to confirm a board with that name doesn't already exist before calling create_board. Includes personal boards and any team boards the user has access to. Returns: id, name, description, is_public, team_ids, image_count.
get_board_images Read the images on a board and return their downloadable URLs + metadata. Identify the board by boardId (preferred — use list_boards to find it) or by name (returns the most recently updated board you can access with that name). Returns each image's url, videoUrl (for videos), width/height/aspectRatio, assetId, name (display name), model, source, origin, prompt, assetType, and position, plus the board's namingTemplate. origin is "upload" (the user put it on the board) or "generated" (Pikes made it) — boards mix both, since generated results are saved back onto the board holding the references. When sourcing a product shot or style reference to feed into edit_image / submit_image_job, filter to origin "upload": reusing a generated image as a source compounds its distortions. prompt is the generation prompt that created the image (empty for uploads) — to recreate a similar shot, start from that prompt and adapt it.
create_board Create a new image board. Returns the board id — pass it to add_images_to_board next. Visibility defaults to "private"; pass "team" + teamIds to share with one or more teams, or "public" to make the board world-readable. Public boards return share_url (https://pikes.ai/b/) — when sharing a link, use that exact URL; never construct board URLs yourself.
update_board Edit an existing board's name, description, or visibility. Only the board owner can update. To change visibility, pass the new "visibility" value (and teamIds when switching to "team"). Pass null for fields to leave unchanged. Boards cannot be deleted via MCP. Public boards return share_url (https://pikes.ai/b/) — when sharing a link, use that exact URL; never construct board URLs yourself.
add_images_to_board Add one or more images to a board. Pass assetId(s) from generate_image / edit_image / expand_image ("id" field), OR image URL(s) via publicUrl/publicUrls — Pikes URLs are linked directly, and EXTERNAL http(s) image URLs (e.g. find_ads ad stills, web images) are automatically fetched and re-hosted as the user's assets. Do not run a dummy edit_image just to get an id. The user must be the board owner or a team member with write access.
batch_rename_assets Rename assets on a board (sets each asset's display name — storage URLs never change). Flow: get_board_images first (returns name/model/source/prompt per image), derive a short concept name per image from its prompt/content, then ALWAYS show the user the proposed old → new rename table and wait for confirmation BEFORE calling this tool. Names: lowercase, hyphens inside, underscores between fields, no spaces. This renames the global asset name (visible everywhere); for per-download filename conventions set the board's namingTemplate via update_board instead.
list_teams List the teams the user is a member of. Use this when the user asks to share a board with a team — you need the team id to pass to create_board / update_board with visibility="team".

Research

Tool Description
find_ads Search Foreplay's ad library for real ads from any brand/competitor — for INSPIRATION and competitive research, NOT as generation inputs. Signature use: find a competitor's (or a niche's) ads that have run a LONG time, which signals the creative is likely working ("winning ads") — set sort:"longest_running", live:true, minRunningDays (30=working, 60/90=proven). Also browse by keyword/theme, niche, format, or platform. Returns ad image stills + metadata (brand, days running, headline, CTA). Analyze their composition, then create with the user's OWN product — do NOT pass the returned ad URLs into edit_image as the product.

Meta Ads and everything else

Tool Description
meta_get_ad_accounts List all Meta ad accounts the user has access to. Returns account ID, name, currency, and status. Call this first to get the accountId needed for other Meta tools.
meta_get_ad_comments Read user comments on a Meta ad — Facebook AND Instagram. Resolves the ad to its underlying post automatically (works on dark/unpublished posts too), so pass an adId from meta_get_ads, NOT a post id.
meta_get_ad_creative Get just the creative assets for a specific ad by ID. Use this when you already know the ad_id and only need the creative (not metrics).
meta_get_ad_insights Get detailed performance insights with conversions, ROAS, and breakdowns.
meta_get_ads Get ads with creative assets, performance metrics, conversions, and ROAS in a single call.
meta_get_audience_breakdowns Get available audience and delivery segment rows for specific ads.
meta_get_campaigns List campaigns for an ad account. Returns campaign ID, name, objective, status, budget, and date range.
meta_get_page_comments Read user comments on a Facebook Page's ORGANIC posts (posts that were never run as ads). Use alongside meta_get_ad_comments for full voice-of-customer coverage. Pass a pageId (e.g. the pageId returned by meta_get_ad_comments, or the part before the underscore in an effective_object_story_id). Returns comments tagged source:"organic". Requires that the user administers the page.

GET/mcp returns the same list with full schemas.

Common parameters#

Parameter Values
aspectRatio auto, 21:9, 16:9, 3:2, 4:3, 5:4, 1:1, 4:5, 3:4, 2:3, 9:16 (default 9:16)
resolution 1K, 2K, 4K — for consistency_pro these map to quality low / medium / high
model creativity_pro (Google Nano Banana Pro, default) and consistency_pro (OpenAI GPT Image 2 — stronger text and label fidelity) are the two to reach for. Also accepted: creativity_fast, creativity_light, flux_krea, ideogram_v3, ideogram_v4, google_edit, google_edit_pro, gpt_image_2_edit
imageCount 1–4 (default 1)
imageUrls up to 9 reference images on edit_image

Product identity is reference-conditioned, not fine-tuned: pass the actual pack shots as imageUrls (or let get_product_images fetch them from the product library) and the model works from those pixels. New packaging = new reference images, no retraining step.

Long renders#

4K and video can outrun an HTTP timeout. Submit and poll instead:

bash
curl -X POST https://pikes.ai/mcp/tools/submit_image_job \
  -H "x-api-key: psk_…" -H "Content-Type: application/json" \
  -d '{"tool":"generate_image","prompt":"…","resolution":"4K"}'
# → jobId

curl -X POST https://pikes.ai/mcp/tools/get_image_job \
  -H "x-api-key: psk_…" -H "Content-Type: application/json" \
  -d '{"jobId":"…"}'

Credits are charged once, when the job runs. Jobs are scoped to the caller.


Product-shot endpoints#

Two multipart endpoints for the simplest case — send a file, get a finished shot.

bash
curl -X POST https://pikes.ai/api/product-shot \
  -H "x-api-key: psk_…" \
  -F "image=@bottle.jpg" \
  -F "aspect_ratio=4:5" \
  -F "resolution=4K"
/api/product-shot /api/product-shot-custom
Prompt Fixed studio product-photography prompt Your prompt field (required)
aspect_ratio auto (default) or any ratio above same
resolution 1K (default) or 4K same

1K runs Nano Banana; 4K runs Nano Banana Pro. Success:

json
{ "success": true, "image": { "url": "…" }, "creditsUsed": 12 }

Cost today: 6 credits at 1K, 12 credits at 4K. Rate limit: 30 requests per minute per key. Credits are pre-charged and refunded automatically if the render fails.


Errors#

Status Meaning
400 Validation — missing prompt, bad aspect_ratio, unknown resolution, imageCount out of range
401 No/invalid/revoked credential
402 Insufficient credits, or no active subscription — body carries the shortfall detail
404 Not found, or not yours (revoking someone else's key looks like this on purpose)
429 Rate limited (product-shot endpoints)
500 Render or server failure — pre-charged credits are refunded

MCP tool calls that fail for content or upstream reasons return 200 with isError: true rather than an HTTP error.

Only the product-shot endpoints are rate limited today. On /mcp and /mcp/tools/* the practical ceiling is the account's credit balance — build your own backoff if you fan out hard.


Workspace scoping#

A credential identifies one user, and calls execute in that user's personal workspace: assets created over the API land with no team attached, whatever teams the user belongs to. list_teams exists so a board can be shared with a team after the fact, but there is no way to say "run this call as the ACME workspace."

Practical consequences for a multi-seat evaluation:

If a connection that belongs to a team rather than a person is a requirement, treat it as a roadmap item, not a configuration flag.


Verifying this document#

server/__tests__/api-surface-probe.js exercises this surface end to end and rewrites the generated blocks above from what the server answered, so the doc cannot quietly drift from the API.

bash
# against a local server (PORT=5099 node -r ./__tests__/boot-stub.js index.js)
node server/__tests__/api-surface-probe.js

# against production, no account needed — discovery, transport, auth negatives
node server/__tests__/api-surface-probe.js --base https://pikes.ai --quick

# refresh the generated blocks in this file
node server/__tests__/api-surface-probe.js --write-docs

# include one real 1K render (~6 credits)
node server/__tests__/api-surface-probe.js --generate

It covers discovery and PKCE advertisement, the auth negatives (no credential, bogus key, minting a key without a session), the key lifecycle across two accounts including cross-account revoke, initialize and tools/list, a REST tool call and its content-block envelope, revocation actually killing a key, and whether every live tool is documented here. A full run creates two throwaway users and deletes them; --quick creates nothing. Exit code is non-zero on any failure, so it drops straight into a loop or a scheduled check.


Data and billing notes#