The D8alytics API.
Generate labeled datasets, track jobs, and pull results — straight from your own code.
Before you start
Four steps, about five minutes.
- Be on Pro or Enterprise. The API is not included in the Free plan — see plans.
- Create an API key in Dashboard → API keys and copy it. It is shown only once.
- Pick your system in the tabs on every example below — Windows, macOS / Linux, or Python. Choosing once sets it for the whole page.
- Run Check your key first. If that works, everything else will work too.
Overview
The API is a small REST interface over the same engine that powers the studios. All requests go to one base URL and return JSON.
Base URL
https://api.d8alytics.com/v1
The typical flow: create a dataset job, poll its status until it's completed, then request a download link for the resulting ZIP.
Authentication
Send your API key as a Bearer token on every request. Create and revoke keys in Dashboard → API keys. A key is shown only once when you create it, so store it safely. Keep keys server-side — never ship one in browser code.
Authorization: Bearer d8_live_xxxxxxxxxxxxxxxxxxxxxxxx
Quickstart
Generate a dataset end to end: start a job, wait for it, save the ZIP. Copy the whole block, put your key in, and run it.
$BASE = "https://api.d8alytics.com/v1"
$KEY = "d8_live_YOUR_KEY"
$H = @{ Authorization = "Bearer $KEY"; "Content-Type" = "application/json" }
# 1) start a job
$body = @{
name = "PPE detection"
parameters = @{
prompt = "workers on a construction site, CCTV angle"
classes = @("person","hard hat","safety vest")
num_images = 6
}
} | ConvertTo-Json -Depth 6
$job = Invoke-RestMethod -Uri "$BASE/jobs" -Headers $H -Method POST -Body $body
"Job started: $($job.job_id)"
# 2) wait until it is finished (checks every 15 seconds)
do {
Start-Sleep -Seconds 15
$s = Invoke-RestMethod -Uri "$BASE/jobs/$($job.job_id)" -Headers $H
"$($s.status) $($s.progress)%"
} while ($s.status -eq "pending" -or $s.status -eq "processing")
# 3) get the download link and save the ZIP
$dl = Invoke-RestMethod -Uri "$BASE/datasets/$($s.dataset_id)/download" -Headers $H
Invoke-WebRequest -Uri $dl.url -OutFile "dataset.zip"BASE="https://api.d8alytics.com/v1"
KEY="d8_live_YOUR_KEY"
AUTH="Authorization: Bearer $KEY"
# 1) start a job (needs curl and jq)
JOB=$(curl -s -X POST "$BASE/jobs" -H "$AUTH" -H "Content-Type: application/json" \
-d '{"name":"PPE detection","parameters":{
"prompt":"workers on a construction site, CCTV angle",
"classes":["person","hard hat","safety vest"],
"num_images":6}}' | jq -r .job_id)
echo "Job started: $JOB"
# 2) wait until it is finished (checks every 15 seconds)
while true; do
S=$(curl -s "$BASE/jobs/$JOB" -H "$AUTH")
echo "$(echo "$S" | jq -r .status) $(echo "$S" | jq -r .progress)%"
case "$(echo "$S" | jq -r .status)" in completed|failed|cancelled) break;; esac
sleep 15
done
# 3) get the download link and save the ZIP
DS=$(echo "$S" | jq -r .dataset_id)
URL=$(curl -s "$BASE/datasets/$DS/download" -H "$AUTH" | jq -r .url)
curl -sL "$URL" -o dataset.zip# pip install requests
import time, requests
BASE = "https://api.d8alytics.com/v1"
KEY = "d8_live_YOUR_KEY"
H = {"Authorization": f"Bearer {KEY}"}
# 1) start a job
job = requests.post(f"{BASE}/jobs", headers=H, json={
"name": "PPE detection",
"parameters": {
"prompt": "workers on a construction site, CCTV angle",
"classes": ["person", "hard hat", "safety vest"],
"num_images": 6,
},
}).json()
print("Job started:", job["job_id"])
# 2) wait until it is finished (checks every 15 seconds)
while True:
s = requests.get(f"{BASE}/jobs/{job['job_id']}", headers=H).json()
print(s["status"], s["progress"], "%")
if s["status"] in ("completed", "failed", "cancelled"):
break
time.sleep(15)
# 3) get the download link and save the ZIP
url = requests.get(f"{BASE}/datasets/{s['dataset_id']}/download", headers=H).json()["url"]
with open("dataset.zip", "wb") as f:
f.write(requests.get(url).content)Generation takes a few minutes — that is the GPU doing real work, not a problem.
The ZIP is ready to train on: images/,
labels/, data.yaml.
Check your key
Confirms a key works and shows the limits on your plan. Good first call.
Invoke-RestMethod -Uri "https://api.d8alytics.com/v1/me" `
-Headers @{ Authorization = "Bearer YOUR_API_KEY" }curl https://api.d8alytics.com/v1/me \
-H "Authorization: Bearer YOUR_API_KEY"import requests
r = requests.get("https://api.d8alytics.com/v1/me",
headers={"Authorization": "Bearer YOUR_API_KEY"})
print(r.json())200 OK
{
"user_id": "cbcd9721-bbc3-4a0e-b3e9-8bf92110421d",
"email": "[email protected]",
"plan": "pro",
"limits": {
"requests_per_minute": 60,
"dataset_jobs_per_day": 50,
"max_images_per_job": 15,
"max_classes_per_job": 6
}
}
Create a dataset job
Starts a generation job. Returns a job_id you can poll. Jobs run in the same queue as the studios.
$body = @{
name = "PPE detection"
parameters = @{
prompt = "workers on a construction site, CCTV angle"
classes = @("person","hard hat","safety vest")
label_guide = "hard hat: box only the helmet, not the head."
num_images = 6
image_size = 1024
augment_copies = 0
}
} | ConvertTo-Json -Depth 6
Invoke-RestMethod -Uri "https://api.d8alytics.com/v1/jobs" -Method POST -Body $body `
-Headers @{ Authorization = "Bearer YOUR_API_KEY"; "Content-Type" = "application/json" }curl -X POST https://api.d8alytics.com/v1/jobs \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "PPE detection",
"parameters": {
"prompt": "workers on a construction site, CCTV angle",
"classes": ["person", "hard hat", "safety vest"],
"label_guide": "hard hat: box only the helmet, not the head.",
"num_images": 6,
"image_size": 1024,
"augment_copies": 0
}
}'import requests
r = requests.post("https://api.d8alytics.com/v1/jobs",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={
"name": "PPE detection",
"parameters": {
"prompt": "workers on a construction site, CCTV angle",
"classes": ["person", "hard hat", "safety vest"],
"label_guide": "hard hat: box only the helmet, not the head.",
"num_images": 6,
"image_size": 1024,
"augment_copies": 0,
},
})
print(r.json())201 Created
{
"job_id": "9b0e46c1-417f-4320-99a7-b2b0c4c7cc00",
"status": "pending",
"created_at": "2026-07-27T10:12:04.518Z"
}
Get job status
Poll until status is completed (or failed / cancelled). Polling every 10–15 seconds is plenty.
Invoke-RestMethod -Uri "https://api.d8alytics.com/v1/jobs/JOB_ID" `
-Headers @{ Authorization = "Bearer YOUR_API_KEY" }curl https://api.d8alytics.com/v1/jobs/JOB_ID \
-H "Authorization: Bearer YOUR_API_KEY"import requests
r = requests.get("https://api.d8alytics.com/v1/jobs/JOB_ID",
headers={"Authorization": "Bearer YOUR_API_KEY"})
print(r.json())200 OK
{
"job_id": "9b0e46c1-417f-4320-99a7-b2b0c4c7cc00",
"type": "dataset",
"status": "completed",
"stage": "completed",
"progress": 100,
"created_at": "2026-07-27T10:12:04.518Z",
"started_at": "2026-07-27T10:12:19.002Z",
"completed_at": "2026-07-27T10:18:41.774Z",
"dataset_id": "b2f1c0de-8a44-4f2e-9d31-6f0b7a2c1e55",
"total_images": 6,
"total_objects": 41,
"size_bytes": 5241880,
"error": null
}
status is one of pending, processing, completed, failed, cancelled. While a job runs, stage and progress show how far along it is; dataset_id stays null until it finishes.
Download a dataset
Returns a short-lived signed URL to the dataset ZIP (YOLO format: images/, labels/, data.yaml, plus metadata). Follow the URL to fetch the file.
$dl = Invoke-RestMethod -Uri "https://api.d8alytics.com/v1/datasets/DATASET_ID/download" `
-Headers @{ Authorization = "Bearer YOUR_API_KEY" }
# then save the file
Invoke-WebRequest -Uri $dl.url -OutFile "dataset.zip"URL=$(curl -s https://api.d8alytics.com/v1/datasets/DATASET_ID/download \
-H "Authorization: Bearer YOUR_API_KEY" | jq -r .url)
# then save the file
curl -sL "$URL" -o dataset.zipimport requests
url = requests.get("https://api.d8alytics.com/v1/datasets/DATASET_ID/download",
headers={"Authorization": "Bearer YOUR_API_KEY"}).json()["url"]
# then save the file
with open("dataset.zip", "wb") as f:
f.write(requests.get(url).content)200 OK
{ "url": "https://cdn-lfs.huggingface.co/...signed...", "expires_in": 300 }
The link expires in about 5 minutes — request a new one whenever you need it. If the dataset isn't finished yet you get 409 not_ready.
Parameters
All generation options go inside parameters. Only prompt and classes are required.
| Field | Type | Notes |
|---|---|---|
prompt | string | Required. What the images should show. |
classes | string[] | Required. Objects to detect, one label each. Max 6. |
label_guide | string | Per-class definitions. Strongly recommended for accurate labels. |
num_images | int | Images to generate. Default 5, max 15. |
image_size | int | 640 or 1024. Default 1024. |
environments | string[] | Optional. Rotated across images for variety. |
captures | string[] | Optional. Capture/realism variety. |
augment_copies | int | Extra augmented variants per image (0–10). Default 0. |
Errors & limits
Every error returns the same shape, with a matching HTTP status:
{ "error": { "code": "limit_exceeded", "message": "Too many images: 40. Your plan allows 15 per job." } }
| Status | Code | Meaning |
|---|---|---|
400 | invalid_request | A required field is missing or malformed. |
400 | limit_exceeded | More images or classes than your plan allows. |
401 | unauthorized | Key missing, wrong, or revoked. |
403 | forbidden | Plan without API access, or the resource is another account's. |
404 | not_found | Unknown job, dataset, or endpoint. |
409 | not_ready | The dataset hasn't finished generating yet. |
429 | rate_limited | Too many requests per minute, or the daily job quota is used up. |
Rate limits
| Plan | Requests / min | Dataset jobs / day | Images / job | Classes / job |
|---|---|---|---|---|
| Pro | 60 | 50 | 15 | 6 |
| Enterprise | 300 | 500 | 15 | 6 |
Need higher image or class limits for a large workload? Talk to us — these are tied to dedicated generation capacity.