Seedance 2.5 is live on EvoLinkTry Seedance 2.5
Asynchronous Grok Imagine Image 2.0 API pipeline from request to callback and storage
Tutorial

How to Use the Grok Imagine Image 2.0 API on EvoLink

Jacey
Jacey
August 12, 2026
14 min read
This guide takes an EvoLink user from an API key to a completed Grok Imagine Image 2.0 task. The minimum path is: send POST /v1/images/generations with model: "grok-imagine-image-2.0", store the returned task id, then query GET /v1/tasks/{task_id} until the task reaches completed or failed.
The same route handles text-to-image and image editing. Omit image_urls to generate from text; include one to three public image URLs to edit or compose from references. For current pricing and interactive testing, use the Grok Imagine Image 2.0 model page. This article focuses on application flow, failure handling, storage, and model fallback rather than duplicating the complete parameter reference.
Open Grok Imagine Image 2.0 on EvoLink
Last verified: August 12, 2026.
Visual disclosure: the cover and supporting images in this guide were generated with GPT Image 2 as workflow illustrations. They are not Grok Imagine Image 2.0 output samples.

What you will build

By the end of the guide, your application will be able to:

  1. create a text-to-image task;
  2. switch to reference editing without changing model IDs;
  3. use indexed references in a multi-image prompt;
  4. track an asynchronous task by ID;
  5. accept a completion callback safely;
  6. persist results before their 24-hour URLs expire;
  7. reconcile final usage and failed-task refunds;
  8. hand off to a fallback route when the workload or task outcome requires it.
If you first need the launch facts and testing boundary, read the Grok Imagine Image 2.0 release guide. This guide stays focused on implementation.

Before you start

Create an API key from EvoLink API Key Management. Keep the key in a server-side secret store or environment variable. Never expose it in browser JavaScript, a public repository, analytics events, screenshots, or client error reports.
ItemCurrent EvoLink contract
Base URLhttps://api.evolink.ai
Create taskPOST /v1/images/generations
Query taskGET /v1/tasks/{task_id}
AuthenticationAuthorization: Bearer YOUR_API_KEY
Modelgrok-imagine-image-2.0
Text-to-imageOmit image_urls
Image editingSupply 1-3 public HTTP/HTTPS image URLs
Output1K/2K, Low/Medium, n=1-10
ProcessingAsynchronous task
Result lifetime24 hours
The authoritative field list is the Grok Imagine Image 2.0 API documentation. Recheck it before deploying because contracts can change after publication.

Step 1: keep the API key server-side

For a shell test, set the key in an environment variable:

export EVOLINK_API_KEY="your_api_key"
The examples below use ${EVOLINK_API_KEY}. Do not replace it with a real key inside code that will be committed.

Step 2: create a text-to-image task

Send a prompt and omit image_urls:
curl --request POST "https://api.evolink.ai/v1/images/generations" \
  --header "Authorization: Bearer ${EVOLINK_API_KEY}" \
  --header "Content-Type: application/json" \
  --data '{
    "model": "grok-imagine-image-2.0",
    "prompt": "Editorial product photograph of a teal glass perfume bottle on pale limestone, warm coastal morning light, restrained luxury art direction, no text or logos",
    "size": "1:1",
    "resolution": "1K",
    "quality": "medium",
    "n": 1
  }'
The create response represents an asynchronous task. Store its id immediately:
{
  "id": "task-unified-1757156493-imcg5zqt",
  "model": "grok-imagine-image-2.0",
  "object": "image.generation.task",
  "progress": 0,
  "status": "pending",
  "type": "image",
  "usage": {
    "billing_rule": "per_call",
    "credits_reserved": 3.06,
    "user_group": "default"
  }
}

The reservation value above is a documentation example, not a price promise and not the final charge. Use the current model page for live pricing and the terminal task response for final usage.

Step 3: query the asynchronous task

