Media API · v1 · ۲۰۲۶/۰۹/۰۵

API تولید عکس، ویدئو و موسیقی با هوش مصنوعی

یک REST API برای چهار نوع خروجی: عکس، ویدئو، موسیقی و مدل سه‌بعدی. با یک کلید، قیمت را قبل از تولید بگیرید، درخواست را امن تکرار کنید و هزینه را از کردیت کیف پول بپردازید.

آدرس پایه

https://api.noqte.ai/v1/media

ارسال تولید · POST /v1/media/generations

curl -sS "https://api.noqte.ai/v1/media/generations" \
  -H "Authorization: Bearer $NOQTE_MEDIA_KEY" \
  -H "Idempotency-Key: order-1042-cover-v1" \
  -H "Content-Type: application/json" \
  -d '{
  "model_slug": "gpt-image-2",
  "prompt": "A calm cinematic scene at sunrise, soft light",
  "params": {
    "size": "1:1",
    "quality": "low"
  },
  "max_credits": 20
}'
import os
import requests

BASE = "https://api.noqte.ai/v1/media"
HEADERS = {"Authorization": f"Bearer {os.environ['NOQTE_MEDIA_KEY']}"}

payload = {
    "model_slug": "gpt-image-2",
    "prompt": "A calm cinematic scene at sunrise, soft light",
    "params": {
        "size": "1:1",
        "quality": "low",
    },
    "max_credits": 20,
}

response = requests.post(
    f"{BASE}/generations",
    json=payload,
    headers={**HEADERS, "Idempotency-Key": "order-1042-cover-v1"},
    timeout=60,
)
data = response.json()
if not response.ok:
    raise RuntimeError(f"{response.status_code} {data['error']['code']}: {data['error']['message']}")
print(data)
const BASE = "https://api.noqte.ai/v1/media";
const headers = { Authorization: `Bearer ${process.env.NOQTE_MEDIA_KEY}` };

const response = await fetch(`${BASE}/generations`, {
  method: "POST",
  headers: { ...headers, "Content-Type": "application/json", "Idempotency-Key": "order-1042-cover-v1" },
  body: JSON.stringify({
    model_slug: "gpt-image-2",
    prompt: "A calm cinematic scene at sunrise, soft light",
    params: {
      size: "1:1",
      quality: "low"
    },
    max_credits: 20
  }),
});
const data = await response.json();
if (!response.ok) throw new Error(`${response.status} ${data.error.code}: ${data.error.message}`);
console.log(data);
<?php
$base = "https://api.noqte.ai/v1/media";
$headers = [
    "Authorization: Bearer " . getenv("NOQTE_MEDIA_KEY"),
    "Idempotency-Key: order-1042-cover-v1",
    "Content-Type: application/json",
];

$payload = [
    "model_slug" => "gpt-image-2",
    "prompt" => "A calm cinematic scene at sunrise, soft light",
    "params" => [
        "size" => "1:1",
        "quality" => "low",
    ],
    "max_credits" => 20,
];

$ch = curl_init("$base/generations");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => $headers,
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => json_encode($payload, JSON_UNESCAPED_UNICODE),
]);

$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

$data = json_decode($body, true);
if ($status >= 400) {
    throw new RuntimeException("$status {$data['error']['code']}: {$data['error']['message']}");
}
print_r($data);
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"strings"
)

func main() {
	payload := `{
	  "model_slug": "gpt-image-2",
	  "prompt": "A calm cinematic scene at sunrise, soft light",
	  "params": {
	    "size": "1:1",
	    "quality": "low"
	  },
	  "max_credits": 20
	}`

	req, err := http.NewRequest("POST", "https://api.noqte.ai/v1/media/generations", strings.NewReader(payload))
	if err != nil {
		panic(err)
	}
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", "Bearer "+os.Getenv("NOQTE_MEDIA_KEY"))
	req.Header.Set("Idempotency-Key", "order-1042-cover-v1")

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()
	data, _ := io.ReadAll(res.Body)
	fmt.Println(res.StatusCode, string(data))
}
endpoint فعال
۷
زبان نمونهٔ کد
۵
مدل قابل فراخوانی
۴۳
پیش‌نیاز اشتراک پرو
ندارد

01 · Why

چرا با API نقطه بسازید

یک قرارداد برای چهار نوع خروجی، با پرداخت ریالی و رفتار مالی صریح: قیمت قبل از تولید، سقف هزینه در خود درخواست و بازگشت کردیت در شکست.

01

پرداخت با کردیت کیف پول

هزینهٔ هر تولید از موجودی ریالی همان حساب کسر می‌شود؛ نه کارت خارجی لازم است نه اشتراک دلاری. مصرف هر کلید جدا گزارش می‌شود.

02

بدون نیاز به اشتراک پرو

کلید تولید محتوا مستقل از پلن حساب ساخته می‌شود. کلیدهای مدل زبانی در این API پذیرفته نمی‌شوند و برعکس.

03

قیمت را قبل از تولید بدانید

همان بدنهٔ تولید را به «برآورد» بفرستید تا قیمت دقیق همان ورودی و گزینه‌های resolve‌شده را بگیرید؛ در این مرحله چیزی کسر نمی‌شود.

04

تکرار امن به‌جای هزینهٔ دوباره

هر ارسال یک Idempotency-Key دارد. اگر اتصال قطع شد، همان شناسه و همان بدنه را دوباره بفرستید؛ همان تولید برمی‌گردد، نه یک کسر تازه.

05

سقف هزینه در خود درخواست

با max_credits سقف رضایت خود را اعلام کنید. اگر قیمت واقعی از آن بیشتر باشد درخواست رد می‌شود و کردیتی کسر نمی‌شود.

06

بازگشت کردیت در شکست

اگر تولید کامل نشود، وضعیت مالی جدا از وضعیت تولید گزارش می‌شود و همان بخش تحویل‌نشده به کیف پول برمی‌گردد.

02 · Quick start

شروع سریع در سه قدم

REST + JSON با احراز هویت Bearer و پذیرش غیرهم‌زمان. کلید را فقط سمت سرور و در متغیر محیطی نگه دارید.

  1. 01

    برآورد

    همان بدنهٔ تولید را بدون max_credits بفرستید؛ قیمت دقیق برمی‌گردد و کردیتی کسر نمی‌شود.

  2. 02

    ارسال

    با max_credits و یک Idempotency-Key ثابت. پاسخ 202 یعنی پذیرفته شد و هزینه کسر شد.

  3. 03

    پیگیری

    هر چند ثانیه وضعیت را بخوانید؛ outputs لینک امضاشده و زمان‌دار دارد.

# کلید را فقط در متغیر محیطی نگه دارید؛ نیازمند curl و jq
export NOQTE_MEDIA_KEY='sk-media-…'
BASE='https://api.noqte.ai/v1/media'
PAYLOAD='{"model_slug":"gpt-image-2","prompt":"A calm cinematic scene at sunrise, soft light","params":{"size":"1:1","quality":"low"}}'

# ۱) برآورد — بدون کسر کردیت
curl -sS "$BASE/estimate" \
  -H "Authorization: Bearer $NOQTE_MEDIA_KEY" \
  -H "Content-Type: application/json" \
  -d "$PAYLOAD"

# ۲) ارسال تولید — شناسهٔ تکرار را یک‌بار بسازید و در retry همان را بفرستید
OP_ID="$(uuidgen)"
GEN_ID=$(curl -sS "$BASE/generations" \
  -H "Authorization: Bearer $NOQTE_MEDIA_KEY" \
  -H "Idempotency-Key: $OP_ID" \
  -H "Content-Type: application/json" \
  -d "$(printf '%s' "$PAYLOAD" | jq '. + {max_credits: 20}')" | jq -r '.generation.id')

# ۳) پیگیری هر ۵ ثانیه تا completed یا failed
while :; do
  STATUS=$(curl -sS "$BASE/generations/$GEN_ID" -H "Authorization: Bearer $NOQTE_MEDIA_KEY")
  STATE=$(printf '%s' "$STATUS" | jq -r '.generation.status')
  [ "$STATE" = completed ] || [ "$STATE" = failed ] && break
  sleep 5
done
printf '%s\n' "$STATUS" | jq '.generation | {status, net_credits, billing_status, outputs}'
import os
import time
import uuid

import requests

BASE = "https://api.noqte.ai/v1/media"
HEADERS = {"Authorization": f"Bearer {os.environ['NOQTE_MEDIA_KEY']}"}


