جارٍ تحميل حسابك

البدء السريع

من الصفر إلى ملف منزَّل في خمس خطوات. تحتاج إلى مفتاح لواجهة البرمجة بالصلاحيتين generate وread، وإلى بعض العملات.

1. اختر نموذجًا

GET /v1/models عامة. لكل نموذج id ونوع مهمة وparams مع القيم التي تقبلها. أرسل فقط المعاملات التي تريد ضبطها: تأخذ البقية القيمة الافتراضية للنموذج. راجع النماذج.

2. احصل على تسعيرة

تُعيد POST /v1/quotes قيمة coins الدقيقة للطلب وquoteToken صالحًا لمدة 10 دقائق.

3. أرسل الطلب

استدعِ POST /v1/generations بالقيمتين نفسيهما modelId وparams، مع واحد فقط من quoteToken (يُخصم عدد العملات المسعَّر بالضبط) أو maxCoins (يُخصم السعر الحالي، ولا يتجاوز هذه القيمة أبدًا). الترويسة Idempotency-Key إلزامية: إذا فشل طلب بسبب الشبكة، فأعد إرساله بالمفتاح نفسه لتحصل على عملية التوليد نفسها بدلًا من خصم ثانٍ.

لتتخطى التسعيرة، أرسل الطلب مع maxCoins. إذا كان السعر أعلى منها، يفشل الطلب بـ max_coins_exceeded ولا يُخصم شيء.

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

4. انتظر النتيجة

استعلم عن GET /v1/generations/:id كل بضع ثوانٍ (ليس أسرع من مرة كل ثانيتين) حتى تصبح الحالة succeeded أو failed أو canceled. والأفضل من ذلك أن تسجّل خطاف ويب لتتلقى إشعارًا.

5. نزّل النتيجة

لكل عنصر في outputs قيمة url. الروابط موقّعة وقصيرة الأجل: نزّل الملفات سريعًا، أو اقرأ عملية التوليد مرة أخرى (أو GET /v1/assets/:id) للحصول على روابط جديدة.

مثال كامل

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)

استخدام ملفاتك الخاصة

تحتاج النماذج التي تأخذ صورة أو صوتًا أو فيديو إلى رفع الملف أولًا: أرسل الملف إلى POST /v1/uploads بصيغة multipart/form-data في الحقل file، ثم مرّر قيمة id المُعادة في معامل الوسائط (مثل image أو images). تُحذف الملفات المرفوعة بعد 30 يومًا.

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"]