Skip to content

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" } }'
SituationResult
Same key, same bodySame request_id, no second charge
Same key, different model or body409 idempotency_key_reuse
Retry while the first request is still being processed409 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 2xx within 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.

HTTPcodeWhat to do
400 / 422invalid_request / model_input_invalidFix the body or parameters; don't retry as is
401 / 403invalid_api_key / insufficient_scopeCheck the key and its permissions
402insufficient_creditsTop up the balance
409request_in_progressRetry in a few seconds with the same idempotency key
429rate_limit_exceededWait Retry-After seconds and retry
429concurrency_limit_exceededWait for one of your jobs to finish
500 / 503internal_error / service_unavailableRetry 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: 37

Exponential 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_url or response_url when 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.