Skip to content

Admin API

Admin endpoints are prefixed with /api/v1/admin.

Authentication options: - Browser admin console: cookie-backed admin session via /api/v1/admin/auth/login - Direct admin API clients: HTTP Basic Auth

Browser admin session endpoints: - POST /api/v1/admin/auth/login - GET /api/v1/admin/auth/session - POST /api/v1/admin/auth/logout

Authorization: Basic base64(username:password)

GET /api/v1/admin/stats

Returns aggregate statistics across all images and jobs. Requires storage-backed mode; returns 501 when FACE_API_STORAGE_ENABLED=false.

  • Request format: none
  • Response format: JSON (StatsResponse)
curl -u admin:password https://face-api.xylolabs.com/api/v1/admin/stats
import requests
from requests.auth import HTTPBasicAuth

response = requests.get(
    "https://face-api.xylolabs.com/api/v1/admin/stats",
    auth=HTTPBasicAuth("admin", "password"),
)
print(response.json())
const basic = btoa("admin:password");
const response = await fetch("https://face-api.xylolabs.com/api/v1/admin/stats", {
  headers: { Authorization: `Basic ${basic}` },
});
console.log(await response.json());
using System.Net.Http.Headers;
using System.Text;

using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
    "Basic",
    Convert.ToBase64String(Encoding.ASCII.GetBytes("admin:password"))
);

var response = await client.GetAsync("https://face-api.xylolabs.com/api/v1/admin/stats");
Console.WriteLine(await response.Content.ReadAsStringAsync());
{
  "total_images": 1250,
  "total_jobs": 3420,
  "total_faces_detected": 8910,
  "avg_inference_ms": 14.52,
  "storage_used_bytes": 524288000,
  "jobs_by_type": { "detect": 2100, "mask": 1320 },
  "jobs_by_method": { "gaussian": 800, "pixelate": 400, "solid": 120 }
}

Images

GET /api/v1/admin/images

Returns a paginated list of stored images, including a private original download URL and the latest processed image URL when one exists. Requires storage-backed mode; returns 501 when FACE_API_STORAGE_ENABLED=false.

  • Request format: none (query string only)
  • Response format: JSON (PaginatedResponse[StoredImageResponse])

processed_url is null when no processed result exists yet for that image. When FACE_API_S3_PUBLIC_ENDPOINT is configured, processed_url may point at the public processed-asset host.

Parameter Type Default Description
page int 1 Page number
per_page int 20 Items per page (1-100)
curl -u admin:password "https://face-api.xylolabs.com/api/v1/admin/images?page=1&per_page=10"
import requests
from requests.auth import HTTPBasicAuth

response = requests.get(
    "https://face-api.xylolabs.com/api/v1/admin/images?page=1&per_page=10",
    auth=HTTPBasicAuth("admin", "password"),
)
print(response.json())
const basic = btoa("admin:password");
const response = await fetch("https://face-api.xylolabs.com/api/v1/admin/images?page=1&per_page=10", {
  headers: { Authorization: `Basic ${basic}` },
});
console.log(await response.json());
using System.Net.Http.Headers;
using System.Text;

using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
    "Basic",
    Convert.ToBase64String(Encoding.ASCII.GetBytes("admin:password"))
);

var response = await client.GetAsync("https://face-api.xylolabs.com/api/v1/admin/images?page=1&per_page=10");
Console.WriteLine(await response.Content.ReadAsStringAsync());
{
  "items": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "filename": "photo.jpg",
      "content_type": "image/jpeg",
      "size_bytes": 245760,
      "width": 1920,
      "height": 1080,
      "original_url": "https://signed.example.com/originals/...",
      "processed_url": "https://static.face-api.xylolabs.com/face-api/processed/...",
      "job_count": 3,
      "created_at": "2026-04-06T10:30:00+00:00"
    }
  ],
  "total": 1250, "page": 1, "per_page": 10, "pages": 125
}

signed.example.com is an illustrative placeholder for a private signed/original download URL. static.face-api.xylolabs.com illustrates the public processed-asset host when FACE_API_S3_PUBLIC_ENDPOINT is configured.

GET /api/v1/admin/images/{image_id}

Returns image details together with all associated jobs.

  • Request format: none
  • Response format: JSON (StoredImageDetailResponse)
curl -u admin:password https://face-api.xylolabs.com/api/v1/admin/images/550e8400-...
import requests
from requests.auth import HTTPBasicAuth

response = requests.get(
    "https://face-api.xylolabs.com/api/v1/admin/images/550e8400-...",
    auth=HTTPBasicAuth("admin", "password"),
)
print(response.json())
const basic = btoa("admin:password");
const response = await fetch("https://face-api.xylolabs.com/api/v1/admin/images/550e8400-...", {
  headers: { Authorization: `Basic ${basic}` },
});
console.log(await response.json());
using System.Net.Http.Headers;
using System.Text;

using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
    "Basic",
    Convert.ToBase64String(Encoding.ASCII.GetBytes("admin:password"))
);

var response = await client.GetAsync("https://face-api.xylolabs.com/api/v1/admin/images/550e8400-...");
Console.WriteLine(await response.Content.ReadAsStringAsync());

DELETE /api/v1/admin/images/{image_id}

Deletes an image, its associated jobs, and its S3 objects. Returns 204.

  • Request format: none
  • Response format: empty body (204 No Content)
curl -u admin:password -X DELETE https://face-api.xylolabs.com/api/v1/admin/images/550e8400-...
import requests
from requests.auth import HTTPBasicAuth