Grok Imagine Image 2.0 asynchronous task workflow from submission through callback to durable storage
Grok Imagine Image 2.0 asynchronous task workflow from submission through callback to durable storage
This image was generated with GPT Image 2 as a workflow illustration. It is not a Grok Imagine Image 2.0 output sample or quality result.
Append the returned id to the task endpoint. Do not include braces around the value:
curl --request GET \
  "https://api.evolink.ai/v1/tasks/task-unified-1757156493-imcg5zqt" \
  --header "Authorization: Bearer ${EVOLINK_API_KEY}"
For this route, the query response uses processing, completed, or failed. A completed response includes results, structured result_data, and final usage:
{
  "id": "task-unified-1757156493-imcg5zqt",
  "model": "grok-imagine-image-2.0",
  "object": "image.generation.task",
  "progress": 100,
  "status": "completed",
  "results": ["https://cdn.evolink.ai/images/generated-image.jpg"],
  "result_data": [
    {
      "url": "https://cdn.evolink.ai/images/generated-image.jpg",
      "mime_type": "image/jpeg"
    }
  ],
  "type": "image",
  "usage": {
    "credits_used": 3.06,
    "cost": {
      "credits": 3.06,
      "cny": 0.31,
      "usd": 0.05
    }
  }
}

Those numeric values are example response values. Record the values returned by your own terminal task; do not use this example to calculate customer billing.

Step 4: add controlled polling

Polling should stop on a terminal status, back off between requests, and enforce an application timeout. The following server-side TypeScript example keeps the task workflow explicit:

type GrokTaskStatus = "processing" | "completed" | "failed";

type GrokTask = {
  id: string;
  status: GrokTaskStatus;
  progress: number;
  results?: string[];
  error?: {
    code: string;
    message: string;
    type: "task_error";
  };
};

const API_BASE_URL = "https://api.evolink.ai";

async function getTask(apiKey: string, taskId: string): Promise<GrokTask> {
  const response = await fetch(`${API_BASE_URL}/v1/tasks/${taskId}`, {
    headers: { Authorization: `Bearer ${apiKey}` },
    cache: "no-store",
  });

  if (!response.ok) {
    throw new Error(`Task query failed with HTTP ${response.status}`);
  }

  return response.json() as Promise<GrokTask>;
}

async function waitForTask(
  apiKey: string,
  taskId: string,
  timeoutMs = 180_000,
): Promise<GrokTask> {
  const startedAt = Date.now();
  let intervalMs = 2_000;

  while (Date.now() - startedAt < timeoutMs) {
    const task = await getTask(apiKey, taskId);

    if (task.status === "completed" || task.status === "failed") {
      return task;
    }

    await new Promise((resolve) => setTimeout(resolve, intervalMs));
    intervalMs = Math.min(Math.round(intervalMs * 1.5), 10_000);
  }

  throw new Error("Grok Imagine Image 2.0 task timed out in the application");
}

An application timeout is not proof that the upstream task failed. Before retrying generation, query the original task again or use an idempotency strategy in your own job layer. Otherwise, a client timeout can create duplicate billable tasks.

Step 5: switch to single-reference editing

Add image_urls to switch modes. Input images must be publicly accessible through HTTP or HTTPS; base64 and data URLs are not supported by the current contract. Supported extensions are JPEG, JPG, PNG, and WebP.
curl --request POST "https://api.evolink.ai/v1/images/generations" \
  --header "Authorization: Bearer ${EVOLINK_API_KEY}" \
  --header "Content-Type: application/json" \
  --data '{
    "model": "grok-imagine-image-2.0",
    "prompt": "Move the chair into a quiet rain-soaked garden room. Preserve the chair shape, teal upholstery, camera angle, and scale. Change only the environment and reflected light.",
    "image_urls": [
      "https://example.com/chair.webp"
    ],
    "size": "4:3",
    "resolution": "1K",
    "quality": "medium",
    "n": 1
  }'

Your application should validate count, protocol, file type, and server reachability before creating a paid task. A URL that works in a signed-in browser may still be inaccessible to the generation service.

Step 6: compose with multiple references

