API Reference

SharkAPI Documentation

Complete reference for the SharkAPI image generation API. Generate 1024×1024 AI images asynchronously — submit a job, poll for the result.

Overview

SharkAPI is an asynchronous image generation API. You submit a prompt (and optionally a reference image), receive a job_id immediately, then poll every 2 seconds until your image is ready. Generation typically takes 30–120 seconds.

Billing is wallet-based — you load credit in advance and are charged only when a job successfully completes with an image. Failed jobs are never charged.

3 free trial generations are included with every new account. No credit card required to start.

Base URL

text
https://www.sharkapi.dev

All endpoints are under this base URL. Always use HTTPS.

Authentication

Every request must include your API key in the X-API-Key header. Get your key from Dashboard → API Tokens.

Required header
http
X-API-Key: sk_live_your_token_here
Store keys in environment variables — never hardcode in source files.
Never expose keys in browser/client-side JavaScript.
Create a separate key per project or environment.
Revoke a key immediately if you suspect it has been leaked.
The full key is shown only once — copy it right after creation.
ParameterTypeRequiredDescription
401 UnauthorizedHTTPOptionalX-API-Key header is missing or the key is invalid.
403 ForbiddenHTTPOptionalKey exists but has been revoked, or account is suspended.

How it works

Every image generation follows this async pattern:

1

POST /api/v1/image

Submit your prompt → receive job_id instantly (~200ms)

2

Worker picks up job

Background worker claims the job, starts generation (30–120s)

3

GET /api/v1/jobs/:id

Poll every 2 seconds — status moves from queued → processing

4

status: completed

image_url is ready. Wallet charged. Job done.

Quick start

Full flow in 2 commands
bash
# Step 1 — submit a job
curl -X POST https://www.sharkapi.dev/api/v1/image \
  -H "X-API-Key: sk_live_••••••••" \
  -H "Content-Type: application/json" \
  -d '{"prompt": "A great white shark in bioluminescent deep ocean, cinematic, 8K"}'

# → 202 Accepted
# { "job_id": "3a8f2c1d-...", "status": "queued", "poll_url": "/api/v1/jobs/3a8f2c1d-..." }

# Step 2 — poll every 2 seconds until completed
curl https://www.sharkapi.dev/api/v1/jobs/3a8f2c1d-... \
  -H "X-API-Key: sk_live_••••••••"

# → { "status": "completed", "image_url": "https://...supabase.co/.../generated-images/..." }

Pricing & wallet

1K Mode$0.03

1024 × 1024 px

Fast standard resolution. Currently available.

MOST POPULAR
2K Mode$0.05

2048 × 2048 px

High-resolution output.

COMING SOON
·Minimum wallet load: $10. Only multiples of $10 accepted ($10, $20, $50, $100…).
·Charged only on successful completion — failed or moderated jobs are always free.
·Wallet balance never expires.
·Payments processed securely via Stripe.

POST — Generate image

POSThttps://www.sharkapi.dev/api/v1/image

Submit an image generation job. Returns 202 Accepted with a job_id immediately. The job is processed asynchronously.

Request headers

ParameterTypeRequiredDescription
X-API-KeystringRequiredYour API key. Example: "sk_live_..."
Content-TypestringRequired"application/json"

Request body

ParameterTypeRequiredDescription
promptstringRequiredText description of the image to generate. Maximum 2000 characters.
variantstringOptionalResolution variant. Currently only "1k" (1024×1024) is available. Defaults to "1k" if omitted.
imagestringOptionalBase64-encoded reference image for image-to-image. JPEG, PNG, or WebP. Max 10 MB. Cannot be combined with image_url.
image_urlstringOptionalPublicly accessible URL of a reference image. Max 10 MB. Cannot be combined with image.
image and image_url are mutually exclusive. Send one or the other — never both in the same request.

Response — 202 Accepted

