Retries, limits and rate limits
403 and 429 are different problems
A rate limit means "slow down, try again in a second" and answers 429 VCAP_RATE_LIMITED. A monthly limit agreed for your organization means "not until the month rolls over" and answers 403 VCAP_LIMIT_REACHED. They do not share a status code, because a client that cannot tell them apart retries the second one forever.
HTTP/1.1 403 Forbidden
{"code":"VCAP_LIMIT_REACHED","message":"…","limit":"api_verify_per_month",
"resets_at":"2026-10-01T00:00:00Z"}
The body names the limit and when it rolls over. A limit of zero is the endpoint switched off for your organization. Limits are agreed with us, not bought here: this API has no plans and no payments.
Two units, checked separately
verify is counted on every verification, and detect only when you ask for the watermark detector, so an organization past its detect limit can still verify. Both are checked before any work is dispatched, so a refusal never leaves work behind.
Limits are per organization, not per environment: a sandbox that uses the month's verifications is a fact about the organization, and hiding it behind a separate sandbox budget would only move the surprise.
It is a ceiling on accounted usage. Usage is collected on a pull, so you can overshoot by whatever you use between two collections. We would rather tell you that than keep a second, faster counter that disagrees with the one we report from.
Rate limits
120 requests a minute per source address, 600 a minute per key. The per-address limit is counted before authentication, so probing keys is charged to the prober.
Idempotency
Send Idempotency-Key: <your string> on a request you may retry. Keys are scoped to your environment and to the endpoint.
| First request | The work runs; the response is remembered. |
| Same key, same body | The same bytes, with Idempotent-Replay: true. No work redone. |
| Same key, different body | 422 VCAP_IDEMPOTENCY_KEY_REUSED — refused, never served. |
| Same key, first still running | 409 VCAP_IDEMPOTENCY_IN_PROGRESS. |
| Key older than 24 h | Forgotten. The work runs again, and is counted again. |
| Key over 255 characters | 400 VCAP_IDEMPOTENCY_KEY_INVALID. Nothing runs. |
Only a success is remembered. After a 403 or a 502 the retry you are supposed to make is re-evaluated rather than replayed — otherwise a transient answer would stick for the rest of the window.
The 24-hour retention is the whole privacy budget of the feature: the stored response is the only place a verdict about your file lingers on our side, and the row is deleted, not archived, past the window.