def call(method, path, **kwargs):
    response = requests.request(method, f"{BASE}{path}", headers={**HEADERS, **kwargs.pop("headers", {})}, timeout=60, **kwargs)
    data = response.json()
    if not response.ok:
        raise RuntimeError(f"{response.status_code} {data['error']['code']}: {data['error']['message']}")
    return data


payload = {
    "model_slug": "gpt-image-2",
    "prompt": "A calm cinematic scene at sunrise, soft light",
    "params": {
        "size": "1:1",
        "quality": "low",
    },
}

# ۱) برآورد — بدون کسر کردیت
estimate = call("POST", "/estimate", json=payload)
print("credits:", estimate["credits"], "wallet:", estimate["wallet_balance"])

# ۲) ارسال تولید؛ شناسهٔ تکرار را پیش از ارسال ذخیره کنید و در retry تغییر ندهید
operation_id = str(uuid.uuid4())
accepted = call(
    "POST",
    "/generations",
    json={**payload, "max_credits": estimate["credits"]},
    headers={"Idempotency-Key": operation_id},
)
generation = accepted["generation"]

# ۳) پیگیری تا completed یا failed
while generation["status"] in ("pending", "running"):
    time.sleep(accepted.get("poll_after_seconds") or 5)
    generation = call("GET", f"/generations/{generation['id']}")["generation"]

if generation["status"] == "failed":
    raise RuntimeError(f"{generation['error']['code']} — billing: {generation['billing_status']}")

for output in generation["outputs"]:
    print(output["url"])  # لینک امضاشده و زمان‌دار
import { randomUUID } from "node:crypto";

const BASE = "https://api.noqte.ai/v1/media";
const headers = { Authorization: `Bearer ${process.env.NOQTE_MEDIA_KEY}` };

async function call(path, init = {}) {
  const response = await fetch(`${BASE}${path}`, {
    ...init,
    headers: { ...headers, "Content-Type": "application/json", ...init.headers },
    signal: AbortSignal.timeout(60_000),
  });
  const data = await response.json();
  if (!response.ok) throw new Error(`${response.status} ${data.error.code}: ${data.error.message}`);
  return data;
}

const payload = {
  model_slug: "gpt-image-2",
  prompt: "A calm cinematic scene at sunrise, soft light",
  params: {
    size: "1:1",
    quality: "low"
  }
};

// ۱) برآورد — بدون کسر کردیت
const estimate = await call("/estimate", { method: "POST", body: JSON.stringify(payload) });
console.log("credits:", estimate.credits, "wallet:", estimate.wallet_balance);

// ۲) ارسال تولید؛ شناسهٔ تکرار را پیش از ارسال ذخیره کنید و در retry تغییر ندهید
const operationId = randomUUID();
const accepted = await call("/generations", {
  method: "POST",
  headers: { "Idempotency-Key": operationId },
  body: JSON.stringify({ ...payload, max_credits: estimate.credits }),
});
let { generation } = accepted;

// ۳) پیگیری تا completed یا failed
while (generation.status === "pending" || generation.status === "running") {
  await new Promise((resolve) => setTimeout(resolve, (accepted.poll_after_seconds ?? 5) * 1000));
  ({ generation } = await call(`/generations/${generation.id}`));
}

if (generation.status === "failed") {
  throw new Error(`${generation.error.code} — billing: ${generation.billing_status}`);
}
for (const output of generation.outputs) console.log(output.url); // لینک امضاشده و زمان‌دار
<?php
$base = "https://api.noqte.ai/v1/media";
$key = getenv("NOQTE_MEDIA_KEY");

function call(string $method, string $path, ?array $json = null, array $extraHeaders = []): array
{
    global $base, $key;
    $ch = curl_init($base . $path);
    $headers = array_merge(["Authorization: Bearer $key", "Content-Type: application/json"], $extraHeaders);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_CUSTOMREQUEST => $method,
        CURLOPT_HTTPHEADER => $headers,
        CURLOPT_POSTFIELDS => $json === null ? null : json_encode($json, JSON_UNESCAPED_UNICODE),
    ]);
    $body = curl_exec($ch);
    $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    $data = json_decode($body, true);
    if ($status >= 400) {
        throw new RuntimeException("$status {$data['error']['code']}: {$data['error']['message']}");
    }
    return $data;
}

$payload = [
    "model_slug" => "gpt-image-2",
    "prompt" => "A calm cinematic scene at sunrise, soft light",
    "params" => [
        "size" => "1:1",
        "quality" => "low",
    ],
];

// ۱) برآورد — بدون کسر کردیت
$estimate = call("POST", "/estimate", $payload);
echo "credits: {$estimate['credits']}\n";

// ۲) ارسال تولید؛ شناسهٔ تکرار را پیش از ارسال ذخیره کنید و در retry تغییر ندهید
$operationId = bin2hex(random_bytes(16));
$accepted = call("POST", "/generations", $payload + ["max_credits" => $estimate["credits"]], ["Idempotency-Key: $operationId"]);
$generation = $accepted["generation"];

// ۳) پیگیری تا completed یا failed
while (in_array($generation["status"], ["pending", "running"], true)) {
    sleep($accepted["poll_after_seconds"] ?? 5);
    $generation = call("GET", "/generations/{$generation['id']}")["generation"];
}

if ($generation["status"] === "failed") {
    throw new RuntimeException($generation["error"]["code"] . " — billing: " . $generation["billing_status"]);
}
foreach ($generation["outputs"] as $output) {
    echo $output["url"], "\n"; // لینک امضاشده و زمان‌دار
}
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
	"os"
	"time"

	"github.com/google/uuid"
)

const base = "https://api.noqte.ai/v1/media"

func call(method, path string, body any, headers map[string]string) map[string]any {
	var reader *bytes.Reader
	if body != nil {
		raw, _ := json.Marshal(body)
		reader = bytes.NewReader(raw)
	} else {
		reader = bytes.NewReader(nil)
	}
	req, err := http.NewRequest(method, base+path, reader)
	if err != nil {
		panic(err)
	}
	req.Header.Set("Authorization", "Bearer "+os.Getenv("NOQTE_MEDIA_KEY"))
	req.Header.Set("Content-Type", "application/json")
	for k, v := range headers {
		req.Header.Set(k, v)
	}
	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()
	var data map[string]any
	json.NewDecoder(res.Body).Decode(&data)
	if res.StatusCode >= 400 {
		e := data["error"].(map[string]any)
		panic(fmt.Sprintf("%d %v: %v", res.StatusCode, e["code"], e["message"]))
	}
	return data
}

func main() {
	payload := map[string]any{
		"model_slug": "gpt-image-2",
		"prompt":     "A calm cinematic scene at sunrise, soft light",
		"params":     map[string]string{"size": "1:1", "quality": "low"},
	}

	// ۱) برآورد — بدون کسر کردیت
	estimate := call("POST", "/estimate", payload, nil)
	fmt.Println("credits:", estimate["credits"])

	// ۲) ارسال تولید؛ شناسهٔ تکرار را پیش از ارسال ذخیره کنید و در retry تغییر ندهید
	payload["max_credits"] = estimate["credits"]
	accepted := call("POST", "/generations", payload, map[string]string{"Idempotency-Key": uuid.NewString()})
	generation := accepted["generation"].(map[string]any)

	// ۳) پیگیری تا completed یا failed
	for generation["status"] == "pending" || generation["status"] == "running" {
		time.Sleep(5 * time.Second)
		generation = call("GET", "/generations/"+generation["id"].(string), nil, nil)["generation"].(map[string]any)
	}
	if generation["status"] == "failed" {
		panic(fmt.Sprintf("%v — billing: %v", generation["error"], generation["billing_status"]))
	}
	for _, output := range generation["outputs"].([]any) {
		fmt.Println(output.(map[string]any)["url"]) // لینک امضاشده و زمان‌دار
	}
}

03 · Authentication

احراز هویت و دسترسی‌ها

کلید تولید محتوا با پیشوند sk-media- ساخته می‌شود، فقط یک‌بار نمایش داده می‌شود و نیازی به اشتراک پرو ندارد. آن را در هدر Authorization بفرستید؛ x-api-key هم پذیرفته می‌شود. کلیدهای مدل زبانی (sk-noqte-) در این API کار نمی‌کنند.