ParameterTypeRequiredDescription
job_idstringRequiredUnique job ID. Use this to poll for the result.
statusstringRequiredAlways "queued" on creation.
poll_urlstringRequiredRelative URL to poll: GET {poll_url}
price_usdnumberRequiredCost of this job in USD. Charged only on success.
created_atstringRequiredISO 8601 creation timestamp.
202 Response
json
{
  "job_id":     "3a8f2c1d-7b4e-4f9a-b2d6-1c5e8f3a9b7d",
  "status":     "queued",
  "poll_url":   "/api/v1/jobs/3a8f2c1d-7b4e-4f9a-b2d6-1c5e8f3a9b7d",
  "price_usd":  0.03,
  "created_at": "2025-01-15T10:23:44Z"
}

Text-only cURL

bash
curl -X POST https://www.sharkapi.dev/api/v1/image \
  -H "X-API-Key: sk_live_••••••••" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "A great white shark in bioluminescent deep ocean, cinematic, 8K",
    "variant": "1k"
  }'

Sending a reference image

To use image-to-image generation, attach a reference image using either base64 or a URL. We mirror all inputs to our own storage before sending to the generation engine — your original file is never exposed externally.

Option A — Base64

Encode your file as base64 and pass it in the image field. Both raw base64 and the data:image/...;base64, prefix format are accepted.

Base64 input
bash
# Encode your file to base64 first
IMAGE_B64=$(base64 -w 0 ./reference.jpg)   # Linux
# IMAGE_B64=$(base64 -i ./reference.jpg)   # macOS

curl -X POST https://www.sharkapi.dev/api/v1/image \
  -H "X-API-Key: sk_live_••••••••" \
  -H "Content-Type: application/json" \
  -d "{
    \"prompt\": \"Transform this into a watercolor painting\",
    \"image\": \"$IMAGE_B64\"
  }"

Option B — URL

Pass a publicly accessible URL in the image_url field. The URL must be reachable from our servers without authentication. For private images, use base64.

URL input
bash
curl -X POST https://www.sharkapi.dev/api/v1/image \
  -H "X-API-Key: sk_live_••••••••" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Transform this into a watercolor painting",
    "image_url": "https://your-cdn.com/photo.jpg"
  }'

GET — Job status

GEThttps://www.sharkapi.dev/api/v1/jobs/:id

Poll this endpoint every 2 seconds. Replace :id with the job_id from the generate response. Returns 200 OK with the current job state — check the status field to know if generation is done.

Request

ParameterTypeRequiredDescription
X-API-KeystringRequiredYour API key. Example: "sk_live_..."
:id (path)stringRequiredThe job_id from the POST response.
Poll request
bash
curl https://www.sharkapi.dev/api/v1/jobs/3a8f2c1d-7b4e-4f9a-b2d6-1c5e8f3a9b7d \
  -H "X-API-Key: sk_live_••••••••"

Response fields

ParameterTypeRequiredDescription
job_idstringRequiredJob identifier.
statusstringRequired"queued" | "processing" | "completed" | "failed"
image_urlstring | nullRequiredPermanent image URL. Set only when status is "completed".
coststring | nullRequiredFinal cost, e.g. "$0.03". Set only when status is "completed".
errorstring | nullRequiredError description when status is "failed". Null otherwise.
queued_atstringRequiredISO 8601 timestamp when job entered the queue.
started_atstring | nullRequiredISO 8601 timestamp when the worker began. Null if still queued.
completed_atstring | nullRequiredISO 8601 timestamp of completion. Null if not finished.
created_atstringRequiredISO 8601 timestamp of job creation.

While queued or processing

json
{
  "job_id":       "3a8f2c1d-7b4e-4f9a-b2d6-1c5e8f3a9b7d",
  "status":       "queued",
  "image_url":    null,
  "cost":         null,
  "error":        null,
  "queued_at":    "2025-01-15T10:23:44Z",
  "started_at":   null,
  "completed_at": null,
  "created_at":   "2025-01-15T10:23:44Z"
}

Completed — image ready

json
{
  "job_id":       "3a8f2c1d-7b4e-4f9a-b2d6-1c5e8f3a9b7d",
  "status":       "completed",
  "image_url":    "https://your-project.supabase.co/storage/v1/object/public/generated-images/user-id/3a8f2c1d-xxxx.png",
  "cost":         "$0.03",
  "error":        null,
  "queued_at":    "2025-01-15T10:23:44Z",
  "started_at":   "2025-01-15T10:23:46Z",
  "completed_at": "2025-01-15T10:24:18Z",
  "created_at":   "2025-01-15T10:23:44Z"
}

