API Access

Manage your API keys and integrate VisaPics into your applications

API Balance

Loading...

Add Funds

Photos Available

0

Photos Processed

0

Active Keys

0

Rate Limit

1,000/hr

Your API Keys

API Documentation

Loading API keys...

Pay-As-You-Go Pricing

Your rate improves as you deposit more. Tier is based on lifetime deposits.

Base

$0.50

per photo

< $100 deposited

Starter

$0.40

per photo

20% off

$100+ deposited

Professional

$0.30

per photo

40% off

$250+ deposited

Enterprise

$0.20

per photo

60% off

$500+ deposited

Authentication

All API requests require authentication via Bearer token:

Authorization: Bearer YOUR_API_KEY
GET /api/v1/specifications/{country_code} Get document specifications

Returns all document types for a country with their spec_id.

Parameters

country_code string, required

ISO 2-letter country code (us, gb, de, etc.)

Example Response

{
  "specifications": [
    {"id": 822, "name": "US Passport", "type": "passport"},
    {"id": 821, "name": "US Visa", "type": "visa"}
  ]
}
POST /api/v1/photo/process Process a photo

Upload and process a photo. Returns task_id for async processing.

Request Body (multipart/form-data)

photo *
file

JPEG or PNG image file


spec_id *
integer

Document specification ID (get from /specifications endpoint)


output_format string

"url" (default) or "base64"

Example Request (cURL)

curl -X POST "https://visapics.org/api/v1/photo/process" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "photo=@photo.jpg" \
  -F "spec_id=822"

Response (202 Accepted)

{
  "status": "processing",
  "task_id": "abc123-def456-...",
  "message": "Photo queued for processing"
}
GET /api/v1/task/{task_id} Get processing result

Poll this endpoint to get the processing result.

States

PENDING - In queue
PROCESSING - Being processed
SUCCESS - Completed
FAILURE - Error occurred

Success Response

{
  "success": true,
  "data": {
    "state": "SUCCESS",
    "progress": 100,
    "result": {
      "specification": {
        "country_code": "us",
        "document_type": "US Passport"
      },
      "compliance": {
        "overall_success": true,
        "photo_size": "51x51mm",
        "head_measurements": "25-35mm",
        "resolution_dpi": 300,
        "warnings": [],
        "suitable_for_online": true,
        "printable": true
      },
      "digital_photo_url": "/download/...",
      "printable_photo_url": "/download_printable/..."
    }
  }
}

Error Response (Photo Failed)

{
  "success": false,
  "error": {
    "code": "E400_PROCESSING",
    "message": "Photo processing failed",
    "failure_reasons": [{
      "code": "NO_FACE_DETECTED",
      "message": "No face detected in the photo",
      "suggestion": "Upload a photo with a clearly visible face"
    }],
    "compliance_issues": ["Head size out of spec range"],
    "warnings": []
  }
}
GET /api/v1/billing/balance Get account balance
{
  "balance_usd": 25.50,
  "photos_available": 51,
  "tier": "Starter",
  "rate_per_photo": 0.40
}

Failure Reason Codes

When photo processing fails, these codes indicate why:

NO_FACE_DETECTED

No face found in the uploaded photo

MULTIPLE_FACES

More than one face detected

HEAD_SIZE_INVALID

Head size cannot meet spec requirements

EYE_POSITION_INVALID

Eye position cannot be adjusted

LOW_RESOLUTION

Photo resolution too low

PROCESSING_FAILED

General processing error

Complete Code Examples

Full working examples with async polling:

import requests
import time

API_KEY = "YOUR_API_KEY"
BASE_URL = "https://visapics.org/api/v1"
HEADERS = {"Authorization": f"Bearer {API_KEY}"}

def process_photo(photo_path, spec_id):
    # Step 1: Upload photo
    with open(photo_path, "rb") as f:
        response = requests.post(
            f"{BASE_URL}/photo/process",
            headers=HEADERS,
            files={"photo": f},
            data={"spec_id": spec_id}
        )

    task_id = response.json()["task_id"]
    print(f"Task created: {task_id}")

    # Step 2: Poll for result
    while True:
        result = requests.get(
            f"{BASE_URL}/task/{task_id}",
            headers=HEADERS
        ).json()

        if result["state"] == "SUCCESS":
            return result["result"]
        elif result["state"] == "FAILURE":
            raise Exception(result.get("error", "Processing failed"))

        time.sleep(1)  # Poll every second

# Usage
result = process_photo("photo.jpg", spec_id=822)
print(f"Photo URL: {result['photo_url']}")
print(f"Printable: {result['printable_url']}")