HTTP
GET /v1/media/models?kind=image HTTP/1.1
Host: api.noqte.ai
Authorization: Bearer sk-media-xxxxxxxxxxxxxxxxxxxxxxxx
Accept: application/json
دسترسی‌ها (scopes) — هنگام ساخت کلید انتخاب می‌شوند
media:readکاتالوگ مدل‌ها، برآورد هزینه، وضعیت و تاریخچهٔ تولیدهای همین کلید
media:generateارسال درخواست تولید
assets:writeآپلود فایل مرجع (تصویر، صدا، ویدئو)
usage:readمصرف کردیت، موجودی کیف پول و سقف‌ها

هر کلید فقط تولیدهای خودش را می‌بیند. محدودیت IP، فهرست مدل‌های مجاز، تاریخ انقضا و سقف کردیت روزانه/کل در تنظیمات همان کلید تعیین می‌شود.

04 · Endpoints

فهرست endpointها

endpointscopeکارکرد
GET/v1/media/modelsmedia:readمدل‌های فعال و مجاز برای این کلید، همراه قرارداد ورودی و قیمت پایه.
POST/v1/media/estimatemedia:readورودی را اعتبارسنجی و قیمت دقیق را برمی‌گرداند؛ کردیتی کسر نمی‌شود.
POST/v1/media/uploadsassets:writeفایل مرجع را با multipart ثبت می‌کند و `asset.id` برمی‌گرداند.
POST/v1/media/generationsmedia:generateدرخواست را می‌پذیرد، هزینه را کسر می‌کند و شناسهٔ پیگیری برمی‌گرداند (202).
GET/v1/media/generations/{generation_id}media:readوضعیت، هزینه و لینک خروجی‌های یک تولید.
GET/v1/media/generationsmedia:readفهرست صفحه‌بندی‌شدهٔ تولیدهای همین کلید، از جدید به قدیم.
GET/v1/media/usageusage:readمصرف خالص این کلید، موجودی کیف پول و محدودیت‌های حساب.
GET/v1/media/openapi.jsonبدون کلیدقرارداد OpenAPI 3 همین API برای تولید کلاینت.

05 · Reference

مرجع endpointها

هر endpoint با پارامترها، نمونهٔ درخواست در پنج زبان و پاسخ واقعی.

GET/v1/media/modelsscope: media:read

فهرست مدل‌ها

مدل‌های فعال و مجاز برای این کلید، همراه قرارداد ورودی و قیمت پایه.

کاتالوگ، مرجع ورودی است: slug، گروه‌های options، متن‌های text_inputs، ورودی‌های فایل و سقف پرامپت هر مدل از همین پاسخ خوانده می‌شود. شناسه و قیمت را در کد ثابت فرض نکنید.

اگر برای کلید فهرست مدل مجاز تنظیم شده باشد، فقط همان مدل‌ها برمی‌گردند.

  • پارامترهای query
  • kind"image" | "video" | "music" | "3d"

    فیلتر نوع مدل.

نمونهٔ درخواست

curl -sS "https://api.noqte.ai/v1/media/models?kind=image" \
  -H "Authorization: Bearer $NOQTE_MEDIA_KEY"
import os
import requests

BASE = "https://api.noqte.ai/v1/media"
HEADERS = {"Authorization": f"Bearer {os.environ['NOQTE_MEDIA_KEY']}"}

response = requests.get(
    f"{BASE}/models",
    params={"kind": "image"},
    headers=HEADERS,
    timeout=30,
)
data = response.json()
if not response.ok:
    raise RuntimeError(f"{response.status_code} {data['error']['code']}: {data['error']['message']}")
print(data)
const BASE = "https://api.noqte.ai/v1/media";
const headers = { Authorization: `Bearer ${process.env.NOQTE_MEDIA_KEY}` };

const response = await fetch(`${BASE}/models?kind=image`, { headers });
const data = await response.json();
if (!response.ok) throw new Error(`${response.status} ${data.error.code}: ${data.error.message}`);
console.log(data);
<?php
$base = "https://api.noqte.ai/v1/media";
$headers = [
    "Authorization: Bearer " . getenv("NOQTE_MEDIA_KEY"),
];

$ch = curl_init("$base/models?kind=image");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => $headers,
]);

$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

$data = json_decode($body, true);
if ($status >= 400) {
    throw new RuntimeException("$status {$data['error']['code']}: {$data['error']['message']}");
}
print_r($data);
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
)

func main() {
	req, err := http.NewRequest("GET", "https://api.noqte.ai/v1/media/models?kind=image", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("Authorization", "Bearer "+os.Getenv("NOQTE_MEDIA_KEY"))

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()
	data, _ := io.ReadAll(res.Body)
	fmt.Println(res.StatusCode, string(data))
}

پاسخ200

200 application/json
{
  "models": [
    {
      "slug": "gpt-image-2",
      "kind": "image",
      "label": "نام نمایشی مدل",
      "description": "توضیح کوتاه مدل",
      "credits": 12,
      "unit": "image",
      "prompt_optional": false,
      "prompt_max_chars": 2000,
      "options": {
        "aspect_ratio": [
          {
            "id": "1:1",
            "label": "مربع",
            "default": true,
            "credits": 12
          },
          {
            "id": "16:9",
            "label": "افقی",
            "credits": 12
          }
        ]
      },
      "text_inputs": [],
      "image_input": {
        "max": 4,
        "label": "تصویر مرجع",
        "required": false,
        "max_mb": 20,
        "formats": [
          "png",
          "jpg",
          "webp"
        ]
      },
      "input_slots": []
    }
  ],
  "media_enabled": true,
  "billing_source": "wallet",
  "daily_free_credits_eligible": false
}
POST/v1/media/estimatescope: media:read

برآورد هزینه

ورودی را اعتبارسنجی و قیمت دقیق را برمی‌گرداند؛ کردیتی کسر نمی‌شود.

همان بدنهٔ تولید را بدون max_credits بفرستید. پاسخ، قیمت نهایی این ورودی و گزینه‌های resolve‌شده را می‌دهد.

برآورد رزرو نیست؛ کافی‌بودن موجودی هنگام تولید دوباره بررسی می‌شود.

  • بدنهٔ JSON
  • model_slugstringالزامی

    شناسهٔ دقیق مدل از کاتالوگ (slug). نام نمایشی یا auto پذیرفته نمی‌شود.

  • promptstringالزامی

    متن درخواست. سقف کاراکتر هر مدل در prompt_max_chars است؛ برای مدل‌های prompt_optional می‌تواند خالی باشد.

  • paramsobject<string, string>

    گزینه‌های مدل؛ کلید = نام گروه، مقدار = id یکی از گزینه‌های همان گروه. گزینهٔ ناشناخته خطای 422 می‌دهد.

  • textsobject<string, string>

    متن‌های تکمیلی مدل (مثل ترانه). فقط کلیدهای اعلام‌شده در text_inputs.

  • refsstring[]

    شناسهٔ فایل‌های مرجع عمومی (asset.id از آپلود).

  • ref_slotsobject<string, string[]>

    فایل‌های نقش‌دار؛ کلید = key یکی از input_slots مدل.

  • ref_rolesobject<string, "first" | "last">

    نقش فریم برای هر شناسهٔ حاضر در refs؛ فقط برای مدل‌هایی که frame_contract دارند.

نمونهٔ درخواست

curl -sS "https://api.noqte.ai/v1/media/estimate" \
  -H "Authorization: Bearer $NOQTE_MEDIA_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "model_slug": "gpt-image-2",
  "prompt": "A calm cinematic scene at sunrise, soft light",
  "params": {
    "size": "1:1",
    "quality": "low"
  }
}'
import os
import requests

BASE = "https://api.noqte.ai/v1/media"
HEADERS = {"Authorization": f"Bearer {os.environ['NOQTE_MEDIA_KEY']}"}

payload = {
    "model_slug": "gpt-image-2",
    "prompt": "A calm cinematic scene at sunrise, soft light",
    "params": {
        "size": "1:1",
        "quality": "low",
    },
}

response = requests.post(
    f"{BASE}/estimate",
    json=payload,
    headers=HEADERS,
    timeout=60,
)
data = response.json()
if not response.ok:
    raise RuntimeError(f"{response.status_code} {data['error']['code']}: {data['error']['message']}")
print(data)
const BASE = "https://api.noqte.ai/v1/media";
const headers = { Authorization: `Bearer ${process.env.NOQTE_MEDIA_KEY}` };