Failed — no charge applied

json
{
  "job_id":       "9b3c1a2d-4f8e-4c7b-a1e5-2d9f6b4a8c3e",
  "status":       "failed",
  "image_url":    null,
  "cost":         null,
  "error":        "Provider request timed out after 180s.",
  "queued_at":    "2025-01-15T10:30:00Z",
  "started_at":   "2025-01-15T10:30:02Z",
  "completed_at": null,
  "created_at":   "2025-01-15T10:30:00Z"
}

Job statuses

queued

Job received and waiting for the generation worker to pick it up.

processing

Worker is actively generating the image. Typically 30–120 seconds.

completed

Done. image_url is a permanent URL. Wallet has been charged.

failed

Generation failed (timeout or provider error). No charge. Safe to retry.

Poll every 2 seconds. Set a client-side timeout of 3 minutes — if a job is still not completed after that, it will be automatically marked failed with no charge.

Errors

All error responses are JSON with an error string field. Some errors also include a code field for programmatic handling.

Error response format
json
{
  "error": "Insufficient wallet balance."
}

// Some errors also include a machine-readable code:
{
  "error": "Insufficient wallet balance.",
  "code":  "INSUFFICIENT_BALANCE"
}
400

Bad request — missing or invalid body fields (e.g. no prompt, both image and image_url sent, image too large).

401

Unauthorized — X-API-Key header is missing or the key is invalid.

402

Payment required — wallet balance is below the cost of this request. Top up your account and retry.

403

Forbidden — API key has been revoked or account is suspended.

404

Not found — job ID does not exist or belongs to a different account.

422

Unprocessable — no active model for the requested variant. Only "1k" is currently available.

500

Server error — unexpected failure. Retry after a few seconds. Your wallet is not charged.

Retry 500 errors with exponential backoff (wait 2s, then 4s, then 8s). For 400/401/403/422 errors, fix the request before retrying. For 402, top up your wallet first.

Full examples

Each example below implements the complete flow: submit a job, poll until done, print the image URL.

JavaScript / Node.js

javascript
// ── SharkAPI — complete JavaScript / Node.js example ──────────────

const SHARKAPI_KEY = process.env.SHARKAPI_KEY; // sk_live_...
const BASE_URL     = "https://www.sharkapi.dev";

// 1. Submit a generation job
async function generateImage(prompt, options = {}) {
  const body = { prompt, variant: "1k" };

  // Optional: attach a reference image (base64 or URL, not both)
  if (options.imageBase64) body.image     = options.imageBase64;
  if (options.imageUrl)    body.image_url = options.imageUrl;

  const res = await fetch(`${BASE_URL}/api/v1/image`, {
    method: "POST",
    headers: {
      "X-API-Key": SHARKAPI_KEY,
      "Content-Type": "application/json",
    },
    body: JSON.stringify(body),
  });

  if (!res.ok) {
    const err = await res.json();
    throw new Error(err.error ?? `HTTP ${res.status}`);
  }

  return res.json(); // { job_id, status: "queued", poll_url, price_usd }
}

// 2. Poll until completed or failed
async function waitForJob(jobId, timeoutMs = 180_000) {
  const url      = `${BASE_URL}/api/v1/jobs/${jobId}`;
  const headers  = { "X-API-Key": SHARKAPI_KEY };
  const deadline = Date.now() + timeoutMs;

  while (Date.now() < deadline) {
    const res = await fetch(url, { headers });
    if (!res.ok) throw new Error(`Poll failed: HTTP ${res.status}`);

    const job = await res.json();

    if (job.status === "completed") return job; // job.image_url is ready
    if (job.status === "failed")    throw new Error(job.error ?? "Job failed");

    // queued / processing — wait and retry
    await new Promise(r => setTimeout(r, 2000));
  }

  throw new Error("Job timed out after 3 minutes");
}

