DEV Community

API Crest
API Crest

Posted on

Python Tutorial: Chat Completions and Async Image Jobs with API Crest

Python Tutorial: Chat Completions and Async Image Jobs with API Crest

Disclosure: I work on API Crest. This walkthrough is based on our published API documentation. It is a getting-started guide, not a claim that I've benchmarked the service or executed the example in this article.

If you're building a small AI app, you may need two very different patterns: a quick request for a text response, and an asynchronous job for image generation. This tutorial shows both patterns using Python, and explains where people often run into trouble.

1. Get an API key and install dependencies

Create an API key from the API Crest developer console, then review the model catalog and pricing before running requests. These requests may consume paid credits.

Install Python dependencies:

python -m pip install anthropic requests
Enter fullscreen mode Exit fullscreen mode

Keep the API key out of source code. Set it as an environment variable in your own shell:

export APICREST_API_KEY="YOUR_API_KEY"
Enter fullscreen mode Exit fullscreen mode

On Windows PowerShell, use $env:APICREST_API_KEY = "YOUR_API_KEY" for the current session.

2. Send a chat message with the Anthropic Python SDK

The API Crest documentation documents the Anthropic-style POST /v1/messages route at https://api.vv666.ai and lists claude-haiku-5-5 as a model ID.

import os
from anthropic import Anthropic

client = Anthropic(
    api_key=os.environ["APICREST_API_KEY"],
    base_url="https://api.vv666.ai",
)

response = client.messages.create(
    model="claude-haiku-5-5",
    max_tokens=256,
    messages=[
        {"role": "user", "content": "Explain idempotency in two sentences."}
    ],
)

for block in response.content:
    if getattr(block, "type", None) == "text":
        print(block.text)
Enter fullscreen mode Exit fullscreen mode

The model ID is the provider's documented identifier, not a universal model name. Use the API Crest catalog to confirm current model availability and rates.

The equivalent raw HTTP shape uses a POST /v1/messages request, an API key in an accepted auth header, and JSON fields such as model, messages, and max_tokens.

3. Submit an image generation task and poll for completion

Unlike the chat request above, API Crest's media API documents an asynchronous flow:

  1. POST /v1/media/generate with a model and prompt.
  2. Read the returned task_id.
  3. GET /v1/media/status?task_id=... until is_final is true.
  4. Read result_url for a successful job, or handle an error state.

Here's a minimal example built around the documented gpt-image-2.5 model and media routes:

import os
import time
import requests

BASE = "https://api.vv666.ai"
HEADERS = {"Authorization": f"Bearer {os.environ['APICREST_API_KEY']}"}

created = requests.post(
    f"{BASE}/v1/media/generate",
    headers=HEADERS,
    json={
        "model": "gpt-image-2.5",
        "prompt": "A tiny robot watering a bonsai tree, soft studio lighting",
        "params": {"aspect_ratio": "1:1", "quality": "auto"},
    },
    timeout=30,
)
created.raise_for_status()
task_id = created.json()["task_id"]

for _ in range(20):
    check = requests.get(
        f"{BASE}/v1/media/status",
        headers=HEADERS,
        params={"task_id": task_id},
        timeout=30,
    )
    check.raise_for_status()
    job = check.json()

    if job.get("is_final"):
        if job.get("state") == "success":
            print("Result:", job.get("result_url"))
            break
        raise RuntimeError(f"Generation failed: {job.get('error', job.get('state'))}")

    time.sleep(5)
else:
    print("Job is still pending; keep the task_id and check later.")
Enter fullscreen mode Exit fullscreen mode

A five-second polling interval is only an illustration, not a documented rate-limit recommendation. For production, use sensible retry/backoff logic, persist your task_id, and avoid endlessly polling a failed job.

4. Practical production checklist

Before connecting any AI API to production, I recommend:

  • Keep keys on the server: never expose them in a public frontend bundle.
  • Avoid retrying a creation request blindly: if the first response is lost after the job is accepted, a duplicate submission could incur extra cost.
  • Log the task ID and final status: especially important for images, video, and other long-running jobs.
  • Budget requests and monitor consumption: model prices and billing units differ.
  • Handle 403/429/5xx responses: including permission problems, throttling, and transient failures.
  • Choose the protocol per model: don't assume all model routes share one request schema.

Documentation and feedback

If you're integrating chat and media generation in the same app, what causes you more trouble: keeping usage costs predictable, handling async job states, or normalizing provider APIs?

I'd be interested to hear what you'd add to this checklist.

Top comments (0)