const response = await fetch(`${BASE}/estimate`, {
  method: "POST",
  headers: { ...headers, "Content-Type": "application/json" },
  body: JSON.stringify({
    model_slug: "gpt-image-2",
    prompt: "A calm cinematic scene at sunrise, soft light",
    params: {
      size: "1:1",
      quality: "low"
    }
  }),
});
const data = await response.json();
if (!response.ok) throw new Error(`${response.status} ${data.error.code}: ${data.error.message}`);
console.log(data);
<?php
$base = "https://api.noqte.ai/v1/media";
$headers = [
    "Authorization: Bearer " . getenv("NOQTE_MEDIA_KEY"),
    "Content-Type: application/json",
];

$payload = [
    "model_slug" => "gpt-image-2",
    "prompt" => "A calm cinematic scene at sunrise, soft light",
    "params" => [
        "size" => "1:1",
        "quality" => "low",
    ],
];

$ch = curl_init("$base/estimate");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => $headers,
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => json_encode($payload, JSON_UNESCAPED_UNICODE),
]);

$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

$data = json_decode($body, true);
if ($status >= 400) {
    throw new RuntimeException("$status {$data['error']['code']}: {$data['error']['message']}");
}
print_r($data);
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"strings"
)

func main() {
	payload := `{
	  "model_slug": "gpt-image-2",
	  "prompt": "A calm cinematic scene at sunrise, soft light",
	  "params": {
	    "size": "1:1",
	    "quality": "low"
	  }
	}`

	req, err := http.NewRequest("POST", "https://api.noqte.ai/v1/media/estimate", strings.NewReader(payload))
	if err != nil {
		panic(err)
	}
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", "Bearer "+os.Getenv("NOQTE_MEDIA_KEY"))

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()
	data, _ := io.ReadAll(res.Body)
	fmt.Println(res.StatusCode, string(data))
}

پاسخ200

200 application/json
{
  "credits": 12,
  "wallet_balance": 480,
  "has_enough_credits": true,
  "resolved_params": {
    "size": "1:1",
    "quality": "low"
  },
  "billing_source": "wallet",
  "daily_free_credits_eligible": false
}
POST/v1/media/uploadsscope: assets:write

آپلود فایل مرجع

فایل مرجع را با multipart ثبت می‌کند و `asset.id` برمی‌گرداند.

فایل بر اساس قرارداد همان مدل (فرمت، حجم، ابعاد، مدت) بررسی می‌شود. شناسهٔ برگشتی را در refs یا ref_slots تولید قرار دهید؛ URL یا مسیر فایل پذیرفته نمی‌شود.

فایل متعلق به حساب شماست و برای مدل دیگر هم قابل استفاده است، ولی هنگام استفاده دوباره با قرارداد آن مدل بررسی می‌شود.

  • فیلدهای multipart/form-data
  • filefileالزامی

    فایل تصویر، صدا یا ویدئو. Content-Type فایل باید درست باشد.

  • model_slugstringالزامی

    مدلی که فایل برای آن آماده می‌شود.

  • target_slotstring

    برای ورودی نقش‌دار، key همان slot (مثلاً first_frame).

نمونهٔ درخواست

curl -sS "https://api.noqte.ai/v1/media/uploads" \
  -H "Authorization: Bearer $NOQTE_MEDIA_KEY" \
  -F "model_slug=gpt-image-2" \
  -F "file=@reference.png;type=image/png"
import os
import requests

BASE = "https://api.noqte.ai/v1/media"
HEADERS = {"Authorization": f"Bearer {os.environ['NOQTE_MEDIA_KEY']}"}

with open("reference.png", "rb") as file:
    response = requests.post(
        f"{BASE}/uploads",
        data={"model_slug": "gpt-image-2"},
        files={"file": ("reference.png", file, "image/png")},
        headers=HEADERS,
        timeout=120,
    )
data = response.json()
if not response.ok:
    raise RuntimeError(f"{response.status_code} {data['error']['code']}: {data['error']['message']}")
print(data)
import { readFile } from "node:fs/promises";

const BASE = "https://api.noqte.ai/v1/media";
const headers = { Authorization: `Bearer ${process.env.NOQTE_MEDIA_KEY}` };

const form = new FormData();
form.append("model_slug", "gpt-image-2");
form.append(
  "file",
  new Blob([await readFile("reference.png")], { type: "image/png" }),
  "reference.png",
);

const response = await fetch(`${BASE}/uploads`, { method: "POST", headers, body: form });
const data = await response.json();
if (!response.ok) throw new Error(`${response.status} ${data.error.code}: ${data.error.message}`);
console.log(data);
<?php
$base = "https://api.noqte.ai/v1/media";
$headers = [
    "Authorization: Bearer " . getenv("NOQTE_MEDIA_KEY"),
];

$ch = curl_init("$base/uploads");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => $headers,
    CURLOPT_POSTFIELDS => [
        "model_slug" => "gpt-image-2",
        "file" => new CURLFile("reference.png", "image/png", "reference.png"),
    ],
]);

$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

$data = json_decode($body, true);
if ($status >= 400) {
    throw new RuntimeException("$status {$data['error']['code']}: {$data['error']['message']}");
}
print_r($data);
package main

import (
	"bytes"
	"fmt"
	"io"
	"mime/multipart"
	"net/http"
	"os"
)

func main() {
	var buf bytes.Buffer
	writer := multipart.NewWriter(&buf)
	writer.WriteField("model_slug", "gpt-image-2")
	file, err := os.Open("reference.png")
	if err != nil {
		panic(err)
	}
	defer file.Close()
	part, _ := writer.CreateFormFile("file", "reference.png")
	io.Copy(part, file)
	writer.Close()

	req, err := http.NewRequest("POST", "https://api.noqte.ai/v1/media/uploads", &buf)
	if err != nil {
		panic(err)
	}
	req.Header.Set("Content-Type", writer.FormDataContentType())
	req.Header.Set("Authorization", "Bearer "+os.Getenv("NOQTE_MEDIA_KEY"))

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()
	data, _ := io.ReadAll(res.Body)
	fmt.Println(res.StatusCode, string(data))
}

پاسخ201

201 application/json
{
  "asset": {
    "id": "5b8e1c4d7a2f4e9b8c3d6a1f0e7b2c9d",
    "kind": "image",
    "name": "reference.png",
    "size_bytes": 184204,
    "duration_seconds": null
  }
}
POST/v1/media/generationsscope: media:generate

ارسال تولید

درخواست را می‌پذیرد، هزینه را کسر می‌کند و شناسهٔ پیگیری برمی‌گرداند (202).

پذیرش غیرهم‌زمان است: پاسخ 202 یعنی درخواست قبول شد، نه اینکه خروجی آماده است. مسیر پیگیری در هدر Location و فیلد poll_after_seconds می‌آید.

max_credits سقف رضایت شما برای همین عملیات است؛ اگر قیمت واقعی از آن بیشتر باشد، پاسخ 409 است و چیزی کسر نمی‌شود.

  • هدرها
  • Idempotency-Keystring (8–200)الزامی

    شناسهٔ یکتای این عملیات. تکرار همان شناسه با همان بدنه، همان تولید را بدون هزینهٔ دوباره برمی‌گرداند (replayed: true).

  • بدنهٔ JSON
  • model_slugstringالزامی

    شناسهٔ دقیق مدل از کاتالوگ (slug). نام نمایشی یا auto پذیرفته نمی‌شود.

  • promptstringالزامی

    متن درخواست. سقف کاراکتر هر مدل در prompt_max_chars است؛ برای مدل‌های prompt_optional می‌تواند خالی باشد.

  • paramsobject<string, string>

    گزینه‌های مدل؛ کلید = نام گروه، مقدار = id یکی از گزینه‌های همان گروه. گزینهٔ ناشناخته خطای 422 می‌دهد.

  • textsobject<string, string>

    متن‌های تکمیلی مدل (مثل ترانه). فقط کلیدهای اعلام‌شده در text_inputs.

  • refsstring[]

    شناسهٔ فایل‌های مرجع عمومی (asset.id از آپلود).

  • ref_slotsobject<string, string[]>

    فایل‌های نقش‌دار؛ کلید = key یکی از input_slots مدل.

  • ref_rolesobject<string, "first" | "last">

    نقش فریم برای هر شناسهٔ حاضر در refs؛ فقط برای مدل‌هایی که frame_contract دارند.

  • max_creditsinteger ≥ 1الزامی

    حداکثر کردیتی که برای این درخواست می‌پذیرید. مقدار برآورد یا بیشتر از آن.

نمونهٔ درخواست

