Skip to content

Errors & retries

HTTP status codes

Status Meaning What to do
200 OK / 201 Created / 204 No Content Success Use the response body.
400 Bad Request Validation failed (missing required field, malformed JSON, unknown enum value). Fix the request; do not retry as-is.
401 Unauthorized JWT expired, missing, or invalid. Re-authenticate via /api/Login/Authenticate and replay the request.
403 Forbidden The authenticated tenant lacks access to the requested resource. Confirm the resource belongs to your tenant; do not retry.
404 Not Found Resource (batch, work item) does not exist within your tenant. Verify the id; check whether the resource was created with a different tenant's credentials.
409 Conflict Optimistic-concurrency clash on RowVersion (someone else updated the resource since you read it). Re-fetch the resource and re-apply your change.
422 Unprocessable Entity Domain-level validation failure — returns a list of error messages. Fix the offending fields; do not retry as-is.
500 Internal Server Error Server-side failure. Safe to retry once after a short backoff; if it persists, contact support.

Idempotency

  • AddWorkItem* endpoints assign a server-generated workItemId (and workBatchId). Retrying an AddWorkItem* without remembering the returned ids creates a duplicate work item. If a submit fails mid-flight (network error, timeout) and you have no ids, fetch by customerReference via GET /api/VlmMad/GetResultByReference before resubmitting.
  • GetResult / GetResultByReference / status-poll endpoints are idempotent — safe to retry.
  • All actions are tenant-scoped through the JWT, so retries cannot leak into another tenant.

Rate limits

No HTTP-level rate limit is enforced today. Treat this as an implementation detail that may change; if you see 429 Too Many Requests in the future, retry with exponential backoff starting at 1s.

Webhook delivery

Result webhooks are sent by WebhookService, which runs as a cron job every 3 minutes. Each work item with a configured webhookUrl has a WebhookCallCount budget (default from AppSettings.WebhookRetryCount); failures decrement that counter and schedule the next attempt with polynomial backoff — the delay is (maxRetryCount - remainingCalls)^2 * 30 seconds, so retries spread out further over time. Both transient network failures and non-2xx responses (4xx and 5xx) are retried until the counter reaches zero. Your webhook receiver must therefore:

  • Accept the same workItemId more than once and treat duplicates as no-ops.
  • Respond 200 quickly (within a few seconds); do the heavy work asynchronously.
  • Use the payload itself as the source of truth — do not assume webhook delivery order.

If your endpoint exhausts the retry budget, the server gives up and the result is still queryable via the normal status-poll endpoints (GetResult / GetResultByReference).