Agent API

Programmatic access for AI agents with credits-based pricing.

Start here first

If you want the shortest zero-to-first-call path, read Agent Quickstart first.

If you are still deciding whether Rynjer is the right fit, start from For Agents.

If you need help deciding whether Nano Banana 2 should be the first model, use the Model Routing Guide.

Quick start

Fast path for most builders

  1. Read Agent Quickstart
  2. Check model fit with Model Routing Guide
  3. Estimate with POST /v1/credits/estimate
  4. Call POST /v1/generate
  5. Poll GET /v1/generate/{requestId} if needed

Minimal call (example)

POST /v1/generate
{
  "model": "nano-banana-pro",
  "prompt": "Studio product shot of a matte black smart speaker on a neutral background, soft commercial lighting, premium ad look",
  "request_id": "uuid"
}

Machine-first examples

This section is for builders who want copy-paste examples instead of product-level explanation.

Example 1: inspect the model catalog

curl -s https://rynjer.com/v1/models/list \
  -H "Authorization: Bearer $RYNJER_ACCESS_TOKEN"

Use this when the agent should inspect the current catalog instead of hardcoding model assumptions.

Example 2: estimate credits before generation

curl -s https://rynjer.com/v1/credits/estimate \
  -H "Authorization: Bearer $RYNJER_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "product": "image",
    "model": "nano-banana-pro",
    "units": {
      "count": 1,
      "resolution": "1K"
    }
  }'

Example 3: submit a generation request

curl -s https://rynjer.com/v1/generate \
  -H "Authorization: Bearer $RYNJER_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "request_id": "demo-uuid-001",
    "model": "nano-banana-pro",
    "prompt": "Studio product shot of a matte black smart speaker on a neutral background, soft commercial lighting, premium ad look"
  }'

Example 4: poll the same request

curl -s https://rynjer.com/v1/generate/demo-uuid-001 \
  -H "Authorization: Bearer $RYNJER_ACCESS_TOKEN"

Authentication

App-level usage

  • API Key: Authorization: Bearer <api_key>
  • Moltbook: POST /auth/moltbook/exchangeaccess_token (15 min)

Agent identity flow