curl -sS "https://api.noqte.ai/v1/media/generations" \
  -H "Authorization: Bearer $NOQTE_MEDIA_KEY" \
  -H "Idempotency-Key: order-1042-cover-v1" \
  -H "Content-Type: application/json" \
  -d '{
  "model_slug": "gpt-image-2",
  "prompt": "A calm cinematic scene at sunrise, soft light",
  "params": {
    "size": "1:1",
    "quality": "low"
  },
  "max_credits": 20
}'
import os
import requests

BASE = "https://api.noqte.ai/v1/media"
HEADERS = {"Authorization": f"Bearer {os.environ['NOQTE_MEDIA_KEY']}"}

payload = {
    "model_slug": "gpt-image-2",
    "prompt": "A calm cinematic scene at sunrise, soft light",
    "params": {
        "size": "1:1",
        "quality": "low",
    },
    "max_credits": 20,
}

response = requests.post(
    f"{BASE}/generations",
    json=payload,
    headers={**HEADERS, "Idempotency-Key": "order-1042-cover-v1"},
    timeout=60,
)
data = response.json()
if not response.ok:
    raise RuntimeError(f"{response.status_code} {data['error']['code']}: {data['error']['message']}")
print(data)
const BASE = "https://api.noqte.ai/v1/media";
const headers = { Authorization: `Bearer ${process.env.NOQTE_MEDIA_KEY}` };

const response = await fetch(`${BASE}/generations`, {
  method: "POST",
  headers: { ...headers, "Content-Type": "application/json", "Idempotency-Key": "order-1042-cover-v1" },
  body: JSON.stringify({
    model_slug: "gpt-image-2",
    prompt: "A calm cinematic scene at sunrise, soft light",
    params: {
      size: "1:1",
      quality: "low"
    },
    max_credits: 20
  }),
});
const data = await response.json();
if (!response.ok) throw new Error(`${response.status} ${data.error.code}: ${data.error.message}`);
console.log(data);
<?php
$base = "https://api.noqte.ai/v1/media";
$headers = [
    "Authorization: Bearer " . getenv("NOQTE_MEDIA_KEY"),
    "Idempotency-Key: order-1042-cover-v1",
    "Content-Type: application/json",
];

$payload = [
    "model_slug" => "gpt-image-2",
    "prompt" => "A calm cinematic scene at sunrise, soft light",
    "params" => [
        "size" => "1:1",
        "quality" => "low",
    ],
    "max_credits" => 20,
];

$ch = curl_init("$base/generations");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => $headers,
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => json_encode($payload, JSON_UNESCAPED_UNICODE),
]);

$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

$data = json_decode($body, true);
if ($status >= 400) {
    throw new RuntimeException("$status {$data['error']['code']}: {$data['error']['message']}");
}
print_r($data);
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"strings"
)

func main() {
	payload := `{
	  "model_slug": "gpt-image-2",
	  "prompt": "A calm cinematic scene at sunrise, soft light",
	  "params": {
	    "size": "1:1",
	    "quality": "low"
	  },
	  "max_credits": 20
	}`

	req, err := http.NewRequest("POST", "https://api.noqte.ai/v1/media/generations", strings.NewReader(payload))
	if err != nil {
		panic(err)
	}
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", "Bearer "+os.Getenv("NOQTE_MEDIA_KEY"))
	req.Header.Set("Idempotency-Key", "order-1042-cover-v1")

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()
	data, _ := io.ReadAll(res.Body)
	fmt.Println(res.StatusCode, string(data))
}

پاسخ202Location: /v1/media/generations/{generation_id} · Retry-After: 5

202 application/json
{
  "request_id": "req_9f1c2d3e4a5b6c7d8e9f0a1b2c3d4e5f",
  "generation": {
    "id": "0f3a9c2e7b1d4a6c8e5f2b9d1c7a3e4f",
    "request_id": "req_9f1c2d3e4a5b6c7d8e9f0a1b2c3d4e5f",
    "api_key_id": 51,
    "kind": "image",
    "model_slug": "gpt-image-2",
    "prompt": "A calm cinematic scene at sunrise, soft light",
    "params": {
      "size": "1:1",
      "quality": "low"
    },
    "texts": {},
    "status": "pending",
    "created_at": "2026-09-05T10:00:00+00:00",
    "completed_at": null,
    "charged_credits": 12,
    "refunded_credits": 0,
    "net_credits": 12,
    "billing_status": "charged",
    "outputs": [],
    "error": null
  },
  "replayed": false,
  "poll_after_seconds": 5
}
GET/v1/media/generations/{generation_id}scope: media:read

وضعیت و خروجی تولید

وضعیت، هزینه و لینک خروجی‌های یک تولید.

تا وقتی status برابر pending یا running است هر poll_after_seconds ثانیه دوباره بخوانید. تولید ناموفق هم با HTTP 200 برمی‌گردد؛ موفقیت HTTP را با موفقیت تولید اشتباه نگیرید.

لینک‌های outputs[].url امضاشده و زمان‌دار (حدود یک ساعت) هستند. برای لینک تازه، همین مسیر را دوباره بخوانید.

  • پارامترهای مسیر
  • generation_idstringالزامی

    generation.id از پاسخ ارسال.

نمونهٔ درخواست

curl -sS "https://api.noqte.ai/v1/media/generations/0f3a9c2e7b1d4a6c8e5f2b9d1c7a3e4f" \
  -H "Authorization: Bearer $NOQTE_MEDIA_KEY"
import os
import requests

BASE = "https://api.noqte.ai/v1/media"
HEADERS = {"Authorization": f"Bearer {os.environ['NOQTE_MEDIA_KEY']}"}

response = requests.get(
    f"{BASE}/generations/0f3a9c2e7b1d4a6c8e5f2b9d1c7a3e4f",
    headers=HEADERS,
    timeout=30,
)
data = response.json()
if not response.ok:
    raise RuntimeError(f"{response.status_code} {data['error']['code']}: {data['error']['message']}")
print(data)
const BASE = "https://api.noqte.ai/v1/media";
const headers = { Authorization: `Bearer ${process.env.NOQTE_MEDIA_KEY}` };

const response = await fetch(`${BASE}/generations/0f3a9c2e7b1d4a6c8e5f2b9d1c7a3e4f`, { headers });
const data = await response.json();
if (!response.ok) throw new Error(`${response.status} ${data.error.code}: ${data.error.message}`);
console.log(data);
<?php
$base = "https://api.noqte.ai/v1/media";
$headers = [
    "Authorization: Bearer " . getenv("NOQTE_MEDIA_KEY"),
];

$ch = curl_init("$base/generations/0f3a9c2e7b1d4a6c8e5f2b9d1c7a3e4f");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => $headers,
]);

$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

$data = json_decode($body, true);
if ($status >= 400) {
    throw new RuntimeException("$status {$data['error']['code']}: {$data['error']['message']}");
}
print_r($data);
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
)