// 3. Full flow
async function main() {
  console.log("Submitting job...");
  const { job_id } = await generateImage(
    "A great white shark in bioluminescent deep ocean, cinematic, 8K"
  );

  console.log(`Job created: ${job_id} — polling...`);
  const job = await waitForJob(job_id);

  console.log("Done!");
  console.log("Image URL:", job.image_url);
  console.log("Cost:     ", job.cost);
}

main().catch(console.error);

Python

python
# ── SharkAPI — complete Python example ────────────────────────────
import os, time, httpx

SHARKAPI_KEY = os.environ["SHARKAPI_KEY"]  # sk_live_...
BASE_URL     = "https://www.sharkapi.dev"

def generate_image(prompt: str, image_path: str | None = None, image_url: str | None = None) -> dict:
    """Submit a generation job. Returns the job dict with job_id."""
    headers = {
        "X-API-Key": SHARKAPI_KEY,
        "Content-Type": "application/json",
    }
    body = {"prompt": prompt, "variant": "1k"}

    if image_path:
        import base64
        with open(image_path, "rb") as f:
            body["image"] = base64.b64encode(f.read()).decode()
    elif image_url:
        body["image_url"] = image_url

    res = httpx.post(f"{BASE_URL}/api/v1/image", headers=headers, json=body, timeout=30)
    res.raise_for_status()
    return res.json()  # { job_id, status, poll_url, price_usd }


def wait_for_job(job_id: str, timeout: int = 180) -> dict:
    """Poll until completed or failed. Returns the completed job dict."""
    url      = f"{BASE_URL}/api/v1/jobs/{job_id}"
    headers  = {"X-API-Key": SHARKAPI_KEY}
    deadline = time.time() + timeout

    while time.time() < deadline:
        res = httpx.get(url, headers=headers, timeout=10)
        res.raise_for_status()
        job = res.json()

        if job["status"] == "completed":
            return job  # job["image_url"] is ready
        if job["status"] == "failed":
            raise RuntimeError(job.get("error") or "Job failed — no charge applied")

        time.sleep(2)  # queued / processing — keep polling

    raise TimeoutError("Job timed out after 3 minutes")


# Full flow
if __name__ == "__main__":
    print("Submitting job...")
    job_info = generate_image(
        "A great white shark in bioluminescent deep ocean, cinematic, 8K"
    )
    job_id = job_info["job_id"]
    print(f"Job created: {job_id} — polling...")

    job = wait_for_job(job_id)
    print("Done!")
    print("Image URL:", job["image_url"])
    print("Cost:     ", job["cost"])

Shell (bash / cURL)

bash
#!/bin/bash
# ── SharkAPI — complete shell script example ──────────────────────

TOKEN="sk_live_••••••••"
BASE="https://www.sharkapi.dev"

# 1. Submit job
RESPONSE=$(curl -s -X POST "$BASE/api/v1/image" \
  -H "X-API-Key: $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"prompt":"A great white shark in bioluminescent deep ocean, cinematic, 8K"}')

JOB_ID=$(echo "$RESPONSE" | grep -o '"job_id":"[^"]*"' | cut -d'"' -f4)
echo "Job created: $JOB_ID"

# 2. Poll every 2 seconds
while true; do
  POLL=$(curl -s "$BASE/api/v1/jobs/$JOB_ID" \
    -H "X-API-Key: $TOKEN")

  STATUS=$(echo "$POLL" | grep -o '"status":"[^"]*"' | cut -d'"' -f4)
  echo "Status: $STATUS"

  if [ "$STATUS" = "completed" ]; then
    echo "Image URL: $(echo $POLL | grep -o '"image_url":"[^"]*"' | cut -d'"' -f4)"
    break
  fi

  if [ "$STATUS" = "failed" ]; then
    echo "Job failed — no charge applied"
    break
  fi

  sleep 2
done

Coming soon

2K Mode — 2048×2048 px at $0.05/image

High-resolution output for print, detailed renders, and premium applications. When 2K launches, you will be able to pass variant: "2k" and the API behaviour stays identical — just poll the same way. No integration changes needed on your side.