API Docs

Quickstart

From zero to your first generated image in three steps.

Step 1 — Create a key

Open Account → API platform and hit Create key. Give it a name you will recognise later. The key is copied to your clipboard as soon as it is created, and you can copy it again from the list whenever you need it.

A key is your account — it spends your credits. You can copy it again from the list at any time, so there is no need to scatter copies around; every extra copy widens the blast radius.

Step 2 — See which models are available

Put the key in an environment variable and list the models. The id in the response is what you pass as model later.

bash
curl https://open.pikpikgo.com/v1/models \
  -H "Authorization: Bearer $PIKPIK_API_KEY"

Step 3 — Generate an image

bash
curl https://open.pikpikgo.com/v1/images/generations \
  -H "Authorization: Bearer $PIKPIK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "a rainy cyberpunk street at night, neon reflections",
    "size": "16:9",
    "quality": "2k",
    "n": 1
  }'

This is synchronous by default: the call waits until the image is ready and data[0].url holds it — no task lookup needed. A single image usually takes over 30 seconds, so raise your client timeout to 300 seconds.

json
{
  "created": 1786000246,
  "data": [
    { "url": "https://cdn.pikpikgo.com/ai/xxxx.png", "revised_prompt": "a rainy cyberpunk street at night, neon reflections" }
  ],
  "id": "2608101909450810293847",
  "object": "image.generation",
  "model": "img-std-1",
  "status": "succeeded",
  "n": 1,
  "credits": 10,
  "tasks": [
    {
      "id": "2608101909450810293847",
      "status": "succeeded",
      "data": [{ "url": "https://cdn.pikpikgo.com/ai/xxxx.png", "revised_prompt": "a rainy cyberpunk street at night, neon reflections" }]
    }
  ]
}

Step 4 — Prefer not to wait? Go asynchronous

Add async: true and the call returns straight away with status queued and an empty data array — nothing has been rendered yet. Keep tasks[0].id.

bash
curl https://open.pikpikgo.com/v1/images/generations \
  -H "Authorization: Bearer $PIKPIK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "a rainy cyberpunk street at night, neon reflections",
    "size": "16:9",
    "quality": "2k",
    "n": 1,
    "async": true
  }'
json
{
  "id": "2608101909450810293847",
  "object": "image.generation",
  "created": 1786000185,
  "model": "img-std-1",
  "status": "queued",
  "n": 1,
  "credits": 10,
  "tasks": [
    { "id": "2608101909450810293847", "status": "queued", "data": [] }
  ],
  "data": []
}

Poll that id; once status is succeeded, data[0].url holds the image. Video generation only works this way.

bash
curl https://open.pikpikgo.com/v1/tasks/2608101909450810293847 \
  -H "Authorization: Bearer $PIKPIK_API_KEY"
json
{
  "id": "2608101909450810293847",
  "object": "image.generation",
  "created": 1786000185,
  "model": "img-std-1",
  "status": "succeeded",
  "prompt": "a rainy cyberpunk street at night, neon reflections",
  "size": "16:9",
  "quality": "2k",
  "credits": 10,
  "error": "",
  "data": [
    { "url": "https://cdn.pikpikgo.com/ai/xxxx.png", "revised_prompt": "a rainy cyberpunk street at night, neon reflections" }
  ]
}

Full examples

The synchronous path works with the official OpenAI SDK — only the baseURL changes:

javascript
import OpenAI from 'openai'

const client = new OpenAI({
  apiKey: process.env.PIKPIK_API_KEY,
  baseURL: 'https://open.pikpikgo.com/v1',
  timeout: 300 * 1000,
})

// Synchronous: one round trip returns the URL, timeout raised to 300 seconds
const res = await client.images.generate({
  model: 'img-std-1',
  prompt: 'a rainy cyberpunk street at night, neon reflections',
  size: '1792x1024',
  n: 1,
})

console.log(res.data[0].url)

The asynchronous path needs submit and poll wired together, Node.js:

javascript
const BASE = 'https://open.pikpikgo.com/v1'
const KEY = process.env.PIKPIK_API_KEY

async function call(path, body) {
  const res = await fetch(BASE + path, {
    method: body ? 'POST' : 'GET',
    headers: {
      Authorization: `Bearer ${KEY}`,
      'Content-Type': 'application/json',
    },
    body: body ? JSON.stringify(body) : undefined,
  })
  const json = await res.json()
  if (json.error) throw new Error(json.error.message)
  return json
}

// Submit and wait for completion: poll every 3 seconds, give up after 10 minutes
async function generateImage(prompt) {
  const job = await call('/images/generations', { prompt, size: '16:9', async: true })
  const id = job.tasks[0].id

  for (let i = 0; i < 200; i++) {
    const task = await call(`/tasks/${id}`)
    if (task.status === 'succeeded') return task.data[0].url
    if (task.status === 'failed') throw new Error(task.error || 'generation failed')
    await new Promise((r) => setTimeout(r, 3000))
  }
  throw new Error('timed out waiting')
}

generateImage('a rainy cyberpunk street at night, neon reflections').then(console.log)

Python (video this time, with a longer poll interval):

python
import os, time, requests

BASE = "https://open.pikpikgo.com/v1"
KEY = os.environ["PIKPIK_API_KEY"]
HEAD = {"Authorization": f"Bearer {KEY}", "Content-Type": "application/json"}


def call(path, body=None):
    if body is None:
        r = requests.get(BASE + path, headers=HEAD, timeout=30)
    else:
        r = requests.post(BASE + path, headers=HEAD, json=body, timeout=60)
    data = r.json()
    if "error" in data:
        raise RuntimeError(data["error"]["message"])
    return data


def generate_video(prompt, seconds=5):
    job = call("/video/generations", {"prompt": prompt, "duration": seconds})

    # Video usually takes 1-5 minutes; polling every 5 seconds is plenty, tighter loops only burn rate limit
    for _ in range(200):
        task = call(f"/video/generations/{job['task_id']}")
        if task["status"] == "succeeded":
            return task["url"]
        if task["status"] == "failed":
            raise RuntimeError(task["error"] or "generation failed")
        time.sleep(5)
    raise TimeoutError("timed out waiting")


print(generate_video("slow dolly in, a girl turns back and smiles"))