func main() {
	req, err := http.NewRequest("GET", "https://api.noqte.ai/v1/media/generations/0f3a9c2e7b1d4a6c8e5f2b9d1c7a3e4f", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("Authorization", "Bearer "+os.Getenv("NOQTE_MEDIA_KEY"))

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()
	data, _ := io.ReadAll(res.Body)
	fmt.Println(res.StatusCode, string(data))
}

پاسخ200

200 application/json
{
  "generation": {
    "id": "0f3a9c2e7b1d4a6c8e5f2b9d1c7a3e4f",
    "request_id": "req_9f1c2d3e4a5b6c7d8e9f0a1b2c3d4e5f",
    "api_key_id": 51,
    "kind": "image",
    "model_slug": "gpt-image-2",
    "prompt": "A calm cinematic scene at sunrise, soft light",
    "params": {
      "size": "1:1",
      "quality": "low"
    },
    "texts": {},
    "status": "completed",
    "created_at": "2026-09-05T10:00:00+00:00",
    "completed_at": "2026-09-05T10:00:41+00:00",
    "charged_credits": 12,
    "refunded_credits": 0,
    "net_credits": 12,
    "billing_status": "charged",
    "outputs": [
      {
        "id": "0f3a9c2e7b1d4a6c8e5f2b9d1c7a3e4f:0",
        "url": "https://api.noqte.ai/v1/media/outputs/0f3a9c2e7b1d4a6c8e5f2b9d1c7a3e4f/api-output.png?sig=…&exp=…",
        "kind": "image",
        "mime_type": "image/png",
        "title": null,
        "duration_seconds": null,
        "cover_url": null
      }
    ],
    "error": null
  },
  "poll_after_seconds": null
}
GET/v1/media/generationsscope: media:read

تاریخچهٔ تولیدها

فهرست صفحه‌بندی‌شدهٔ تولیدهای همین کلید، از جدید به قدیم.

برای صفحهٔ بعد، next_cursor را بدون تغییر در cursor بفرستید. from شامل و to غیرشامل است.

  • پارامترهای query
  • kind"image" | "video" | "music" | "3d"

    فیلتر نوع.

  • status"pending" | "running" | "completed" | "failed"

    فیلتر وضعیت.

  • model_slugstring

    فیلتر مدل.

  • fromISO 8601

    از این زمان (شامل).

  • toISO 8601

    تا این زمان (غیرشامل).

  • limitinteger 1–100

    پیش‌فرض ۳۰.

  • cursorstring

    مقدار next_cursor صفحهٔ قبل.

نمونهٔ درخواست

curl -sS "https://api.noqte.ai/v1/media/generations?status=completed&limit=20" \
  -H "Authorization: Bearer $NOQTE_MEDIA_KEY"
import os
import requests

BASE = "https://api.noqte.ai/v1/media"
HEADERS = {"Authorization": f"Bearer {os.environ['NOQTE_MEDIA_KEY']}"}

response = requests.get(
    f"{BASE}/generations",
    params={"status": "completed", "limit": "20"},
    headers=HEADERS,
    timeout=30,
)
data = response.json()
if not response.ok:
    raise RuntimeError(f"{response.status_code} {data['error']['code']}: {data['error']['message']}")
print(data)
const BASE = "https://api.noqte.ai/v1/media";
const headers = { Authorization: `Bearer ${process.env.NOQTE_MEDIA_KEY}` };

const response = await fetch(`${BASE}/generations?status=completed&limit=20`, { headers });
const data = await response.json();
if (!response.ok) throw new Error(`${response.status} ${data.error.code}: ${data.error.message}`);
console.log(data);
<?php
$base = "https://api.noqte.ai/v1/media";
$headers = [
    "Authorization: Bearer " . getenv("NOQTE_MEDIA_KEY"),
];

$ch = curl_init("$base/generations?status=completed&limit=20");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => $headers,
]);

$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

$data = json_decode($body, true);
if ($status >= 400) {
    throw new RuntimeException("$status {$data['error']['code']}: {$data['error']['message']}");
}
print_r($data);
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
)

func main() {
	req, err := http.NewRequest("GET", "https://api.noqte.ai/v1/media/generations?status=completed&limit=20", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("Authorization", "Bearer "+os.Getenv("NOQTE_MEDIA_KEY"))

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()
	data, _ := io.ReadAll(res.Body)
	fmt.Println(res.StatusCode, string(data))
}

پاسخ200

200 application/json
{
  "generations": [
    {
      "id": "0f3a9c2e7b1d4a6c8e5f2b9d1c7a3e4f",
      "request_id": "req_9f1c2d3e4a5b6c7d8e9f0a1b2c3d4e5f",
      "api_key_id": 51,
      "kind": "image",
      "model_slug": "gpt-image-2",
      "prompt": "A calm cinematic scene at sunrise, soft light",
      "params": {
        "size": "1:1",
        "quality": "low"
      },
      "texts": {},
      "status": "completed",
      "created_at": "2026-09-05T10:00:00+00:00",
      "completed_at": "2026-09-05T10:00:41+00:00",
      "charged_credits": 12,
      "refunded_credits": 0,
      "net_credits": 12,
      "billing_status": "charged",
      "outputs": [
        {
          "id": "0f3a9c2e7b1d4a6c8e5f2b9d1c7a3e4f:0",
          "url": "https://api.noqte.ai/v1/media/outputs/0f3a9c2e7b1d4a6c8e5f2b9d1c7a3e4f/api-output.png?sig=…&exp=…",
          "kind": "image",
          "mime_type": "image/png",
          "title": null,
          "duration_seconds": null,
          "cover_url": null
        }
      ],
      "error": null
    }
  ],
  "next_cursor": "WyIyMDI2LTA5LTA1VDEwOjAwOjAwKzAwOjAwIiwgIi4uLiJd"
}
GET/v1/media/usagescope: usage:read

مصرف و سقف‌ها

مصرف خالص این کلید، موجودی کیف پول و محدودیت‌های حساب.

daily_used با مرز نیمه‌شب تهران بازنشانی می‌شود (daily_reset_at). سقف‌های null یعنی بدون سقف اضافه.

نمونهٔ درخواست

curl -sS "https://api.noqte.ai/v1/media/usage" \
  -H "Authorization: Bearer $NOQTE_MEDIA_KEY"
import os
import requests

BASE = "https://api.noqte.ai/v1/media"
HEADERS = {"Authorization": f"Bearer {os.environ['NOQTE_MEDIA_KEY']}"}

response = requests.get(
    f"{BASE}/usage",
    headers=HEADERS,
    timeout=30,
)
data = response.json()
if not response.ok:
    raise RuntimeError(f"{response.status_code} {data['error']['code']}: {data['error']['message']}")
print(data)
const BASE = "https://api.noqte.ai/v1/media";
const headers = { Authorization: `Bearer ${process.env.NOQTE_MEDIA_KEY}` };

const response = await fetch(`${BASE}/usage`, { headers });
const data = await response.json();
if (!response.ok) throw new Error(`${response.status} ${data.error.code}: ${data.error.message}`);
console.log(data);
<?php
$base = "https://api.noqte.ai/v1/media";
$headers = [
    "Authorization: Bearer " . getenv("NOQTE_MEDIA_KEY"),
];

$ch = curl_init("$base/usage");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => $headers,
]);

$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

$data = json_decode($body, true);
if ($status >= 400) {
    throw new RuntimeException("$status {$data['error']['code']}: {$data['error']['message']}");
}
print_r($data);
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
)

