Quick Start
API Reference
Error Reference
AI Agents

Error Reference

Every API error response follows the same shape. Machine-readable codes, human-readable messages, and an optional action object that tells you exactly what to do next.

Response Shape

json
{
  "error": "error_code",
  "message": "Human-readable explanation",
  "action": {
    "type": "upgrade | verify | wait | redirect",
    "url": "https://...",
    "label": "Button text for humans",
    "seconds": 3600
  },
  "usage": {
    "plan": "free",
    "uploads_used": 100,
    "uploads_limit": 100
  }
}

The action and usage fields are only present on certain errors. The action.seconds field is only present for wait type actions.

Action Types

Type When What To Do
upgrade Quota exceeded (verified user) Surface action.url to user — it's a signed upgrade link.
verify Unverified account limit Surface action.url to user for email verification.
wait Rate limited Wait action.seconds before retrying.
redirect Registration closed Direct user to action.url (usually the dashboard).

Error Codes

unauthorized

HTTP 401 — Invalid or missing API key.

No action included.

json
{
  "error": "unauthorized",
  "message": "Invalid or missing API key"
}

forbidden

HTTP 403 — Valid key but insufficient permissions.

No action included.

json
{
  "error": "forbidden",
  "message": "Insufficient permissions"
}

quota_exceeded

HTTP 403 — Upload or storage limit reached.

Includes an upgrade action for verified users, or a verify action for unverified users.

Verified user (upgrade):

json
{
  "error": "quota_exceeded",
  "message": "Monthly upload limit reached.",
  "action": {
    "type": "upgrade",
    "url": "https://img.pro/upgrade/pro?t=abc&exp=1709337600&sig=hmac...",
    "label": "Upgrade to Pro ($10/mo) for 1,000 uploads"
  },
  "usage": {
    "plan": "free",
    "uploads_used": 100,
    "uploads_limit": 100
  }
}

Unverified user (verify):

json
{
  "error": "quota_exceeded",
  "message": "Unverified upload limit reached. Verify your email to unlock permanent storage.",
  "action": {
    "type": "verify",
    "url": "https://img.pro/verify?t=abc&exp=1709337600&sig=hmac...",
    "label": "Verify email for permanent storage"
  },
  "usage": {
    "plan": "free",
    "uploads_used": 100,
    "uploads_limit": 100
  }
}

registration_closed

HTTP 403 — Team's agent policy is set to "closed".

Includes a redirect action.

json
{
  "error": "registration_closed",
  "message": "This account does not accept new API key registrations.",
  "action": {
    "type": "redirect",
    "url": "https://img.pro/keys",
    "label": "Request key from dashboard"
  }
}

key_limit_reached

HTTP 403 — Unverified account, max 3 active keys.

Includes a verify action.

json
{
  "error": "key_limit_reached",
  "message": "Unverified accounts can have 3 active keys. Verify your email to create more.",
  "action": {
    "type": "verify",
    "url": "https://img.pro/verify?t=abc&exp=1709337600&sig=hmac...",
    "label": "Verify email to remove limit"
  }
}

rate_limited

HTTP 429 — Too many requests. Includes a Retry-After HTTP header.

For key creation, includes a wait action. For anonymous uploads, includes a redirect action to the quick-start docs.

json
// Key creation rate limit
{
  "error": "rate_limited",
  "message": "Too many key creation requests. Try again later.",
  "action": {
    "type": "wait",
    "seconds": 60
  }
}

// Anonymous upload rate limit
{
  "error": "rate_limited",
  "message": "Hourly limit of 20 uploads reached. Resets in 42 minutes. Get an API key for higher limits.",
  "action": {
    "type": "redirect",
    "url": "https://img.pro/api/quick-start",
    "label": "Create API Key"
  },
  "retry_after": 2520
}

validation_error

HTTP 422 — Invalid input (bad namespace, missing required field, etc.).

No action included. Has an errors field instead with per-field messages.

json
{
  "error": "validation_error",
  "message": "Validation failed",
  "errors": {
    "namespace": ["Must be lowercase alphanumeric with hyphens"],
    "file": ["File is required"]
  }
}

not_found

HTTP 404 — Media or resource doesn't exist.

No action included.

json
{
  "error": "not_found",
  "message": "Media not found"
}

upload_failed

HTTP 500 — File processing failed (invalid format, too large, or internal error).

No action included.

json
{
  "error": "upload_failed",
  "message": "File too large: 150.00 MB. Maximum file size is 70 MB."
}

fetch_failed

HTTP 502 / 504 — URL import couldn't fetch the source. Returns 504 if the request timed out (30 second limit).

No action included.

json
{
  "error": "fetch_failed",
  "message": "URL returned 404"
}

Timeout example (HTTP 504):

json
{
  "error": "fetch_failed",
  "message": "URL fetch timeout"
}

import_failed

HTTP 500 — URL import processing failed after fetch succeeded.

No action included.

json
{
  "error": "import_failed",
  "message": "Import failed"
}

update_failed

HTTP 500 — Media metadata update failed.

No action included.

json
{
  "error": "update_failed",
  "message": "Update failed"
}

delete_failed

HTTP 500 — Media deletion failed.

No action included.

json
{
  "error": "delete_failed",
  "message": "Delete failed"
}

Handling Errors in Code

Here's a comprehensive example showing how to handle errors, including action-based responses:

python
import requests

def upload_image(api_key, filepath, namespace=None):
    response = requests.post(
        "https://api.img.pro/v1/upload",
        headers={"Authorization": f"Bearer {api_key}"},
        files={"file": open(filepath, "rb")},
        data={"namespace": namespace} if namespace else {}
    )

    if response.ok:
        return response.json()

    data = response.json()
    action = data.get("action")

    if action:
        if action["type"] == "upgrade":
            print(f"Limit reached. {action['label']}")
            print(f"Upgrade here: {action['url']}")
        elif action["type"] == "verify":
            print(f"Verify your email: {action['url']}")
        elif action["type"] == "wait":
            import time
            time.sleep(action["seconds"])
            return upload_image(api_key, filepath, namespace)

    raise Exception(f"Upload failed: {data['message']}")