Guides
Best practices
Build a reliable Clipia API integration — idempotent retries, webhooks over polling, error and 429 handling, cost estimates and storing request_id.
A reliable Clipia API integration with predictable costs comes down to five practices: make submissions idempotent, prefer webhooks to polling, handle errors and 429 with backoff, estimate the cost before you submit, and store request_id on your side.
Idempotent retries
Send an Idempotency-Key with every submission — a unique UUID v4 per logical request. If the connection drops, retry with the same key and the same body: you get the same request_id back, with no second generation and no second charge. A key lives for 24 hours within a single API key.
curl -X POST https://api.clipia.ai/v1/models/nano-banana-2 \
-H "Authorization: Bearer $CLIPIA_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 8f3a1c7e-2b41-4d2a-9c0e-1200304cf45b" \
-d '{ "input": { "prompt": "a sunset over mountains, cinematic" } }'| Situation | Result |
|---|---|
| Same key, same body | Same request_id, no second charge |
| Same key, different model or body | 409 idempotency_key_reuse |
| Retry while the first request is still being processed | 409 request_in_progress — retry in a few seconds |
One key per logical request
Create a new UUID for every new generation, not for every network attempt. The SDKs add a random key on their own, but to retry safely, pass your own key and reuse it. Don't put personal data in the key. See Idempotency.
Webhooks over polling
Pass a webhook_url (https:// only) when you submit, and Clipia sends a POST when the job finishes, so you don't have to poll. Keep polling as a fallback and poll no more than once every 1–3 seconds.
- Respond with
2xxwithin 10 seconds, otherwise the delivery is retried — up to 15 attempts with growing delays, for about 24 hours. - Verify the
X-Clipia-Signature(HMAC-SHA256) on every delivery. Each API key has its own webhook secret. - Handle deliveries idempotently by
request_id: the same delivery can arrive more than once.
See Webhooks.
Errors and 429
Errors share one format: an error object with type, code and message. Decide what to do from the HTTP status and code.
| HTTP | code | What to do |
|---|---|---|
400 / 422 | invalid_request / model_input_invalid | Fix the body or parameters; don't retry as is |
401 / 403 | invalid_api_key / insufficient_scope | Check the key and its permissions |
402 | insufficient_credits | Top up the balance |
409 | request_in_progress | Retry in a few seconds with the same idempotency key |
429 | rate_limit_exceeded | Wait Retry-After seconds and retry |
429 | concurrency_limit_exceeded | Wait for one of your jobs to finish |
500 / 503 | internal_error / service_unavailable | Retry with backoff |
On 429, rely on Retry-After and the RateLimit-* headers. RateLimit-Reset is the moment the window resets, in Unix seconds, not the number of seconds until then:
RateLimit-Limit: 120
RateLimit-Remaining: 0
RateLimit-Reset: 1760011260
Retry-After: 37Exponential backoff with jitter
For 429, 500 and 503, retry with growing delays plus random jitter — for example 1, 2, 4, 8 seconds, at most five attempts — so retries from different clients don't line up. Default limits are 120 requests per minute per key and 600 across all keys of an account. A concurrency limit applies only if one is set for the key or the account. See Rate limits.
Estimate cost before submitting
To price a specific set of parameters without queuing anything, call POST /v1/models/{model}/estimate — it returns credits. Use it to show the price to your users or to block expensive requests up front. On submission, the cost field holds the amount reserved for the job; if the balance is too low, the submission returns 402. See Cost estimation.
Pricing
Model prices change together with the catalog: estimate returns the exact amount in credits for your parameters, and on submit it arrives in the cost field before anything is charged.
Store the request_id
Save the request_id of every submission in your database right after the response. You need it to:
- match an incoming webhook to your own entity;
- poll
status_urlorresponse_urlwhen needed; - avoid processing the same delivery twice.
Pair Idempotency-Key with request_id
Store the Idempotency-Key → request_id pair. If the response to a submission is lost, retrying with the same key returns the same request_id, and no duplicate generation appears.
Python SDK
The official Clipia Python SDK (PyPI clipia 1.5.0) — Clipia and AsyncClipia clients, the generation queue, catalog and price estimates, webhook checks, errors.
Migrating from another generation API
Move an integration from another generation API to Clipia — the submit, status, result flow, keys, webhooks, credits and a pre-launch checklist.