API Docs

Chat completions

POST /v1/chat/completions

Call a text model. Unlike image and video, this endpoint is synchronous: one round trip gives you the answer, no polling. Request and response follow OpenAI chat/completions, streaming included, so any OpenAI SDK works by swapping the base URL.

Parameters

ParameterTypeDescription
modelstringRequired. Model id from /v1/models where type is text
messagesobject[]Required. Each item {role, content}; role is system, user or assistant. Max 64 per request
streambooleanOptional. true switches to SSE deltas; default false returns the whole reply at once
temperaturenumberOptional. Passed through to the model
top_pnumberOptional. Passed through
max_tokensintegerOptional. Passed through
stopstring|string[]Optional. Passed through
presence_penalty / frequency_penaltynumberOptional. Passed through
model is required and has no default: text models differ widely in tone, length and price, so quietly picking one would be making a decision on your behalf that you never saw.

Request

bash
curl https://open.pikpikgo.com/v1/chat/completions \
  -H "Authorization: Bearer $PIKPIK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "text-fast-1",
    "messages": [
      { "role": "system", "content": "You are a screenwriter who specialises in short drama." },
      { "role": "user", "content": "Give me an opening for an urban mystery short, three sentences at most." }
    ]
  }'

Response

json
{
  "id": "chatcmpl-2608102214300000123456",
  "object": "chat.completion",
  "created": 1786372470,
  "model": "text-fast-1",
  "choices": [
    {
      "index": 0,
      "message": { "role": "assistant", "content": "At midnight the lift stops at floor 13, but the building only has twelve." },
      "finish_reason": "stop"
    }
  ],
  "usage": { "prompt_tokens": 38, "completion_tokens": 126, "total_tokens": 164 },
  "credits": 4
}
FieldDescription
choices[0].message.contentThe reply text
choices[0].finish_reasonstop for a normal end, length when max_tokens was hit
usageToken counts. Text is billed per token, so this is the basis of the charge
creditsCredits actually charged (not an OpenAI field)
Text is billed per token, not per call: credits = input tokens × input rate + output tokens × output rate, rounded up, minimum 1 per call. Rates are quoted per million tokens on the pricing page.

Streaming

With stream: true the response becomes text/event-stream and arrives as chat.completion.chunk frames: the first declares the role, content comes one delta per frame, then a frame carrying finish_reason, then a final frame with an empty choices array plus usage and credits, closed by data: [DONE].

bash
curl -N https://open.pikpikgo.com/v1/chat/completions \
  -H "Authorization: Bearer $PIKPIK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "text-fast-1",
    "messages": [
      { "role": "user", "content": "Give me an opening for an urban mystery short, three sentences at most." }
    ],
    "stream": true
  }'
text
data: {"id":"chatcmpl-2608102214300000123456","object":"chat.completion.chunk","created":1786372470,"model":"text-fast-1","choices":[{"index":0,"delta":{"role":"assistant"},"finish_reason":null}]}

data: {"id":"chatcmpl-2608102214300000123456","object":"chat.completion.chunk","created":1786372470,"model":"text-fast-1","choices":[{"index":0,"delta":{"content":"At mid"},"finish_reason":null}]}

data: {"id":"chatcmpl-2608102214300000123456","object":"chat.completion.chunk","created":1786372470,"model":"text-fast-1","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}

data: {"id":"chatcmpl-2608102214300000123456","object":"chat.completion.chunk","created":1786372470,"model":"text-fast-1","choices":[],"usage":{"prompt_tokens":38,"completion_tokens":126,"total_tokens":164},"credits":4}

data: [DONE]

With the official OpenAI SDK you never touch the SSE parsing:

javascript
import OpenAI from 'openai'

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

// Streaming: deltas frame by frame, with usage and credits on the final frame
const stream = await client.chat.completions.create({
  model: 'text-fast-1',
  messages: [{ role: 'user', content: 'Give me an opening for an urban mystery short, three sentences at most.' }],
  stream: true,
})

for await (const chunk of stream) {
  process.stdout.write(chunk.choices[0]?.delta?.content || '')
}
Streaming is billed from the usage on the final frame; if upstream omits it, the call is charged the 1-credit minimum. Also note that once frames start flowing the HTTP status is already 200 — a mid-stream failure cannot become a 4xx/5xx. It arrives as an in-stream {"error": {...}} frame followed by the usual [DONE], so handle that frame while reading.