API Reference
Integrate ConceptViz diagram generation into your applications via REST API
Authentication
All API requests require an API key passed via the Authorization header.
Authorization: Bearer cvk_your_api_key_hereYou can create and manage API keys in your Settings > API Keys dashboard.
Your API key grants full access to your account credits. Keep it secret and never expose it in client-side code.
Base URL
https://conceptviz.app/api/v1Generate Diagrams
Generation is asynchronous. You submit a request, receive a task ID, then poll for results.
Step 1: Submit Generation Request
POST /api/v1/generate
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
prompt | string | Yes* | A single text prompt describing the diagram |
prompts | string[] | Yes* | Array of prompts for batch generation (max 4) |
model | string | No | Public model family: "cv-2" (default) or "cv-1" |
quality | string | No | Image resolution. CV-2 uses "2k" automatically. CV-1 supports "2k" (default) or "4k" |
aspectRatio | string | No | Aspect ratio (e.g. "16:9", "1:1", "4:3", "9:16", "a4-portrait") |
Provide either prompt (single) or prompts (batch) — not both. If both are provided, prompts takes priority.
Response
{
"taskId": "vaW29_MJ1wbnyFU4bl_pd",
"status": "pending",
"model": "cv-2",
"quality": "2k",
"aspect_ratio": "16:9",
"credits_used": 2,
"credits_remaining": 79,
"poll_url": "/api/v1/task/vaW29_MJ1wbnyFU4bl_pd"
}Step 2: Poll for Results
GET /api/v1/task/{taskId}
Poll this endpoint every 3–5 seconds until status is completed or failed. Typical generation takes 30–90 seconds.
Response (completed)
{
"status": "completed",
"images": [
{
"url": "https://r2.conceptviz.app/images/abc123.png",
"prompt": "water cycle diagram"
}
]
}Response (failed)
{
"status": "failed",
"error": "Image generation failed. Please try again later.",
"code": "GENERATION_FAILED",
"credits_refunded": true
}Response (pending/processing)
{
"status": "processing"
}Edit Images
Image editing is also asynchronous. Submit one or more input images with an edit prompt, then poll the same task endpoint for the edited result.
POST /api/v1/edit
JSON Request Body
Use this format when your input image is already hosted at a public URL or provided as a data URL.
| Parameter | Type | Required | Description |
|---|---|---|---|
prompt | string | Yes | Edit instructions for the image |
images | string[] | Yes | Input image URLs or data:image/...;base64,... values (max 4) |
model | string | No | Public model family: "cv-2" (default) or "cv-1" |
quality | string | No | Image resolution. CV-2 uses "2k" automatically. CV-1 supports "2k" (default) or "4k" |
aspectRatio | string | No | Output aspect ratio (e.g. "16:9", "1:1", "4:3", "9:16") |
Image inputs are moderated before processing. Uploaded images can be up to 20MB each, with a maximum of 4 images per edit request.
curl -X POST https://conceptviz.app/api/v1/edit \
-H "Authorization: Bearer cvk_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"prompt": "Replace the annotations with a clean professional architecture diagram",
"images": ["https://example.com/marked-up-diagram.png"],
"model": "cv-2"
}'Multipart Upload
Use this format to upload local image files directly.
curl -X POST https://conceptviz.app/api/v1/edit \
-H "Authorization: Bearer cvk_your_api_key_here" \
-F "prompt=Convert this sketch into a polished system diagram" \
-F "image=@./sketch.png" \
-F "model=cv-2"To provide multiple input images, repeat the image form field.
curl -X POST https://conceptviz.app/api/v1/edit \
-H "Authorization: Bearer cvk_your_api_key_here" \
-F "prompt=Combine these references into one clean diagram" \
-F "image=@./reference-1.png" \
-F "image=@./reference-2.png"Response
{
"taskId": "vaW29_MJ1wbnyFU4bl_pd",
"status": "pending",
"model": "cv-2",
"quality": "2k",
"aspect_ratio": "16:9",
"credits_used": 2,
"credits_remaining": 79,
"poll_url": "/api/v1/task/vaW29_MJ1wbnyFU4bl_pd"
}Credit Cost
| Model | Quality | Credits per Image |
|---|---|---|
cv-2 | 2k balanced | 2 |
cv-1 | 2k | 1 |
cv-1 | 4k | 2 |
Credits are consumed when the task is submitted. If generation fails, credits are automatically refunded.
Examples
cURL
# Step 1: Submit
RESPONSE=$(curl -s -X POST https://conceptviz.app/api/v1/generate \
-H "Authorization: Bearer cvk_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"prompt": "water cycle diagram showing evaporation, condensation, and precipitation",
"model": "cv-2",
"quality": "2k"
}')
TASK_ID=$(echo $RESPONSE | jq -r '.taskId')
echo "Task ID: $TASK_ID"
# Step 2: Poll until complete
while true; do
RESULT=$(curl -s https://conceptviz.app/api/v1/task/$TASK_ID \
-H "Authorization: Bearer cvk_your_api_key_here")
STATUS=$(echo $RESULT | jq -r '.status')
echo "Status: $STATUS"
if [ "$STATUS" = "completed" ] || [ "$STATUS" = "failed" ]; then
echo $RESULT | jq .
break
fi
sleep 5
donePython
import requests
import time
API_KEY = "cvk_your_api_key_here"
BASE_URL = "https://conceptviz.app/api/v1"
HEADERS = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
}
# Step 1: Submit
response = requests.post(
f"{BASE_URL}/generate",
headers=HEADERS,
json={
"prompt": "photosynthesis process diagram",
"model": "cv-2",
"quality": "2k",
},
)
data = response.json()
task_id = data["taskId"]
print(f"Task submitted: {task_id}")
print(f"Credits used: {data['credits_used']}, remaining: {data['credits_remaining']}")
# Step 2: Poll for result
while True:
result = requests.get(f"{BASE_URL}/task/{task_id}", headers=HEADERS).json()
print(f"Status: {result['status']}")
if result["status"] == "completed":
for image in result["images"]:
print(f"Image URL: {image['url']}")
break
elif result["status"] == "failed":
print(f"Error: {result['error']}")
print(f"Credits refunded: {result.get('credits_refunded', False)}")
break
time.sleep(5)JavaScript / TypeScript
const API_KEY = "cvk_your_api_key_here";
const BASE_URL = "https://conceptviz.app/api/v1";
// Step 1: Submit
const submitResponse = await fetch(`${BASE_URL}/generate`, {
method: "POST",
headers: {
Authorization: `Bearer ${API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
prompts: [
"cell division mitosis diagram",
"DNA double helix structure",
],
model: "cv-2",
quality: "2k",
}),
});
const { taskId, credits_used, credits_remaining } = await submitResponse.json();
console.log(`Task: ${taskId}, credits used: ${credits_used}`);
// Step 2: Poll for result
while (true) {
const pollResponse = await fetch(`${BASE_URL}/task/${taskId}`, {
headers: { Authorization: `Bearer ${API_KEY}` },
});
const result = await pollResponse.json();
console.log(`Status: ${result.status}`);
if (result.status === "completed") {
console.log("Images:", result.images);
break;
} else if (result.status === "failed") {
console.error("Failed:", result.error);
break;
}
await new Promise((r) => setTimeout(r, 5000));
}Error Handling
The API returns standard HTTP status codes with JSON error bodies:
{
"error": "Human-readable error message",
"code": "ERROR_CODE"
}Error Codes
| HTTP Status | Code | Description |
|---|---|---|
400 | INVALID_BODY | Request body is not valid JSON |
400 | IMAGE_REQUIRED | Edit request did not include an input image |
400 | INVALID_IMAGE | Input image data, URL, or file type is invalid |
400 | PROMPT_REQUIRED | No prompt or prompts provided |
400 | TOO_MANY_IMAGES | More than 4 images in one edit request |
400 | TOO_MANY_PROMPTS | More than 4 prompts in one request |
400 | UNSUPPORTED_MODEL | Model must be cv-2 or cv-1 |
401 | UNAUTHORIZED | Missing or invalid Authorization header |
401 | INVALID_API_KEY | API key is invalid or disabled |
402 | INSUFFICIENT_CREDITS | Not enough credits (includes credits_remaining) |
403 | PLAN_REQUIRED | API access requires a Pro plan or higher |
403 | QUALITY_NOT_ALLOWED | Requested quality is not available for your plan |
403 | PLAN_LIMIT_EXCEEDED | Batch size exceeds your plan limit |
404 | TASK_NOT_FOUND | Task ID not found or doesn't belong to your account |
429 | MODERATION_RATE_LIMITED | Too many moderation requests in a short period |
400 | INPUT_MODERATION_BLOCKED | Prompt or input image was blocked by safety checks |
500 | CREDIT_CONSUMPTION_FAILED | Credits could not be consumed |
500 | GENERATION_FAILED | Image generation failed (credits auto-refunded) |
Example: Handling Errors
response = requests.post(f"{BASE_URL}/generate", headers=headers, json=payload)
if response.status_code == 402:
data = response.json()
print(f"Not enough credits. Remaining: {data.get('credits_remaining', 0)}")
elif response.status_code != 200:
print(f"Error: {response.json()['error']}")
else:
data = response.json()
task_id = data["taskId"]
# Start polling...Limits
| Constraint | Value |
|---|---|
| Max images per request | 4 |
| Max API keys per account | 5 |
| Generation time | 30–90 seconds typical |
| Poll interval | 3–5 seconds recommended |
| Available models | cv-2 (default), cv-1 |
| Available qualities | cv-2: 2k; cv-1: 2k, 4k |
