Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.lasscyber.com/llms.txt

Use this file to discover all available pages before exploring further.

Network requests can fail anywhere — connection reset, timeout, gateway 502, ambiguous 5xx. To make retries safe on write endpoints without creating duplicate resources, send an Idempotency-Key header on the original request and on every retry.

How it works

When the API receives a request with an Idempotency-Key:
  1. First time with that key + tenant: process the request normally and cache the response keyed off (tenant_id, idempotency_key, body_hash) for 24 hours.
  2. Same key + same body: return the cached response. The request is not processed again.
  3. Same key + different body: return idempotency_conflict (HTTP 409) so you know the key was reused with mismatched intent.
Idempotency keys are tenant-scoped; another tenant with the same key value sees no collision.

Where to use it

Use Idempotency-Key on every write call:
  • POST /api/v1/policies/
  • POST /api/v1/yara-rules/
  • POST /api/v1/yara-policies/
  • POST /api/v1/sdp/policies/
  • POST /api/v1/safety-policies/
  • POST /api/v1/api-keys/
  • POST /api/v1/tenants/
  • POST /api/v1/billing/portal-session
  • POST /api/v1/billing/create-checkout-session
  • POST /api/v1/support/tickets
Read endpoints (GET) are naturally idempotent and ignore the header. The hero POST /api/v1/analyze/ deliberately does not dedupe on Idempotency-Key. Each analysis is a fresh decision; you almost never want a cached one. If you need dedupe at your application layer (e.g. retrying the same prompt should not run analyzers twice in 100 ms), do it in your own caller.

Generating a key

A UUID v4 is the simplest choice. Both SDKs accept any string; pick something with enough entropy that you will not accidentally collide with another caller in your tenant.
curl -X POST https://api.lasscyber.com/api/v1/policies/ \
  -H "Authorization: Bearer ak_live_…" \
  -H "Idempotency-Key: 6f1e3c00-2c5a-4c58-9b2c-2b6f7a4f3a9d" \
  -H "Content-Type: application/json" \
  -d '{ "name": "inbound-strict", "slug": "inbound-strict", ... }'
Reuse the same key across every retry of the same logical write. If you generate a fresh key per retry, you defeat the protection.

SDK helpers

Python

The Python SDK auto-generates an idempotency key on every retried write when you do not pass one explicitly. To control it yourself:
from agnes import Agnes
import uuid

agnes = Agnes()

agnes.policies.create(
    policy,
    idempotency_key=str(uuid.uuid4()),
)

TypeScript

import { Agnes } from "@lasscyber/agnes-security";

const agnes = new Agnes();

await agnes.policies.create(policy, {
  idempotencyKey: crypto.randomUUID(),
});

Conflicts

If you reuse a key with a different body, the API returns:
HTTP/1.1 409 Conflict
{
  "detail": "Idempotency-Key was reused with a different request body.",
  "code": "idempotency_conflict",
  "request_id": "...",
  "doc_url": "https://docs.lasscyber.com/errors/idempotency_conflict"
}
Recovery: pick a new key and re-send.

Cache lifetime

  • 24 hours from the first request. After that the key is forgotten and a new request with the same key is treated as a fresh write.
  • Cache entries are not visible across tenants.
  • Cache entries survive Cloud Run autoscale events (the cache is Postgres-backed).

Common pitfalls

  • Generating the key inside the retry loop. A fresh key per retry is a different request as far as Agnes is concerned. Generate the key once outside the retry loop.
  • Using the same key for different operations. A key scopes to the full request body, so different operations naturally have different bodies — but using "create-policy-1" for both a policy create and a rule create is asking for confusion. Prefer UUIDs.
  • Sending an empty key. The API ignores empty / whitespace-only values. To use idempotency, send a real value.

Next