Watercolor REST API
Complete guide to the asynchronous watercolor image API.
The REST API generates watercolor images from text or uploaded source images. It is asynchronous and stateless: creation endpoints return a task immediately, and your application polls that task to completion.
Base URL and API key
https://www.aiwatercolorgenerator.com
- Sign in and open Settings → API Keys.
- Create a key and copy it immediately. The complete key is shown only once.
- Store it as a server-side secret such as
AIWATERCOLOR_API_KEY.
Production keys start with awg_live_. Never put a key in client-side code, a URL, a public repository, or logs.
Quick start
curl https://www.aiwatercolorgenerator.com/api/v1/images/generations \
-X POST \
-H "Authorization: Bearer $AIWATERCOLOR_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: generation-example-001" \
-d '{
"prompt": "A red cottage beside a lake",
"model": "watercolor-lite",
"aspect_ratio": "4:3",
"resolution": "1k"
}'
The API normally returns HTTP 202 Accepted:
{
"id": "task_123",
"object": "image_task",
"status": "processing",
"operation": "generation",
"model": "watercolor-lite",
"resolution": "1k",
"aspect_ratio": "4:3",
"prompt": "A red cottage beside a lake",
"output": [],
"credits": { "charged": 1, "refunded": 0 },
"error": null,
"created_at": "2026-09-15T12:00:00.000Z",
"completed_at": null,
"links": { "self": "/api/v1/tasks/task_123" }
}
Use the response id in the task path and poll until succeeded, failed, or canceled:
curl https://www.aiwatercolorgenerator.com/api/v1/tasks/task_123 \
-H "Authorization: Bearer $AIWATERCOLOR_API_KEY"
Do not wait for generation inside the original POST. Processing continues after the Worker returns its response.
Common request rules
| Header | Required | Applies to | Description |
|---|---|---|---|
Authorization: Bearer <API_KEY> | Yes | All endpoints | Authenticates the account and task owner. |
Content-Type: application/json | Yes | Generate and edit | Body must be a JSON object, at most 32 KiB. |
Content-Type: multipart/form-data | Yes | Upload | Let curl -F or your HTTP client set the boundary. |
Content-Length | Yes | Upload | Must declare the bounded multipart body length; clients normally set it automatically. |
Idempotency-Key | Yes | Generate and edit | Caller-generated value containing 8–255 characters. |
Unknown JSON fields are rejected. Every response includes X-Request-Id; retain it for debugging. Responses use Cache-Control: no-store.
Idempotency and retries
- The first accepted generate/edit request normally returns HTTP
202. - Repeating the same key and normalized body returns the original task with HTTP
200and does not charge again. - Reusing the key with different parameters on the same operation returns
409 idempotency_conflict. - Keys are scoped to the API key and operation. Use a new UUID-like value for every new logical request.
- If a client times out, retry the identical body with the identical key.
- After a definite
502 provider_submission_failedresponse, the original key remains attached to that failed task. Submit the same body with a new key to start another task.
Models and credit cost
All output is watercolor; style_preset does not exist. Each request produces one image.
model | 1K | 2K | 4K | Maximum edit inputs |
|---|---|---|---|---|
watercolor-lite | 1 | 4 | 9 | 4 |
nano-banana-2 | 8 | 12 | 16 | 9 |
nano-banana-pro | 15 | 15 | 30 | 9 |
gpt-image-2 | 23 | 25 | 43 | 9 |
Values are credits per request. Credits are charged atomically when a new task is created. Failed or canceled tasks receive a full refund. API calls always use account credits and never consume the website's daily free allowance.
Supported resolution values: 1k, 2k, 4k. Supported aspect_ratio values: auto, 1:1, 4:3, 3:4, 16:9, 9:16, 21:9, 9:21.
Generate from text
POST /api/v1/images/generations
| Field | Type | Required | Default | Rules |
|---|---|---|---|---|
prompt | string | Yes | — | 1–4,000 Unicode characters after trimming. |
model | string | No | watercolor-lite | One of the four model identifiers above. |
aspect_ratio | string | No | auto | One of the supported ratios above. |
resolution | string | No | 1k | 1k, 2k, or 4k. |
curl https://www.aiwatercolorgenerator.com/api/v1/images/generations \
-X POST \
-H "Authorization: Bearer $AIWATERCOLOR_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 0199-generation-landscape-001" \
-d '{
"prompt": "Misty mountains reflected in a quiet lake",
"model": "nano-banana-2",
"aspect_ratio": "16:9",
"resolution": "2k"
}'
| HTTP | Meaning |
|---|---|
| 202 | New task accepted. |
| 200 | Idempotent replay; original task returned. |
| 400 | Invalid header, JSON, field, or value. |
| 401 | Missing or invalid API key. |
| 402 | Insufficient credits. |
| 409 | Idempotency conflict. |
| 429 | Rate or concurrent-task limit reached. |
| 502 | Provider rejected submission. |
| 503 | Generation or rate limiting unavailable. |
Upload an edit source
POST /api/v1/uploads
Upload third-party or local images before editing. The endpoint accepts a multipart file field containing a non-empty JPEG, PNG, or WebP image up to 10 MiB. It validates file signatures, not only filenames or submitted MIME types. Uploads do not use an idempotency key.
curl https://www.aiwatercolorgenerator.com/api/v1/uploads \
-X POST \
-H "Authorization: Bearer $AIWATERCOLOR_API_KEY" \
-F "file=@./source-image.png"
HTTP 201 Created:
{
"id": "upload_123",
"object": "image_upload",
"url": "https://cdn.aiwatercolorgenerator.com/api-inputs/.../upload_123.png",
"content_type": "image/png",
"size_bytes": 284193
}
Pass url unchanged to the edit endpoint. The upload id cannot replace the URL.
| HTTP | Meaning |
|---|---|
| 201 | Image validated and stored. |
| 400 | Missing, empty, oversized, or unsupported file. |
| 401 | Invalid API key. |
| 429 | Upload or IP limit reached. |
| 500 | Unexpected storage failure. |
| 503 | Storage unavailable. |
Edit uploaded images
POST /api/v1/images/edits
| Field | Type | Required | Default | Rules |
|---|---|---|---|---|
prompt | string | Yes | — | 1–4,000 Unicode characters after trimming. |
input_images | string[] | Yes | — | 1–4 URLs for Lite; 1–9 for other models; each at most 2,048 characters. |
model | string | No | watercolor-lite | One of the four supported models. |
aspect_ratio | string | No | auto | One of the supported ratios. |
resolution | string | No | 1k | 1k, 2k, or 4k. |
Every input must be an HTTPS URL returned by this API on trusted application storage. Arbitrary external URLs, URLs with credentials, custom ports, and HTTP URLs are rejected.
curl https://www.aiwatercolorgenerator.com/api/v1/images/edits \
-X POST \
-H "Authorization: Bearer $AIWATERCOLOR_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 0199-edit-portrait-001" \
-d '{
"prompt": "Preserve the person and composition with soft wet-on-wet washes",
"input_images": [
"https://cdn.aiwatercolorgenerator.com/api-inputs/.../upload_123.png"
],
"model": "watercolor-lite",
"aspect_ratio": "3:4",
"resolution": "2k"
}'
Responses match the generation endpoint. The returned task has operation: "edit".
Retrieve a task
GET /api/v1/tasks/{task_id}
Replace {task_id} with the id returned by generate/edit. Tasks are account-owned; another account's ID returns 404 task_not_found.
| Status | Terminal | Meaning |
|---|---|---|
queued | No | Created but not yet submitted. |
processing | No | Submitted and running. |
succeeded | Yes | output contains result URLs. |
failed | Yes | Inspect error.code; credits are refunded. |
canceled | Yes | Credits are refunded. |
Poll every 2–5 seconds. Stop at a terminal state and back off after 429 or transient 5xx responses.
Task fields
| Field | Type | Description |
|---|---|---|
id | string | Public task ID used in the polling URL. |
object | "image_task" | Stable object type. |
status | string | One of the five states above. |
operation | "generation" or "edit" | Creating operation. |
model | string or null | Public model identifier. |
resolution | string or null | Billable resolution. |
aspect_ratio | string or null | Requested ratio. |
prompt | string | Original caller prompt; internal instructions are not returned. |
output | array | Empty until success; items contain url and content_type. |
credits | object | charged and refunded integer amounts. |
error | object or null | Failed tasks expose a stable public code only. |
created_at | ISO 8601 string | Creation time. |
completed_at | ISO 8601 string or null | Terminal-state time. |
links.self | string | Relative polling URL. |
{
"id": "task_123",
"object": "image_task",
"status": "succeeded",
"operation": "generation",
"model": "watercolor-lite",
"resolution": "1k",
"aspect_ratio": "4:3",
"prompt": "A red cottage beside a lake",
"output": [
{
"url": "https://cdn.aiwatercolorgenerator.com/api-results/.../0.png",
"content_type": "image/png"
}
],
"credits": { "charged": 1, "refunded": 0 },
"error": null,
"created_at": "2026-09-15T12:00:00.000Z",
"completed_at": "2026-09-15T12:00:12.000Z",
"links": { "self": "/api/v1/tasks/task_123" }
}
A task accepted over HTTP can later fail. Then polling returns HTTP 200 with status: "failed", empty output, refunded credits, and an error such as:
{
"error": { "code": "generation_failed" },
"credits": { "charged": 1, "refunded": 1 }
}
HTTP errors
{
"error": {
"type": "invalid_request_error",
"code": "invalid_parameter",
"message": "model is not supported.",
"param": "model",
"request_id": "req_123"
}
}
Branch on stable code, not message. param identifies a related field/header or is null. request_id also appears as X-Request-Id.
| HTTP | Common codes | Action |
|---|---|---|
| 400 | invalid_content_type, invalid_json, request_too_large, invalid_idempotency_key | Correct request encoding or headers. |
| 400 | unknown_parameter, invalid_parameter, unsupported_model | Correct/remove the field named by param. |
| 400 | too_many_input_images, untrusted_image_url | Reduce inputs or use uploaded URLs. |
| 400 | missing_file, file_too_large, request_length_required, unsupported_image_type | Correct the upload or request headers. |
| 401 | invalid_api_key | Use an active Bearer key. |
| 402 | insufficient_credits | Add credits or choose a cheaper configuration. |
| 404 | task_not_found | Check the task ID and account. |
| 409 | idempotency_conflict | Reuse the original body or choose a new key. |
| 429 | rate_limit_exceeded | Wait for Retry-After. |
| 429 | concurrent_task_limit | Wait for an active task to finish. |
| 500 | internal_error | Retry with backoff; retain request_id. |
| 502 | provider_submission_failed | Retry the same body with a new key later. |
| 503 | provider_unavailable, storage_unavailable, rate_limit_unavailable | Retry later. |
Rate and concurrency limits
| Scope | Limit |
|---|---|
| Per client IP, all endpoints combined | 60 requests/minute |
| Per API key, generate + edit combined | 10 requests/minute |
| Per API key, uploads | 10 requests/minute |
| Per API key, task reads | 120 requests/minute |
Per account, queued + processing tasks | 3 concurrent tasks |
HTTP 429 includes Retry-After in seconds. IP and API-key limits apply independently.
Production checklist
- Call the API from your server and load the key from a secret manager.
- Retain each idempotency key and task
idso requests survive process restarts. - Poll every 2–5 seconds; stop at terminal states and back off on
429/transient5xx. - Log request IDs, never API keys or private source images.
- Treat
codeas stable andmessageas diagnostic text. - Copy successful outputs to your own storage if you need a separate retention policy.
Machine-readable definition
The OpenAPI 3.1 document is for code generators, schema tools, and automated clients. This page is the human guide and includes workflow, retry, billing, limits, and troubleshooting details that a schema cannot explain.