Aller au contenu

Idempotency & quotas

Write endpoints (POST) and the RPA tarification endpoint apply safeguards so that retries, network glitches and accidental loops never produce duplicates or runaway costs.

Idempotency-Key

Send an Idempotency-Key header on every POST. The same key + same cabinet + same endpoint returns the same result instead of creating a second resource.

curl -X POST https://dev.aeliam.ai/api/v1/public/opportunities \
  -H "X-API-Key: aelm_dev_xxxxxxxx" \
  -H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \
  -H "Content-Type: application/json" \
  -d '{"title":"New lead","product":"mrp","contact":{"last_name":"Martin"}}'
  • A repeated key returns the original response with HTTP 200 (idempotent replay) instead of 201.
  • Two truly concurrent requests with the same key may yield 409 idempotency_conflict — retry the same request.
  • Use a fresh UUID per distinct operation.

Cursor pagination

List endpoints are keyset-paginated with an opaque, HMAC-signed cursor:

{ "data": [  ], "next_cursor": "…", "has_more": true, "count": 50 }
  • limit: 1–100 (default 50), clamped server-side.
  • Pass next_cursor back as ?cursor=…. Never craft or mutate a cursor — it is signed and will be rejected.
  • Cursors are deterministic (by created_at + id), so they stay valid as new data arrives.

RPA tarification — quotas & anti-abuse

POST /automation/tarifications triggers a real, billable robot run. Extra guards apply:

error (HTTP) Meaning What to do
rpa_quota_exceeded (429) Cabinet hit its hourly tarification quota Wait until reset_at
rpa_replay_detected (429) Identical dicData submitted again too soon Don't loop; wait the indicated delay
rpa_circuit_open (503) Too many failures on that insurer — breaker open Retry later
api_rpa_temporarily_disabled (503) Global kill-switch is on Retry later

dry_run first

Validate the whole pipeline (schema, quota, credentials) without creating a job or incurring cost:

curl -X POST https://dev.aeliam.ai/api/v1/public/automation/tarifications \
  -H "X-API-Key: aelm_dev_xxxxxxxx" -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"compagnie":"axa","produit":"mrp","dry_run":true,
       "dicData":{"raison_sociale":"Acme","siret":"00000000000000"}}'
{
  "job_id": null,
  "status": "dry_run_ok",
  "validation": {
    "schema_ok": false,
    "missing_required_fields": ["chiffre_affaires"],
    "quota": { "remaining": 95, "limit": 100 },
    "credentials_configured": true,
    "would_cost_credits": 5
  },
  "credits_consumed": 0
}

Cost model (observe mode)

Today, tarifications are not billed. The platform records a nominal cost (~5 credits per tarification) in observe mode — no debit, no blocking. The credits_consumed / billing_mode: "observe" fields are informational while pricing is finalised.

Job lifecycle

After a real enqueue you get a job_id. Poll GET /automation/jobs/{job_id}:

{
  "job_id": "…",
  "status": "completed",
  "compagnie": "axa",
  "produit": "mrp",
  "devis_id": "…",
  "result": {
    "tarif_eur": 376.65,
    "suspens": "0000012345678901",
    "pdf_url": "/api/v1/public/devis/<devis_id>/pdf"
  },
  "progress": { "step": "ack:completed", "percent": 100 }
}

Statuses: pendingclaimedrunning → (mfa_required / awaiting_mfa) → completed | partial | failed | cancelled. Provide a callback_webhook_id to be notified instead of polling — see Webhooks.