For two or three reference images, use zero-based indexes in the prompt. The index maps to the position in image_urls.
curl --request POST "https://api.evolink.ai/v1/images/generations" \
  --header "Authorization: Bearer ${EVOLINK_API_KEY}" \
  --header "Content-Type: application/json" \
  --data '{
    "model": "grok-imagine-image-2.0",
    "prompt": "Place the person from <IMAGE_0> in the architectural setting from <IMAGE_1>, carrying the blue sculptural bag from <IMAGE_2>. Preserve the outfit silhouette and match the late-afternoon direction of light.",
    "image_urls": [
      "https://example.com/person.webp",
      "https://example.com/location.webp",
      "https://example.com/bag.webp"
    ],
    "size": "3:4",
    "resolution": "2K",
    "quality": "medium",
    "n": 1
  }'

Store the exact array order with the prompt. If a user interface lets someone reorder uploads, update the array and index labels together.

Step 7: choose parameters by workflow stage

Grok Imagine Image 2.0 supports 13 ratios plus auto, 1K/2K resolution, Low/Medium quality, and n=1-10.
ParameterUse it to decideProduction rule
sizeDelivery shape or model-selected autoValidate against the documented ratio enum before submitting
resolution1K draft/review vs 2K delivery candidateDo not send 4K; the route does not support it
qualityLow for faster/lower-cost exploration vs Medium for more detailEvaluate the tier against the actual acceptance criterion
nNumber of independent outputsCap it per product action and budget because each output is billed independently
image_urlsText-only generation vs reference editingOmit entirely for text-to-image; accept at most three URLs

Use a request allowlist rather than passing arbitrary client JSON directly to the API. This prevents unsupported fields, excessive batches, or internal callback URLs from reaching the route.

Step 8: use callbacks for production completion

Pass callback_url when your application can expose a public HTTPS endpoint:
{
  "model": "grok-imagine-image-2.0",
  "prompt": "A clean ecommerce product scene with soft daylight",
  "callback_url": "https://your-domain.com/webhooks/evolink/image-task"
}

The current contract says callbacks are sent after billing confirmation when a task is completed, failed, or cancelled. EvoLink waits up to 10 seconds and may retry a failed callback three times after 1, 2, and 4 seconds. A 2xx response marks delivery successful.

Design the receiver to be idempotent:

  1. authenticate the request using the mechanism your EvoLink account and webhook setup supports;
  2. validate the task ID and expected model;
  3. upsert by task ID rather than inserting a new result on every delivery;
  4. return 2xx after durable persistence;
  5. move slow downloads and review work to a queue;
  6. keep polling as a recovery path when webhook delivery cannot be confirmed.

The callback URL must use HTTPS and cannot point to localhost, private IP ranges, or an internal service address.

Step 9: save results before they expire

Completed image URLs remain available for 24 hours. Treat them as transfer URLs, not permanent application storage.

After completion:

  1. verify that the task belongs to the current account and job;
  2. download every item in results or result_data;
  3. validate content type and file size;
  4. store the file in your own object storage;
  5. save the permanent URL and content hash;
  6. record the generation parameters and review state;
  7. apply your retention and deletion policy to reference inputs and outputs.
If n is greater than one, expect independent result URLs in generation order. Do not persist only the first item unless your product intentionally selects one result.

Step 10: handle failure and billing correctly

The create response may reserve credits, but terminal usage is the billing truth. According to EvoLink's task contract, a final failed task is fully refunded, including upstream rejection, content moderation blocks, and timeouts.
OutcomeApplication actionBilling action
completedPersist every result, run acceptance checks, mark the job completeStore final usage and cost breakdown
failed with retryable infrastructure errorApply capped backoff or route to a verified fallbackConfirm final charge is zero/refunded
failed with content-policy errorShow an actionable prompt/input message; do not blind-retryConfirm refund and retain the error code
Application polling timeoutRe-query the same task before creating anotherDo not assume timeout means refund or failure
Invalid request before task creationFix validation or permissionsNo asynchronous task exists to reconcile
Do not promise users that every unsuccessful experience is free without checking the final task state. A low-quality completed image is still a completed task; quality rejection inside your product is different from an API-level failed status.

Handle request-level HTTP errors before polling

Some failures happen before an asynchronous task is created. The current API reference documents these request-level responses:

HTTP statusDocumented meaningApplication response
400Invalid request parameters or formatValidate the request allowlist, required fields, enums, URL count, and JSON shape before retrying
401Authentication errorCheck that the server sent a valid Bearer key; never expose the key in client logs
402Insufficient quotaStop automatic retries and direct the account owner to recharge or adjust the budget
403Access deniedVerify account or route permissions instead of changing the prompt blindly
429Request rate limit exceededApply bounded exponential backoff and queue work; do not fan out immediate retries
500Internal server errorRetry only under a capped infrastructure policy, then use a verified fallback if the job permits
Only start polling when the create response returned a task id. Request-level errors have no asynchronous task to query or refund record to reconcile.

Step 11: add fallback routing

Production fallback workflow for retries, alternate routing, and failed-task reservation reversal
Production fallback workflow for retries, alternate routing, and failed-task reservation reversal
This is a GPT Image 2-generated workflow illustration, not a paired model benchmark.

The integration should separate the product job from the provider-specific model ID:

type ImageRoute = "grok-imagine-image-2.0" | "gpt-image-2";

type ImageJob = {
  prompt: string;
  imageUrls: string[];
  requiresMask: boolean;
  requires4K: boolean;
};

function chooseImageRoute(job: ImageJob): ImageRoute {
  if (job.requiresMask || job.requires4K || job.imageUrls.length > 3) {
    return "gpt-image-2";
  }

  return "grok-imagine-image-2.0";
}

This example is a contract-level starting policy, not a claim that one model produces better images. Add your own acceptance data, latency, cost, moderation, and availability observations before routing meaningful traffic.

For a complete selection framework, read Grok Imagine Image 2.0 vs GPT Image 2.

Production handoff checklist

  • API key stored in a server-side secret manager.
  • Request body allowlist matches the current EvoLink docs.
  • Model ID is centralized in route configuration.
  • Reference images are public, validated, and limited to three.
  • Multi-reference indexes match the persisted input order.
  • Polling stops on completed/failed and uses backoff.
  • Application timeouts do not automatically create duplicate tasks.
  • Callback processing is idempotent and fast.
  • Result files are copied before the 24-hour expiry.
  • Final usage is stored separately from reserved credits.
  • Failed-task refunds are reconciled.
  • Retryable and non-retryable errors are separated.
  • A tested fallback route exists for required capabilities or outages.
  • Logs exclude API keys and sensitive reference URLs.

Frequently asked questions

Which endpoint creates a Grok Imagine Image 2.0 task?

Use POST https://api.evolink.ai/v1/images/generations with Bearer authentication and the required model and prompt fields.

What model ID should I send?

Send grok-imagine-image-2.0 for the current EvoLink route.

How do I switch from generation to editing?

Keep the model ID unchanged. Omit image_urls for text-to-image or pass one to three URLs for editing.

Can I send base64 image data?

No. The current contract accepts publicly accessible HTTP or HTTPS URLs and does not support base64 or data URLs.

How do I query the result?

Store the task id returned by the create call, then send GET https://api.evolink.ai/v1/tasks/{task_id} with the same Bearer authentication pattern.

Should I poll or use a callback?

Use callbacks for normal production completion and polling as a recovery path. A simple server-side prototype may start with backoff polling.

The current documentation says 24 hours. Copy completed files to permanent storage promptly.

Are failed tasks charged?

A task that reaches the final failed state is fully refunded according to the current EvoLink task documentation. A completed image rejected by your own quality review is not the same as an API failure.

Can I request 4K or High quality?

No. This route currently supports 1K/2K and Low/Medium. Use a different verified route when 4K or High is a hard requirement.

Where can I compare Grok with another image route?

Use the Grok Imagine Image 2.0 vs GPT Image 2 decision guide, then validate both with your own paired test set.

Sources

This guide reflects the EvoLink contract verified on August 12, 2026. Recheck the API documentation before shipping, especially model fields, output limits, callback behavior, and task-response schemas.

Ready to Reduce Your AI Costs by 89%?

Start using EvoLink today and experience the power of intelligent API routing.