Chargement de votre compte

Démarrage rapide

De zéro à un fichier téléchargé en cinq étapes. Il vous faut une clé d’API avec les permissions generate et read, et quelques pièces.

1. Choisir un modèle

GET /v1/models est public. Chaque modèle a un id, un type de tâche et ses params avec les valeurs acceptées. N’envoyez que les paramètres que vous voulez fixer : les autres prennent la valeur par défaut du modèle. Voir Modèles.

2. Chiffrer

POST /v1/quotes renvoie les coins exactes de la requête et un quoteToken valable 10 minutes.

3. Envoyer

POST /v1/generations avec le même modelId et les mêmes params, plus exactement un champ parmi quoteToken (facture exactement les pièces du devis) et maxCoins (facture le prix actuel, jamais plus que cette valeur). L’en-tête Idempotency-Key est obligatoire : si une requête échoue à cause du réseau, renvoyez-la avec la même clé et vous obtiendrez la même génération au lieu d’un second débit.

Pour vous passer du devis, envoyez avec maxCoins. Si le prix est plus élevé, la requête échoue avec max_coins_exceeded et rien n’est débité.

JSON
{
  "modelId": "MODEL_ID",
  "params": { "prompt": "A lighthouse at dusk, watercolor" },
  "maxCoins": 40
}

4. Attendre le résultat

Interrogez GET /v1/generations/:id toutes les quelques secondes (pas plus souvent que toutes les 2 secondes) jusqu’à ce que le statut soit succeeded, failed ou canceled. Mieux encore : enregistrez un webhook pour être averti.

5. Télécharger

Chaque élément de outputs a une url. Les liens sont signés et de courte durée : téléchargez rapidement, ou relisez la génération (ou GET /v1/assets/:id) pour obtenir de nouveaux liens.

Exemple complet

curl
# 1. List the models (public, no key needed)
curl https://api.inker.si/v1/models

# 2. Quote: the exact coins this request costs, and a quoteToken valid 10 minutes
curl https://api.inker.si/v1/quotes \
  -H "Authorization: Bearer $INKER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"modelId": "MODEL_ID", "params": {"prompt": "A lighthouse at dusk, watercolor"}}'

# 3. Submit with the quoteToken (or "maxCoins": N instead).
#    Reuse the same Idempotency-Key when you retry the same request.
curl https://api.inker.si/v1/generations \
  -H "Authorization: Bearer $INKER_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"modelId": "MODEL_ID", "params": {"prompt": "A lighthouse at dusk, watercolor"}, "quoteToken": "QUOTE_TOKEN"}'

# 4. Poll until status is succeeded, failed or canceled (or use webhooks)
curl https://api.inker.si/v1/generations/GENERATION_ID \
  -H "Authorization: Bearer $INKER_API_KEY"

# 5. Download an output: outputs[].url is a short-lived signed link
curl -o output.png "OUTPUT_URL"
JavaScript
// Node 18+ (global fetch). Keep the key on your server, never in a browser.
import { writeFile } from 'node:fs/promises';

const API = 'https://api.inker.si';
const KEY = process.env.INKER_API_KEY;

async function inker(path, { headers, ...init } = {}) {
  const response = await fetch(`${API}${path}`, {
    ...init,
    headers: { Authorization: `Bearer ${KEY}`, 'Content-Type': 'application/json', ...headers },
  });
  const body = await response.json();
  // Errors are RFC 9457 problem details with a stable `code`.
  if (!response.ok) throw new Error(`${body.code}: ${body.detail}`);
  return body;
}

// 1. Pick a model
const { models } = await inker('/v1/models');
const model = models.find((m) => m.taskType === 'image.generate');
const params = { prompt: 'A lighthouse at dusk, watercolor' };

// 2. Quote
const quote = await inker('/v1/quotes', {
  method: 'POST',
  body: JSON.stringify({ modelId: model.id, params }),
});
console.log(`This costs ${quote.coins} coins`);

// 3. Submit (one Idempotency-Key per intended generation; reuse it on retries)
let generation = await inker('/v1/generations', {
  method: 'POST',
  headers: { 'Idempotency-Key': crypto.randomUUID() },
  body: JSON.stringify({ modelId: model.id, params, quoteToken: quote.quoteToken }),
});

// 4. Poll (or receive a webhook)
while (generation.status === 'queued' || generation.status === 'processing') {
  await new Promise((resolve) => setTimeout(resolve, 3000));
  generation = await inker(`/v1/generations/${generation.id}`);
}

// 5. Download the outputs
if (generation.status === 'succeeded') {
  for (const [i, output] of generation.outputs.entries()) {
    const file = await fetch(output.url);
    await writeFile(`output-${i}`, Buffer.from(await file.arrayBuffer()));
  }
}
Python
import os, time, uuid
import requests

API = "https://api.inker.si"
session = requests.Session()
session.headers["Authorization"] = f"Bearer {os.environ['INKER_API_KEY']}"


def inker(method, path, **kwargs):
    response = session.request(method, API + path, **kwargs)
    body = response.json()
    if not response.ok:
        # Errors are RFC 9457 problem details with a stable "code".
        raise RuntimeError(f"{body['code']}: {body['detail']}")
    return body


# 1. Pick a model
models = inker("GET", "/v1/models")["models"]
model = next(m for m in models if m["taskType"] == "image.generate")
params = {"prompt": "A lighthouse at dusk, watercolor"}

# 2. Quote
quote = inker("POST", "/v1/quotes", json={"modelId": model["id"], "params": params})
print(f"This costs {quote['coins']} coins")

# 3. Submit (one Idempotency-Key per intended generation; reuse it on retries)
generation = inker(
    "POST",
    "/v1/generations",
    headers={"Idempotency-Key": str(uuid.uuid4())},
    json={"modelId": model["id"], "params": params, "quoteToken": quote["quoteToken"]},
)

# 4. Poll (or receive a webhook)
while generation["status"] in ("queued", "processing"):
    time.sleep(3)
    generation = inker("GET", f"/v1/generations/{generation['id']}")

# 5. Download the outputs
if generation["status"] == "succeeded":
    for i, output in enumerate(generation["outputs"]):
        with open(f"output-{i}", "wb") as f:
            f.write(requests.get(output["url"]).content)

Utiliser vos propres fichiers

Les modèles qui prennent une image, un audio ou une vidéo demandent d’abord un envoi : envoyez le fichier à POST /v1/uploads en multipart/form-data dans le champ file, puis passez l’id renvoyé dans le paramètre média (par exemple image ou images). Les envois sont supprimés après 30 jours.

curl
# Upload an input file (multipart field "file"), then pass its id in a media param
curl https://api.inker.si/v1/uploads \
  -H "Authorization: Bearer $INKER_API_KEY" \
  -F "file=@photo.png"
JavaScript
import { readFile } from 'node:fs/promises';

const form = new FormData();
form.append('file', new Blob([await readFile('photo.png')], { type: 'image/png' }), 'photo.png');
const upload = await fetch('https://api.inker.si/v1/uploads', {
  method: 'POST',
  headers: { Authorization: `Bearer ${process.env.INKER_API_KEY}` },
  body: form,
});
const asset = await upload.json(); // use asset.id in a media param, e.g. params.image
Python
with open("photo.png", "rb") as f:
    asset = inker("POST", "/v1/uploads", files={"file": ("photo.png", f, "image/png")})
# use asset["id"] in a media param, e.g. params["image"]