If you need the more explicit autonomous-agent path, the current flow is:

  1. POST /api/v1/agents/register
  2. Bind the returned registration_code to a user account
  3. POST /api/v1/agents/keys/create
  4. POST /api/v1/agents/auth/token
  5. Use the resulting bearer token on /v1/*

This keeps long-lived key issuance and short-lived access separate.

Token flow example

The autonomous path is more verbose, but it is the right fit when the agent needs its own identity lifecycle.

Step 1: register the agent identity

curl -s https://rynjer.com/api/v1/agents/register \
  -H "Content-Type: application/json" \
  -d '{
    "public_key": "<ed25519_public_key_hex>",
    "agent_name": "Demo Agent",
    "agent_version": "0.1.0",
    "timestamp": 1742291400,
    "nonce": "random-nonce",
    "signature": "<signature_hex>"
  }'

Expected response shape:

{
  "success": true,
  "data": {
    "agent_id": "...",
    "registration_code": "...",
    "expires_at": "..."
  }
}

Then bind registration_code to the owner account outside the API flow.

Step 2: create a long-lived API key

curl -s https://rynjer.com/api/v1/agents/keys/create \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "<agent_id>",
    "registration_code": "<registration_code>",
    "key_name": "demo-key",
    "scopes": ["image"],
    "expires_in_days": 90,
    "timestamp": 1742291460,
    "nonce": "random-nonce-2",
    "signature": "<signature_hex>"
  }'

Expected response shape:

{
  "success": true,
  "data": {
    "key_id": "...",
    "api_key": "ryn_agent_v1_...",
    "scopes": ["image"],
    "expires_at": "..."
  }
}

Step 3: exchange API key for short-lived access token

curl -s https://rynjer.com/api/v1/agents/auth/token \
  -H "Authorization: Bearer $RYNJER_AGENT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "<agent_id>",
    "scopes": ["image"],
    "timestamp": 1742291520,
    "nonce": "random-nonce-3",
    "signature": "<signature_hex>"
  }'

Expected response shape:

{
  "code": 0,
  "message": "ok",
  "data": {
    "access_token": "...",
    "token_type": "Bearer",
    "expires_in": 900,
    "refresh_token": "...",
    "agent_id": "...",
    "account_id": "...",
    "scopes": ["image"]
  }
}

Step 4: refresh when needed

curl -s https://rynjer.com/api/v1/agents/auth/refresh \
  -H "Content-Type: application/json" \
  -d '{
    "refresh_token": "$RYNJER_REFRESH_TOKEN"
  }'

Request normalization details

POST /v1/generate accepts a few machine-friendly shortcuts:

  • top-level count, resolution, duration, and aspect_ratio are normalized into units
  • image_urls is normalized into input_image_urls
  • product can be omitted when the model makes the product obvious

Example using top-level shortcuts:

curl -s https://rynjer.com/v1/generate \
  -H "Authorization: Bearer $RYNJER_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "request_id": "demo-uuid-002",
    "model": "qwen/text-to-image",
    "prompt": "Minimal ecommerce hero image for a skincare bottle, front-facing, soft shadow, high-end brand aesthetic",
    "count": 1,
    "resolution": "1K",
    "aspect_ratio": "1:1"
  }'

Balance, estimate, and model discovery

  • GET /v1/credits/balance
  • POST /v1/credits/estimate
  • GET /v1/models/list

Estimate request

{
  "product": "image",
  "model": "nano-banana-pro",
  "units": { "count": 1, "resolution": "1K" },
  "price_version": "2026-02-02-v1"
}

Model list response shape

GET /v1/models/list returns:

  • currency
  • price_version
  • models

Use it when the agent needs to inspect the current catalog instead of assuming one fixed model list.

Generate (v1)

Request fields

  • request_id (required)
  • model (required)
  • prompt (required for text-to-*)
  • product (optional: image/video/music; auto-detected if omitted)
  • units: { count, resolution, duration, aspect_ratio }
  • input_image_urls (for image-to-image / image-to-video)
  • price_version (optional)
  • top-level shortcuts like count, resolution, duration, and aspect_ratio are normalized into units
  • image_urls is normalized into input_image_urls when needed

Idempotency: reusing the same request_id will not double-charge.

Response (JSON-only)

{
  "code": 0,
  "message": "ok",
  "data": {
    "task_id": "...",
    "provider_task_id": "...",
    "status": "pending",
    "usage_event_id": "..."
  }
}

Polling

If the task remains pending, poll:

GET /v1/generate/{requestId}

Pricing (credits)

All pricing is credits. For images, count multiplies the cost (1/2/4/8).

Image models (per image)

ModelCreditsNotes
google/nano-banana8fast draft
nano-banana-pro204K = 40
gpt4o_image10
qwen/text-to-image15
qwen/image-to-image15
xai/grok-imagine-image20
xai/grok-imagine-image/edit20
z-image20

Video models

ModelCreditsNotes
sora-210720p baseline
sora-2-pro330
veo3_fast50
veo32801080p = 350
doubao-seedance-1.0-pro-fast40
wan-2.6201080p = 300
fal-ai/ltx-2/image-to-video50
xai/grok-imagine-video/text-to-video10

Notes:

  • 1080p may apply ~1.8x on some models (use /v1/credits/estimate for exact pricing).
  • image-to-video can apply a 1.5x multiplier for some models.

Music models

ModelCredits
V535
V4_5PLUS30
V4_525
V420

Autonomous agent endpoints

These endpoints matter when the agent manages its own identity lifecycle:

  • POST /api/v1/agents/register
  • POST /api/v1/agents/keys/create
  • POST /api/v1/agents/auth/token
  • POST /api/v1/agents/auth/refresh
  • POST /api/v1/agents/keys/list
  • POST /api/v1/agents/keys/revoke

Use this path if you want agent registration, owner binding, scoped keys, and short-lived access tokens.

Errors (JSON)

Common errors:

{
  "code": 0,
  "message": "ok",
  "data": {
    "error": "insufficient_credits",
    "required": 50,
    "available": 10,
    "suggestion": "Use a cheaper model or ask the owner to top up."
  }
}

Machine-readable docs

  • OpenAPI: /agent/openapi.json
  • llms.txt: /llms.txt and /agent/llms.txt