func main() {
	req, err := http.NewRequest("GET", "https://api.noqte.ai/v1/media/usage", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("Authorization", "Bearer "+os.Getenv("NOQTE_MEDIA_KEY"))

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()
	data, _ := io.ReadAll(res.Body)
	fmt.Println(res.StatusCode, string(data))
}

پاسخ200

200 application/json
{
  "generations": 18,
  "charged_credits": 240,
  "refunded_credits": 12,
  "net_credits": 228,
  "daily_used": 36,
  "inflight": 1,
  "daily_reset_at": "2026-09-05T20:30:00+00:00",
  "wallet_balance": 480,
  "billing_source": "wallet",
  "daily_free_credits_eligible": false,
  "limits": {
    "max_api_keys": 2,
    "account_rpm_limit": 10,
    "max_inflight": 2,
    "daily_credit_limit": null,
    "key_daily_credit_limit": 50,
    "key_total_credit_limit": null
  }
}

06 · Generation object

شیء Generation

همان شیئی که در پاسخ ارسال، وضعیت و تاریخچه برمی‌گردد. وضعیت مالی مستقل از وضعیت تولید است.

  • فیلدها
  • idstring

    شناسهٔ تولید؛ در مسیر وضعیت استفاده می‌شود.

  • request_idstring

    شناسهٔ درخواست HTTP پذیرش؛ برای پشتیبانی همین را بفرستید.

  • statusstring

    pending · running · completed · failed

  • kind / model_slugstring

    نوع و مدل تولید.

  • prompt / params / texts

    ورودی پذیرفته‌شده، همان‌طور که فرستاده‌اید.

  • charged_creditsinteger

    کسر اولیه از کیف پول (تغییر نمی‌کند).

  • refunded_creditsinteger

    مبلغ برگشتی تا این لحظه.

  • net_creditsinteger

    هزینهٔ خالص = charged − refunded.

  • billing_statusstring

    مستقل از status؛ جدول پایین.

  • outputs[]object[]

    id، url (امضاشده و زمان‌دار)، kind، mime_type، title، duration_seconds، cover_url.

  • errorobject | null

    code، message، retryable، param — فقط در failed.

  • created_at / completed_atISO 8601

    زمان پذیرش و پایان.

status
pendingپذیرفته شده، در صف
runningدر حال تولید
completedخروجی آماده است؛ outputs را بخوانید
failedناموفق؛ error و billing_status را بررسی کنید
billing_status
chargedهزینه از کیف پول کسر شده و تولید در جریان یا کامل است
partially_refundedبخشی از خروجی تحویل نشد و همان بخش برگشت داده شد
refund_pendingتولید شکست خورده و بازگشت کردیت هنوز تسویه نشده است
refundedکل هزینه به کیف پول برگشته است

07 · Idempotency

تکرار امن با Idempotency-Key

هدر Idempotency-Key روی ارسال تولید اجباری است (۸ تا ۲۰۰ کاراکتر). برای هر عملیات منطقی یک شناسه بسازید و همراه بدنه پیش از ارسال ذخیره کنید.

  • در timeout یا قطع اتصال، همان شناسه و همان بدنه را دوباره بفرستید: همان تولید با replayed: true برمی‌گردد و هزینهٔ دوباره ندارد.
  • همان شناسه با بدنهٔ متفاوت (حتی تغییر max_credits) خطای 409 می‌دهد.
  • شناسه به حساب و کلید محدود است و تا وقتی رکورد تولید هست معتبر می‌ماند؛ برای تولید واقعاً جدید شناسهٔ تازه بسازید.
  • برای درخواست‌های GET و برآورد نیازی به شناسه نیست.

08 · Errors

خطاها

همهٔ خطاها یک ساختار دارند. request_id (و هدر X-Request-ID) را برای پشتیبانی نگه دارید؛ کلید API را هرگز نفرستید.

4xx / 5xx application/json
{
  "request_id": "req_9f1c2d3e4a5b6c7d8e9f0a1b2c3d4e5f",
  "error": {
    "code": "invalid_parameters",
    "message": "ورودی با قرارداد API سازگار نیست.",
    "retryable": false,
    "param": "body.params.aspect_ratio"
  }
}
  • 401invalid_api_key

    کلید نامعتبر، لغوشده یا منقضی است

    کلید را از پنل بررسی یا کلید تازه بسازید

  • 402insufficient_credits

    کیف پول یا سقف کردیت کلید/حساب کافی نیست

    کیف پول را شارژ یا سقف کلید را بالا ببرید

  • 403scope_not_allowed

    دسترسی، مدل، IP یا سیاست حساب اجازه نمی‌دهد

    دسترسی‌ها و فهرست مدل‌های مجاز کلید را در پنل ویرایش کنید

  • 404model_not_found

    مدل فعال با این شناسه وجود ندارد

    شناسه را از GET /v1/media/models بردارید

  • 404asset_not_found

    یک یا چند فایل مرجع متعلق به این حساب نیست

    فایل را با همین کلید آپلود و از asset.id استفاده کنید

  • 404generation_not_found

    تولید در محدودهٔ این کلید پیدا نشد

    هر کلید فقط تولیدهای خودش را می‌بیند

  • 409conflict

    تکرار Idempotency-Key با ورودی متفاوت، قیمت بالاتر از max_credits یا تغییر قرارداد مدل

    دوباره برآورد بگیرید؛ برای تولید جدید شناسهٔ جدید بسازید

  • 413request_too_large

    بدنهٔ JSON بزرگ‌تر از ۱ مگابایت است

    فایل‌ها را با /uploads بفرستید، نه داخل JSON

  • 413upload_too_large

    حجم فایل بیش از سقف مدل است

    فایل را مطابق max_mb مدل کوچک کنید

  • 422invalid_parameters

    ورودی با قرارداد مدل سازگار نیست (فیلد param مسیر خطا را می‌گوید)

    گزینه‌ها و متن‌های مجاز را از کاتالوگ بخوانید

  • 422invalid_reference

    شناسهٔ مرجع باید asset.id سی‌ودو کاراکتری آپلود باشد

    URL یا مسیر فایل پذیرفته نمی‌شود

  • 422invalid_cursor

    مقدار cursor دست‌کاری شده است

    next_cursor را بدون تغییر برگردانید

  • 429rate_limit_exceededretryable

    محدودیت نرخ یا سقف تولید هم‌زمان

    به اندازهٔ هدر Retry-After صبر کنید

  • 503media_unavailableretryable

    پذیرش تولید موقتاً متوقف است

    بعداً با همان Idempotency-Key تکرار کنید

  • 503api_errorretryable

    خطای داخلی؛ وضعیت درخواست نامعلوم است

    همان شناسهٔ تکرار را نگه دارید و دوباره بفرستید

خطای خود تولید (مثلاً شکست مدل) در بدنهٔ 200 مسیر وضعیت و در فیلد generation.error با کد generation_failed می‌آید و کردیت آن مطابق billing_status برمی‌گردد.

09 · Limits

محدودیت‌ها

ارسال و آپلود
۱۰ درخواست در دقیقه
تولید هم‌زمان
۲ تولید
کلید فعال
۲ کلید
خواندن
۱۲۰ درخواست در دقیقه

این مقادیر پیش‌فرض حساب‌های عادی است؛ مقدار دقیق حساب خودتان در پاسخ GET /v1/media/usage می‌آید.

  • بدنهٔ JSON حداکثر ۱ مگابایت؛ فایل‌ها فقط از مسیر /uploads و با سقف حجم همان مدل.
  • سقف طول پرامپت و متن‌ها را از prompt_max_chars و text_inputs[].max_chars مدل بخوانید.
  • لینک خروجی حدود یک ساعت معتبر است؛ برای لینک تازه، جزئیات تولید را دوباره بخوانید و لینک را دائمی فرض نکنید.
  • سقف کردیت روزانهٔ کلید با مرز نیمه‌شب تهران بازنشانی می‌شود؛ سقف کل کلید بازنشانی ندارد.
  • اعتبار رایگان روزانهٔ حساب در API مصرف نمی‌شود؛ فقط موجودی پایدار کیف پول.
  • نسخهٔ فعلی endpoint لغو، webhook یا streaming ندارد؛ وضعیت را poll کنید.

10 · Models

مدل‌ها و شناسه‌ها

مقدار model_slug باید دقیقاً یکی از شناسه‌های زیر باشد. صفحهٔ هر مدل، گروه‌های گزینه، مقدارهای مجاز و نمونهٔ درخواست همان مدل را دارد؛ مرجع زندهٔ قیمت و قرارداد، پاسخ /v1/media/models است.

عکس(۱۱ مدل · kind=image)

GPT Image 2جی‌پی‌تی ایمیج ۲gpt-image-2درک دقیق دستور، متن داخل تصویر و ویرایش چندمرجعی با ابعاد انعطاف‌پذیر.قراردادSeedream 5.0 Proسیدریم ۵ پروseedream-5-proجدیدترین مدل پرچم‌دار بایت‌دنس برای تولید و ویرایش کنترل‌شده.قراردادNano Banana 2 Liteنانو بنانا ۲ لایتnano-banana-2-liteمدل جدید و سریع گوگل برای تصویر و ویرایش با مرجع.قراردادSeedream 5.0 Liteسیدریم ۵ لایتseedream-5-liteخروجی 2K و 3K با قیمت ثابت و پشتیبانی از چند تصویر مرجع.قراردادGrok Imagine Image Qualityگراک ایمجین ایمیجgrok-imagine-image-qualityتولید و ویرایش تصویر xAI در دو سطح 1K و 2K.قراردادNano Banana 2نانو بنانا ۲nano-banana-2ویرایش دقیق، ثبات سوژه و خروجی تا 4K.قراردادImagineArt 2.0ایمجین‌آرت ۲imagineart-2تصویر 2K با دو سطح پردازش و نسبت‌های رسمی مدل.قراردادNano Banana Proنانو بنانا پروnano-banana-proنسخهٔ حرفه‌ای گوگل برای ترکیب چند مرجع، متن دقیق داخل تصویر و خروجی تا 4K.قراردادTopaz Image Upscaleتاپاز افزایش کیفیت عکسtopaz-image-upscaleافزایش وضوح، بازسازی جزئیات و کاهش تاری عکس با بزرگ‌نمایی ۱، ۲ یا ۴ برابر و حفظ کادر اصلی.قراردادP-Image Upscaleپی ایمیج آپ‌اسکیلp-image-upscaleبزرگ‌کردن تصویر تا 8 مگاپیکسل با قیمت دقیق هر بازه.قراردادP-Image Try-Onپی ایمیج پرو مجازیp-image-try-onپرو مجازی با ورودی جداگانه شخص، لباس‌ها و ژست اختیاری.قرارداد

ویدئو(۲۵ مدل · kind=video)

Omni Flash 1.1اومنی فلش ۱.۱gemini-omni-flash-1-1تولید و ادامهٔ ویدیوی چندورودی با صدای بومی تا طول تجمعی ۴۰ ثانیه؛ فریم شروع/پایان و خروجی تا 4K.قراردادGemini Omni Flashجمینای اومنی فلشgemini-omni-flashتولید ویدیوی صدا‌دار با درک مستقیم پرامپت و دیالوگ فارسی.قراردادWan 3.0 Video Primeوان ۳ ویدیو پرایمwan-3-video-primeنسخهٔ سریع Wan 3 برای ساخت ویدیوی صدا‌دار تا ۳۰ ثانیه با تصویر، ویدیو و صوت مرجع و فریم شروع و پایان.قراردادSeedance 2.5سیدنس ۲.۵seedance-2-5نسل تازه Seedance برای ساخت ویدیوی صدا‌دار تا ۳۰ ثانیه با مرجع‌های تصویر، ویدیو و صوت.قراردادWan 3.0 Videoوان ۳ ویدیوwan-3-videoمدل استاندارد Wan 3 برای ساخت ویدیوی صدا‌دار تا ۳۰ ثانیه با تصویر، ویدیو و صوت مرجع و فریم شروع و پایان.قراردادMiniMax H3مینی‌مکس H3minimax-h3ساخت، جان‌بخشی و ویرایش ویدیوی 2K با حرکت طبیعی و صدای هماهنگ.قراردادFLUX 3 VideoFLUX 3 Videoflux-3-videoساخت و ادامه ویدیوی 720p یا 1080p با صدای هماهنگ و کنترل فریم‌های شروع و پایان.قراردادGrok Imagine Videoگراک ایمجین ویدیوgrok-imagine-videoتولید سریع ویدیوی صدا‌دار از متن یا تصویر با Grok.قراردادGrok Imagine Video 1.5گراک ایمجین ویدیو ۱.۵grok-imagine-video-1-5نسخه جدید Grok برای جان‌بخشی به تصویر با خروجی تا 1080p.قراردادSeedance 2.0 Miniسیدنس ۲ مینیseedance-2-miniمدل جدید و اقتصادی بایت‌دنس برای ایده‌پردازی سریع.قراردادVeo 3.1 Liteویو ۳.۱ لایتveo-3-1-liteنسخه اقتصادی Veo با صدای همگام و خروجی 720p یا 1080p.قراردادLip Syncلیپ سینکlip-syncهماهنگ‌سازی طبیعی حرکت لب و حالت چهره با صدای جدید روی ویدیوی موجود؛ مناسب دوبله و بیش از ۹۵ زبان.قراردادWan2.7وان ۲.۷wan-2-7مدل جدید Wan برای ویدیوی صدا‌دار 720p و 1080p.قراردادSeedance 2.0 Fastسیدنس ۲ سریعseedance-2-fastنسخه سریع Seedance 2 برای ویدیوی صدا‌دار تا 720p.قراردادKling 3.0 Standardکلینگ ۳ استانداردkling-3-standardحرکت پایدار و صدای بومی برای کلیپ‌های 3 تا 15 ثانیه.قراردادSeedance 2.0سیدنس ۲seedance-2مدل کامل Seedance 2 با صدای بومی و خروجی تا 4K.قراردادKling VIDEO 3.0 Turboکلینگ ۳ توربوkling-3-turboنسخه جدید و سریع Kling با صدای بومی و کیفیت تا 1080p.قراردادKling VIDEO 3.0 Proکلینگ ۳ پروkling-3-proKling حرفه‌ای 1080p با فریم شروع/پایان و صدای اختیاری.قراردادKling VIDEO 3.0 Omni Proکلینگ ۳ اومنی پروkling-3-omni-proنسخه Omni حرفه‌ای Kling با درک چندمرجع و خروجی 1080p.قراردادRunway Gen-4.5ران‌وی نسل ۴.۵runway-gen-4-5مدل سینمایی Runway برای متن یا تصویر به ویدیوی 720p.قراردادVeo 3.1ویو ۳.۱veo-3-1نسخه کامل Veo با صدای همگام و کنترل فریم شروع در 720p.قراردادKling VIDEO 3.0 4Kکلینگ ۳ چهار کیkling-3-4kخروجی واقعی 4K از Kling با فریم‌های راهنما و صدای اختیاری.قراردادKling VIDEO 3.0 Omni 4Kکلینگ ۳ اومنی چهار کیkling-3-omni-4kنسخه Omni چهار کی Kling برای کنترل مرجع و جزئیات حداکثری.قراردادRunway Aleph 2.0ران‌وی الف ۲runway-aleph-2ویرایش ویدیوی موجود با پرامپت: تعویض سوژه، نور، پس‌زمینه و استایل.قراردادTopaz Video Upscalerتاپاز افزایش کیفیت ویدیوtopaz-video-upscaleافزایش وضوح ویدیو، کاهش نویز و بازسازی جزئیات با حفظ نسبت تصویر و مدت فایل اصلی.قرارداد

مدل سه‌بعدی(۵ مدل · kind=3d)

11 · Tooling

Postman و OpenAPI

مجموعهٔ Postman (نسخهٔ 2.1) شامل هر هفت endpoint با نمونهٔ بدنه و پاسخ است و در Insomnia، Bruno و Hoppscotch هم import می‌شود. پس از import، متغیر apiKey را با کلید خود پر کنید؛ baseUrl از پیش تنظیم شده است. ارسال تولید به‌طور خودکار generationId را ذخیره می‌کند تا مسیر وضعیت بدون کپی دستی کار کند.

12 · FAQ

پرسش‌های پرتکرار توسعه‌دهندگان

برای استفاده از API به اشتراک پرو نیاز دارم؟

نه. کلید تولید محتوا مستقل از پلن حساب ساخته می‌شود و هزینهٔ هر درخواست از کردیت کیف پول کسر می‌شود. کافی است کیف پول شارژ باشد و کلید، دسترسی media:generate داشته باشد.

هزینهٔ هر درخواست چطور محاسبه می‌شود؟

قیمت پایهٔ هر مدل و اثر هر گزینه در کاتالوگ اعلام می‌شود، ولی مرجع نهایی endpoint برآورد است: همان بدنهٔ تولید را بدون max_credits بفرستید تا قیمت دقیق همان ورودی برگردد. برآورد رزرو نیست و کردیتی کسر نمی‌کند.

اگر همان درخواست را دوباره بفرستم دوبار هزینه می‌شود؟

نه، به شرطی که همان Idempotency-Key و همان بدنه را بفرستید؛ در این حالت همان تولید با replayed برابر true برمی‌گردد. همان شناسه با بدنهٔ متفاوت خطای 409 می‌دهد و برای تولید واقعاً جدید باید شناسهٔ تازه بسازید.

محدودیت نرخ درخواست‌ها چقدر است؟

ارسال تولید و آپلود فایل به‌صورت پیش‌فرض ۱۰ درخواست در دقیقه و خواندن ۱۲۰ درخواست در دقیقه است، با سقف پیش‌فرض دو تولید هم‌زمان. عبور از سقف پاسخ 429 با هدر Retry-After می‌گیرد؛ به همان اندازه صبر کنید و با همان Idempotency-Key تکرار کنید.

لینک خروجی تا کی معتبر است؟

لینک‌های خروجی امضاشده و زمان‌دار هستند و حدود یک ساعت اعتبار دارند. آن‌ها را دائمی فرض نکنید؛ برای لینک تازه، جزئیات همان تولید را دوباره بخوانید یا فایل را در فضای ذخیره‌سازی خودتان نگه دارید.

اگر تولید شکست بخورد کردیت برمی‌گردد؟

بله. وضعیت مالی مستقل از وضعیت تولید گزارش می‌شود: کسر اولیه، بازگشت جزئی، بازگشت در انتظار تسویه و بازگشت کامل. تولید ناموفق هم با HTTP 200 برمی‌گردد، پس موفقیت HTTP را با موفقیت تولید یکی نگیرید.

کلید مدل زبانی با کلید تولید محتوا فرق دارد؟

بله، دو نوع کلید جدا هستند. این API فقط کلید تولید محتوا را می‌پذیرد و کلید مدل زبانی در آن کار نمی‌کند. هر کلید هم فقط تولیدهای خودش را می‌بیند.

webhook یا streaming دارید؟

در نسخهٔ فعلی نه. پذیرش غیرهم‌زمان است: پاسخ 202 یعنی درخواست قبول شد و بعد وضعیت را هر چند ثانیه یک‌بار می‌خوانید تا completed یا failed شود. endpoint لغو هم هنوز وجود ندارد.

کلید بسازید و اولین تولید را بفرستید

کلید تولید محتوا در چند ثانیه ساخته می‌شود، دسترسی‌ها و سقف کردیت آن قابل تنظیم است و هزینه از کیف پول همان حساب کسر می‌شود.

ساخت کلید API