photo2url Developer API

Turn photo2url into an image pipeline for AI agents and automation: upload an image with an API key, receive CDN-ready URLs, and get structured metadata back. Create keys from the API Keys page in your dashboard.

Authentication

Every request requires a key from your dashboard, sent as a Bearer token. Keep keys secret — the full key is shown only once, at creation.

Authorization: Bearer p2k_YOUR_API_KEY

Disable a key from the dashboard to revoke it immediately; delete it to remove it permanently.

Upload Image

Upload one image per request as multipart/form-data. The file field is file. Supported formats: PNG, JPG, WEBP, GIF.

POST https://photo2url.com/api/v1/images/upload
Content-Type: multipart/form-data
Authorization: Bearer p2k_YOUR_API_KEY

file  (required)  image bytes
expires (optional, reserved for a future phase)

Analyze Image

Analyze a previously uploaded image and receive structured, machine-readable information: dimensions, format, transparency, animation, and deterministic technical-quality signals. Analysis is computed locally from image headers — there is no vision model, and the result is not an “AI quality score”.

A typical agent workflow is upload → file_id → analyze → decide:

POST /api/v1/images/analyze
Content-Type: application/json
Authorization: Bearer p2k_YOUR_API_KEY

{ "file_id": "b2d0f1c6-0000-0000-0000-000000000000" }

The file must belong to the authenticated account. A file_id that does not exist or belongs to another user returns the same 404 file_not_found. Results are cached per file, so repeated analyses are cheap.

Successful response:

HTTP/1.1 200 OK

{
  "success": true,
  "request_id": "0f26a4a4-...",
  "data": {
    "file_id": "b2d0f1c6-...",
    "metadata": {
      "width": 1200,
      "height": 800,
      "format": "png",
      "mime_type": "image/png",
      "file_size": 412900,
      "aspect_ratio": 1.5
    },
    "properties": {
      "has_transparency": true,
      "animated": false
    },
    "technical_quality": {
      "score": 100,
      "issues": []
    }
  }
}

technical_quality.issues currently reports very_low_resolution, low_resolution, extreme_aspect_ratio, and inefficient_file using fixed, documented thresholds. Orientation is not returned because EXIF metadata is stripped before storage.

Response Format

A successful upload returns CDN URLs plus the file identifier:

HTTP/1.1 200 OK

{
  "success": true,
  "request_id": "0f26a4a4-...",
  "data": {
    "file_id": "b2d0f1c6-...",
    "url": "https://cdn.photo2url.com/uploads/2026/09/....jpg",
    "markdown": "![photo](https://cdn.photo2url.com/uploads/...)",
    "html": "<img src=\"https://cdn.photo2url.com/uploads/...\" alt=\"photo\" />"
  }
}

Errors

Failures use non-2xx status codes and a machine-readable error code. Responses never include stack traces, database internals, or storage details.

StatusErrorMeaning
401invalid_api_keyMissing, unknown, wrong, or disabled key
403account_suspendedKey is valid but the account is suspended
400invalid_fileMissing file, unsupported type, or content mismatch
400file_too_largeFile exceeds your plan limit
400storage_fullYour plan storage is full
400invalid_requestAnalyze body is not JSON or has no valid file_id
400unsupported_fileStored file is not a supported image or is malformed
404file_not_foundFile does not exist or belongs to another account
503service_unavailableStorage is not configured (local/dev)
500server_errorUnexpected failure; retry with the request_id
{
  "success": false,
  "error": "invalid_api_key",
  "request_id": "0f26a4a4-..."
}

Examples

curl:

curl -X POST \
  -H "Authorization: Bearer p2k_YOUR_API_KEY" \
  -F [email protected] \
  https://photo2url.com/api/v1/images/upload

curl (analyze):

curl -X POST \
  -H "Authorization: Bearer p2k_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"file_id":"b2d0f1c6-0000-0000-0000-000000000000"}' \
  https://photo2url.com/api/v1/images/analyze

Node.js / fetch:

const form = new FormData();
const file = new File([bytes], "photo.png", { type: "image/png" });
form.append("file", file);

const res = await fetch("https://photo2url.com/api/v1/images/upload", {
  method: "POST",
  headers: { Authorization: `Bearer ${API_KEY}` },
  body: form,
});
const json = await res.json();

Node.js / fetch (analyze):

const res = await fetch(
  "https://photo2url.com/api/v1/images/analyze",
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ file_id: fileId }),
  }
);
const json = await res.json();

Python:

import requests

resp = requests.post(
    "https://photo2url.com/api/v1/images/analyze",
    headers={"Authorization": f"Bearer {API_KEY}"},
    json={"file_id": file_id},
    timeout=60,
)
data = resp.json()["data"]
print(data["metadata"], data["properties"], data["technical_quality"])

Agent workflow example:

# 1. Agent receives an image
# 2. Upload it, get back file_id + CDN url
# 3. Analyze the image with file_id
analysis = analyze(file_id)

# 4. Agent decides what to do next from structured facts
if analysis.metadata.width < 500:
    resize_or_warn()          # too small for the target use
elif analysis.properties.animated:
    pick_first_frame()        # animated files may not fit
else:
    proceed(analysis)
Developer API – Agent API Gateway | photo2url