response = requests.delete(
    "https://face-api.xylolabs.com/api/v1/admin/images/550e8400-...",
    auth=HTTPBasicAuth("admin", "password"),
)
print(response.status_code)
const basic = btoa("admin:password");
const response = await fetch("https://face-api.xylolabs.com/api/v1/admin/images/550e8400-...", {
  method: "DELETE",
  headers: { Authorization: `Basic ${basic}` },
});
console.log(response.status);
using System.Net.Http.Headers;
using System.Text;

using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
    "Basic",
    Convert.ToBase64String(Encoding.ASCII.GetBytes("admin:password"))
);

var response = await client.DeleteAsync("https://face-api.xylolabs.com/api/v1/admin/images/550e8400-...");
Console.WriteLine(response.StatusCode);

GET /api/v1/admin/images/{image_id}/download

Redirects (302) to the original image download URL.

  • Request format: none
  • Response format: redirect (302 Found)
curl -u admin:password -L https://face-api.xylolabs.com/api/v1/admin/images/550e8400-.../download -o original.jpg
import requests
from requests.auth import HTTPBasicAuth

response = requests.get(
    "https://face-api.xylolabs.com/api/v1/admin/images/550e8400-.../download",
    auth=HTTPBasicAuth("admin", "password"),
    allow_redirects=True,
)
with open("original.jpg", "wb") as f:
    f.write(response.content)
const basic = btoa("admin:password");
const response = await fetch("https://face-api.xylolabs.com/api/v1/admin/images/550e8400-.../download", {
  headers: { Authorization: `Basic ${basic}` },
});
const blob = await response.blob();
using System.Net.Http.Headers;
using System.Text;

using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
    "Basic",
    Convert.ToBase64String(Encoding.ASCII.GetBytes("admin:password"))
);

var response = await client.GetAsync("https://face-api.xylolabs.com/api/v1/admin/images/550e8400-.../download");
await using var output = File.Create("original.jpg");
await response.Content.CopyToAsync(output);

Jobs

GET /api/v1/admin/jobs

Returns a paginated job list with optional filters. Requires storage-backed mode; returns 501 when FACE_API_STORAGE_ENABLED=false.

  • Request format: none (query string only)
  • Response format: JSON (PaginatedResponse[JobResponse])
Parameter Type Default Description
page int 1 Page number
per_page int 20 Items per page (1-100)
job_type string detect or mask
method string Filter by blur method
curl -u admin:password "https://face-api.xylolabs.com/api/v1/admin/jobs?job_type=mask&method=gaussian"
import requests
from requests.auth import HTTPBasicAuth

response = requests.get(
    "https://face-api.xylolabs.com/api/v1/admin/jobs?job_type=mask&method=gaussian",
    auth=HTTPBasicAuth("admin", "password"),
)
print(response.json())
const basic = btoa("admin:password");
const response = await fetch("https://face-api.xylolabs.com/api/v1/admin/jobs?job_type=mask&method=gaussian", {
  headers: { Authorization: `Basic ${basic}` },
});
console.log(await response.json());
using System.Net.Http.Headers;
using System.Text;

using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
    "Basic",
    Convert.ToBase64String(Encoding.ASCII.GetBytes("admin:password"))
);

var response = await client.GetAsync("https://face-api.xylolabs.com/api/v1/admin/jobs?job_type=mask&method=gaussian");
Console.WriteLine(await response.Content.ReadAsStringAsync());

GET /api/v1/admin/jobs/{job_id}

Returns job details with the full detection payload.

  • Request format: none
  • Response format: JSON (JobDetailResponse)
curl -u admin:password https://face-api.xylolabs.com/api/v1/admin/jobs/550e8400-...
import requests
from requests.auth import HTTPBasicAuth

response = requests.get(
    "https://face-api.xylolabs.com/api/v1/admin/jobs/550e8400-...",
    auth=HTTPBasicAuth("admin", "password"),
)
print(response.json())
const basic = btoa("admin:password");
const response = await fetch("https://face-api.xylolabs.com/api/v1/admin/jobs/550e8400-...", {
  headers: { Authorization: `Basic ${basic}` },
});
console.log(await response.json());
using System.Net.Http.Headers;
using System.Text;

using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
    "Basic",
    Convert.ToBase64String(Encoding.ASCII.GetBytes("admin:password"))
);

var response = await client.GetAsync("https://face-api.xylolabs.com/api/v1/admin/jobs/550e8400-...");
Console.WriteLine(await response.Content.ReadAsStringAsync());

GET /api/v1/admin/jobs/{job_id}/download

Redirects (302) to the processed image URL.

  • Request format: none
  • Response format: redirect (302 Found)
curl -u admin:password -L https://face-api.xylolabs.com/api/v1/admin/jobs/550e8400-.../download -o processed.jpg
import requests
from requests.auth import HTTPBasicAuth

response = requests.get(
    "https://face-api.xylolabs.com/api/v1/admin/jobs/550e8400-.../download",
    auth=HTTPBasicAuth("admin", "password"),
    allow_redirects=True,
)
with open("processed.jpg", "wb") as f:
    f.write(response.content)
const basic = btoa("admin:password");
const response = await fetch("https://face-api.xylolabs.com/api/v1/admin/jobs/550e8400-.../download", {
  headers: { Authorization: `Basic ${basic}` },
});
const blob = await response.blob();
using System.Net.Http.Headers;
using System.Text;

using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
    "Basic",
    Convert.ToBase64String(Encoding.ASCII.GetBytes("admin:password"))
);

var response = await client.GetAsync("https://face-api.xylolabs.com/api/v1/admin/jobs/550e8400-.../download");
await using var output = File.Create("processed.jpg");
await response.Content.CopyToAsync(output);

API keys

All /api/v1/admin/api-keys* endpoints require the database-backed mode; they return 501 when the database tier is disabled.