Docs · version 1

Management API reference

The API behind the dashboard, for your own scripts: the same resources, with a management key.

Overview

Base URL: https://{region}.api.alecturalabs.com/v1, where {region} is us, eu or au.

The OpenAPI 3.1 document this page is built from: openapi.yaml.

The management API serves the dashboard and the team's scripts. The gateway, which the team's servers call, is specified in gateway.md.

Hosts

Each region has its own host, and an environment's config and traffic are managed on its region's host. A key or an environment used on another region's host is refused with 403 wrong_region, naming the right host. The team, its members, projects and environments, in every region, are managed on us.api.alecturalabs.com, the one place the team directory is written.

Authentication

Every request carries Authorization: Bearer … with one of:

  • a management key (sk-alectura-mgmt-…), which acts on the environment it belongs to, with its permissions;
  • a session: the Stytch session JWT of a team member signed in to the dashboard, which acts with the member's role on the environment named by the Alectura-Environment header.
Permission Allows
read Config, organizations, users, request metadata, findings, signals, events, summaries
read_content A request's content and attachments; every read is recorded as a request.content_read event
manage Changing config, suspensions, organizations and users; dispositions; replays, evidence packs and assessments; API keys and webhooks

Roles give a team member permissions: admin has all three and manages the team; developer has all three; viewer has read. A key never holds more than whoever made it. Each operation names what it needs in x-alectura-permission, and team operations in x-alectura-role.

Conventions

  • Every object has an object field naming its type, and an id: a ULID with a prefix for its type, such as org_01M3PQE5R0….
  • Times are RFC 3339 in UTC with milliseconds. Money is a decimal string in USD.
  • Lists take limit (1 to 100, default 10), before or after (an id), and order (desc by default), and return {"object": "list", "data": […], "list_metadata": {"before", "after"}}.
  • POST takes an Idempotency-Key. A retry with the same key returns the first result for 24 hours; the same key with a different body is 422 idempotency_key_reused.
  • PATCH merges: an omitted field is unchanged, null clears a field, and a list is replaced whole.
  • Unknown fields and parameters are refused with 422. Responses only ever gain fields, so clients ignore fields they don't know.
  • Errors are {"code", "message", "errors", "request_id"}, where errors lists problems with particular fields.
  • Organizations and users take the team's own identifier as external_id, and up to 10 metadata pairs of strings.

Webhooks

Each event goes to every enabled endpoint that subscribes to it, as a POST of the event object. Order isn't guaranteed; ids and timestamps are.

  • Alectura-Signature: t=1790680024123, v1=5f1c… signs the delivery: v1 is the hex HMAC-SHA256, with the endpoint's secret, of the timestamp in milliseconds, a ., and the raw body. Check it, and that t is within 5 minutes. For 24 hours after a secret is rotated, a delivery carries a v1 for each secret.
  • Alectura-Delivery-Id stays the same across retries, so a receiver can drop duplicates.
  • Any 2xx within 10 seconds is success. Otherwise the delivery is tried again after 1 minute, 10 minutes, 1 hour and 12 hours. After the fifth failure it has failed, and the endpoint is disabled until the team enables it again.

Errors

Every operation can answer with these. The body is an Error, with a code to branch on and the request_id to quote to us.

4XXError

An error. 400 invalid_request: the body can't be parsed. 401 unauthenticated. 403 permission_denied or wrong_region. 404 not_found. 409 conflict: the object's state doesn't allow the change. 405 method_not_allowed, with Allow. 410 gone: the content or files have passed their retention. 422 validation_failed, with errors, or idempotency_key_reused or connection_test_failed. 429 rate_limited, with Retry-After, the seconds until the next request passes: each team may make a burst of 100 requests, refilling at 25 a second, whichever key or member makes them.

5XXError

503 unavailable: a store or service the API depends on failed. Retrying may help; send the same Idempotency-Key so a write that did commit isn't made twice. 500 internal_error: something failed that retrying won't fix, such as a stored object that can't be read; it is logged.

Organizations

The team's customers, as requests name them.

GET/organizations

List organizationsPermission: read

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

limitqueryinteger
beforequerystring

An object id. Returns the page before it.

afterquerystring

An object id. Returns the page after it.

orderquery"asc" | "desc"
suspendedqueryboolean

Responses

200OrganizationList

A page of organizations, newest first by default.

4XX

An error: see Errors

5XX

A service is unavailable: see Errors

Example response · 200

{
  "object": "list",
  "data": [
    {
      "object": "organization",
      "id": "org_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
      "external_id": "acme",
      "name": "Acme",
      "metadata": {"tier": "enterprise"},
      "plan": "pro",
      "suspended": false,
      "state": "active",
      "first_seen_at": "2026-09-29T14:02:11.482Z",
      "last_seen_at": "2026-09-29T14:02:11.482Z",
      "created_at": "2026-09-29T14:02:11.482Z",
      "updated_at": "2026-09-29T14:02:11.482Z"
    }
  ],
  "list_metadata": {"before": null, "after": null}
}

POST/organizations

Create an organizationPermission: manage

Organizations are also created by the first request that names them. Creating one first sets its name and metadata before any traffic.

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

Idempotency-Keyheaderstring

Makes a retry return the first result for 24 hours. The same key with a different body is refused with 422 idempotency_key_reused.

Body

OrganizationCreate

Responses

Example request body

{
  "external_id": "acme",
  "name": "Acme",
  "metadata": {"tier": "enterprise"}
}

Example response · 201

{
  "object": "organization",
  "id": "org_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "external_id": "acme",
  "name": "Acme",
  "metadata": {"tier": "enterprise"},
  "plan": "pro",
  "suspended": false,
  "state": "active",
  "first_seen_at": "2026-09-29T14:02:11.482Z",
  "last_seen_at": "2026-09-29T14:02:11.482Z",
  "created_at": "2026-09-29T14:02:11.482Z",
  "updated_at": "2026-09-29T14:02:11.482Z"
}

GET/organizations/{id}

Get an organizationPermission: read

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

idpath, requiredOrganizationId

Responses

Example response · 200

{
  "object": "organization",
  "id": "org_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "external_id": "acme",
  "name": "Acme",
  "metadata": {"tier": "enterprise"},
  "plan": "pro",
  "suspended": false,
  "state": "active",
  "first_seen_at": "2026-09-29T14:02:11.482Z",
  "last_seen_at": "2026-09-29T14:02:11.482Z",
  "created_at": "2026-09-29T14:02:11.482Z",
  "updated_at": "2026-09-29T14:02:11.482Z"
}

PATCH/organizations/{id}

Update an organizationPermission: manage

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

idpath, requiredOrganizationId

Body

OrganizationUpdate

Responses

Example request body

{"name": "Acme", "metadata": {"tier": "enterprise"}}

Example response · 200

{
  "object": "organization",
  "id": "org_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "external_id": "acme",
  "name": "Acme",
  "metadata": {"tier": "enterprise"},
  "plan": "pro",
  "suspended": false,
  "state": "active",
  "first_seen_at": "2026-09-29T14:02:11.482Z",
  "last_seen_at": "2026-09-29T14:02:11.482Z",
  "created_at": "2026-09-29T14:02:11.482Z",
  "updated_at": "2026-09-29T14:02:11.482Z"
}

DELETE/organizations/{id}

Delete an organizationPermission: manage

Destroys the organization's key at once, which makes its content, attachments and pseudonyms unreadable, then a job removes the rest. Its key leaves backups within 7 days. Records keep a keyed hash in place of its id.

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

idpath, requiredOrganizationId

Responses

202Organization

The organization, in the deleting state.

4XX

An error: see Errors

5XX

A service is unavailable: see Errors

Example response · 202

{
  "object": "organization",
  "id": "org_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "external_id": "acme",
  "name": "Acme",
  "metadata": {"tier": "enterprise"},
  "plan": "pro",
  "suspended": false,
  "state": "active",
  "first_seen_at": "2026-09-29T14:02:11.482Z",
  "last_seen_at": "2026-09-29T14:02:11.482Z",
  "created_at": "2026-09-29T14:02:11.482Z",
  "updated_at": "2026-09-29T14:02:11.482Z"
}

GET/organizations/external_id/{external_id}

Get an organization by the team's identifierPermission: read

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

external_idpath, requiredExternalId

Responses

Example response · 200

{
  "object": "organization",
  "id": "org_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "external_id": "acme",
  "name": "Acme",
  "metadata": {"tier": "enterprise"},
  "plan": "pro",
  "suspended": false,
  "state": "active",
  "first_seen_at": "2026-09-29T14:02:11.482Z",
  "last_seen_at": "2026-09-29T14:02:11.482Z",
  "created_at": "2026-09-29T14:02:11.482Z",
  "updated_at": "2026-09-29T14:02:11.482Z"
}

Users

The people or accounts in the team's product that requests are made for.

GET/users

List usersPermission: read

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

limitqueryinteger
beforequerystring

An object id. Returns the page before it.

afterquerystring

An object id. Returns the page after it.

orderquery"asc" | "desc"
organization_idqueryOrganizationId
suspendedqueryboolean

Responses

Example response · 200

{
  "object": "list",
  "data": [
    {
      "object": "user",
      "id": "user_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
      "external_id": "acme",
      "name": "Acme",
      "metadata": {"tier": "enterprise"},
      "suspended": false,
      "signals": [
        {
          "id": "signal_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
          "kind": "injection_attempts",
          "score": 0.5
        }
      ],
      "first_seen_at": "2026-09-29T14:02:11.482Z",
      "last_seen_at": "2026-09-29T14:02:11.482Z",
      "created_at": "2026-09-29T14:02:11.482Z",
      "updated_at": "2026-09-29T14:02:11.482Z"
    }
  ],
  "list_metadata": {"before": null, "after": null}
}

POST/users

Create a userPermission: manage

Users are also created by the first request that names them.

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

Idempotency-Keyheaderstring

Makes a retry return the first result for 24 hours. The same key with a different body is refused with 422 idempotency_key_reused.

Body

UserCreate

Responses

Example request body

{
  "external_id": "acme",
  "name": "Acme",
  "metadata": {"tier": "enterprise"}
}

Example response · 201

{
  "object": "user",
  "id": "user_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "external_id": "acme",
  "name": "Acme",
  "metadata": {"tier": "enterprise"},
  "suspended": false,
  "signals": [
    {
      "id": "signal_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
      "kind": "injection_attempts",
      "score": 0.5
    }
  ],
  "first_seen_at": "2026-09-29T14:02:11.482Z",
  "last_seen_at": "2026-09-29T14:02:11.482Z",
  "created_at": "2026-09-29T14:02:11.482Z",
  "updated_at": "2026-09-29T14:02:11.482Z"
}

GET/users/{id}

Get a userPermission: read

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

idpath, requiredUserId

Responses

Example response · 200

{
  "object": "user",
  "id": "user_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "external_id": "acme",
  "name": "Acme",
  "metadata": {"tier": "enterprise"},
  "suspended": false,
  "signals": [
    {
      "id": "signal_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
      "kind": "injection_attempts",
      "score": 0.5
    }
  ],
  "first_seen_at": "2026-09-29T14:02:11.482Z",
  "last_seen_at": "2026-09-29T14:02:11.482Z",
  "created_at": "2026-09-29T14:02:11.482Z",
  "updated_at": "2026-09-29T14:02:11.482Z"
}

PATCH/users/{id}

Update a userPermission: manage

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

idpath, requiredUserId

Body

UserUpdate

Responses

Example request body

{"name": "Acme", "metadata": {"tier": "enterprise"}}

Example response · 200

{
  "object": "user",
  "id": "user_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "external_id": "acme",
  "name": "Acme",
  "metadata": {"tier": "enterprise"},
  "suspended": false,
  "signals": [
    {
      "id": "signal_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
      "kind": "injection_attempts",
      "score": 0.5
    }
  ],
  "first_seen_at": "2026-09-29T14:02:11.482Z",
  "last_seen_at": "2026-09-29T14:02:11.482Z",
  "created_at": "2026-09-29T14:02:11.482Z",
  "updated_at": "2026-09-29T14:02:11.482Z"
}

GET/users/external_id/{external_id}

Get a user by the team's identifierPermission: read

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

external_idpath, requiredExternalId

Responses

Example response · 200

{
  "object": "user",
  "id": "user_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "external_id": "acme",
  "name": "Acme",
  "metadata": {"tier": "enterprise"},
  "suspended": false,
  "signals": [
    {
      "id": "signal_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
      "kind": "injection_attempts",
      "score": 0.5
    }
  ],
  "first_seen_at": "2026-09-29T14:02:11.482Z",
  "last_seen_at": "2026-09-29T14:02:11.482Z",
  "created_at": "2026-09-29T14:02:11.482Z",
  "updated_at": "2026-09-29T14:02:11.482Z"
}

GET/related_users

Users who share prompt templates with a userPermission: read

Users whose requests share template fingerprints with this user's, most shared first.

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

user_idquery, requiredUserId
limitqueryinteger

Responses

Example response · 200

{
  "object": "list",
  "data": [
    {
      "object": "related_user",
      "user": {
        "id": "org_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
        "external_id": "acme"
      },
      "shared_fingerprints": 1
    }
  ],
  "list_metadata": {"before": null, "after": null}
}

GET/organization_memberships

List which users have made requests for which organizationsPermission: read

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

limitqueryinteger
beforequerystring

An object id. Returns the page before it.

afterquerystring

An object id. Returns the page after it.

orderquery"asc" | "desc"
organization_idqueryOrganizationId
user_idqueryUserId

Responses

Example response · 200

{
  "object": "list",
  "data": [
    {
      "object": "organization_membership",
      "id": "om_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
      "organization": {
        "id": "org_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
        "external_id": "acme"
      },
      "user": {
        "id": "org_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
        "external_id": "acme"
      },
      "first_seen_at": "2026-09-29T14:02:11.482Z",
      "last_seen_at": "2026-09-29T14:02:11.482Z"
    }
  ],
  "list_metadata": {"before": null, "after": null}
}

Suspensions

Blocking a user's or an organization's requests.

GET/suspensions

List suspensionsPermission: read

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

limitqueryinteger
beforequerystring

An object id. Returns the page before it.

afterquerystring

An object id. Returns the page after it.

orderquery"asc" | "desc"
organization_idqueryOrganizationId
user_idqueryUserId
activequeryboolean

Only suspensions in force, or only lifted and expired ones.

Responses

Example response · 200

{
  "object": "list",
  "data": [
    {
      "object": "suspension",
      "id": "suspension_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
      "organization": {
        "id": "org_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
        "external_id": "acme"
      },
      "user": {
        "id": "org_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
        "external_id": "acme"
      },
      "reason": "Set by our scripts.",
      "note": "Set by our scripts.",
      "created_by": {
        "type": "member",
        "id": "member_01J9ZQ6V8D3K4M5N6P7Q8R9S0T"
      },
      "created_at": "2026-09-29T14:02:11.482Z",
      "expires_at": null,
      "lifted_at": null,
      "lifted_by": null
    }
  ],
  "list_metadata": {"before": null, "after": null}
}

POST/suspensions

Suspend a user or an organizationPermission: manage

Every gateway task refuses the suspended party's next request, within 10 seconds.

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

Idempotency-Keyheaderstring

Makes a retry return the first result for 24 hours. The same key with a different body is refused with 422 idempotency_key_reused.

Body

SuspensionCreate

Responses

Example request body

{
  "user_id": "user_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "reason": "abuse",
  "note": "Scraping answers at volume.",
  "expires_at": "2026-10-09T00:00:00.000Z"
}

Example response · 201

{
  "object": "suspension",
  "id": "suspension_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "organization": {
    "id": "org_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
    "external_id": "acme"
  },
  "user": {
    "id": "org_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
    "external_id": "acme"
  },
  "reason": "Set by our scripts.",
  "note": "Set by our scripts.",
  "created_by": {"type": "member", "id": "member_01J9ZQ6V8D3K4M5N6P7Q8R9S0T"},
  "created_at": "2026-09-29T14:02:11.482Z",
  "expires_at": null,
  "lifted_at": null,
  "lifted_by": null
}

GET/suspensions/{id}

Get a suspensionPermission: read

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

idpath, requiredSuspensionId

Responses

Example response · 200

{
  "object": "suspension",
  "id": "suspension_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "organization": {
    "id": "org_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
    "external_id": "acme"
  },
  "user": {
    "id": "org_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
    "external_id": "acme"
  },
  "reason": "Set by our scripts.",
  "note": "Set by our scripts.",
  "created_by": {"type": "member", "id": "member_01J9ZQ6V8D3K4M5N6P7Q8R9S0T"},
  "created_at": "2026-09-29T14:02:11.482Z",
  "expires_at": null,
  "lifted_at": null,
  "lifted_by": null
}

POST/suspensions/{id}/lift

Lift a suspensionPermission: manage

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

Idempotency-Keyheaderstring

Makes a retry return the first result for 24 hours. The same key with a different body is refused with 422 idempotency_key_reused.

idpath, requiredSuspensionId

Responses

Example response · 200

{
  "object": "suspension",
  "id": "suspension_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "organization": {
    "id": "org_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
    "external_id": "acme"
  },
  "user": {
    "id": "org_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
    "external_id": "acme"
  },
  "reason": "Set by our scripts.",
  "note": "Set by our scripts.",
  "created_by": {"type": "member", "id": "member_01J9ZQ6V8D3K4M5N6P7Q8R9S0T"},
  "created_at": "2026-09-29T14:02:11.482Z",
  "expires_at": null,
  "lifted_at": null,
  "lifted_by": null
}

Policies

Matches and settings, and how they combine.

GET/policies

List policiesPermission: read

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

limitqueryinteger
beforequerystring

An object id. Returns the page before it.

afterquerystring

An object id. Returns the page after it.

orderquery"asc" | "desc"

Responses

Example response · 200

{
  "object": "list",
  "data": [
    {
      "object": "policy",
      "id": "policy_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
      "name": "Free plan",
      "description": "Tighter limits and EU-only routing for the free plan.",
      "match": {"plan": "free"},
      "settings": {
        "routing": {"regions": ["eu"]},
        "limits": {
          "requests": [{"per": "user", "period": "minute", "amount": 20}],
          "spend": [{"per": "user", "period": "day", "amount": "0.50"}]
        },
        "guardrails": {
          "secrets": {"action": "redact", "mode": "enforce"},
          "personal_data": {"action": "pseudonymize", "mode": "enforce"}
        }
      },
      "version": 1,
      "created_at": "2026-09-29T14:02:11.482Z",
      "updated_at": "2026-09-29T14:02:11.482Z"
    }
  ],
  "list_metadata": {"before": null, "after": null}
}

POST/policies

Create a policyPermission: manage

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

Idempotency-Keyheaderstring

Makes a retry return the first result for 24 hours. The same key with a different body is refused with 422 idempotency_key_reused.

Body

PolicyCreate

Responses

Example request body

{
  "name": "Free plan",
  "description": "Tighter limits and EU-only routing for the free plan.",
  "match": {"plan": "free"},
  "settings": {
    "routing": {"regions": ["eu"]},
    "limits": {
      "requests": [{"per": "user", "period": "minute", "amount": 20}],
      "spend": [{"per": "user", "period": "day", "amount": "0.50"}]
    },
    "guardrails": {
      "secrets": {"action": "redact", "mode": "enforce"},
      "personal_data": {"action": "pseudonymize", "mode": "enforce"}
    }
  }
}

Example response · 201

{
  "object": "policy",
  "id": "policy_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "name": "Free plan",
  "description": "Tighter limits and EU-only routing for the free plan.",
  "match": {"plan": "free"},
  "settings": {
    "routing": {"regions": ["eu"]},
    "limits": {
      "requests": [{"per": "user", "period": "minute", "amount": 20}],
      "spend": [{"per": "user", "period": "day", "amount": "0.50"}]
    },
    "guardrails": {
      "secrets": {"action": "redact", "mode": "enforce"},
      "personal_data": {"action": "pseudonymize", "mode": "enforce"}
    }
  },
  "version": 1,
  "created_at": "2026-09-29T14:02:11.482Z",
  "updated_at": "2026-09-29T14:02:11.482Z"
}

GET/policies/{id}

Get a policyPermission: read

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

idpath, requiredPolicyId

Responses

200Policy

The policy, at its current version.

4XX

An error: see Errors

5XX

A service is unavailable: see Errors

Example response · 200

{
  "object": "policy",
  "id": "policy_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "name": "Free plan",
  "description": "Tighter limits and EU-only routing for the free plan.",
  "match": {"plan": "free"},
  "settings": {
    "routing": {"regions": ["eu"]},
    "limits": {
      "requests": [{"per": "user", "period": "minute", "amount": 20}],
      "spend": [{"per": "user", "period": "day", "amount": "0.50"}]
    },
    "guardrails": {
      "secrets": {"action": "redact", "mode": "enforce"},
      "personal_data": {"action": "pseudonymize", "mode": "enforce"}
    }
  },
  "version": 1,
  "created_at": "2026-09-29T14:02:11.482Z",
  "updated_at": "2026-09-29T14:02:11.482Z"
}

PATCH/policies/{id}

Update a policyPermission: manage

Each change makes a new version. The body merges like every PATCH, settings included, except match: when given, it replaces the whole match, so send every field the policy should still match on. A merge would read a null in it as "clear this field" and widen the policy to requests it never matched.

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

idpath, requiredPolicyId

Body

PolicyUpdate

Responses

Example request body

{
  "settings": {
    "limits": {
      "spend": [{"per": "user", "period": "day", "amount": "1.00"}]
    }
  }
}

Example response · 200

{
  "object": "policy",
  "id": "policy_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "name": "Free plan",
  "description": "Tighter limits and EU-only routing for the free plan.",
  "match": {"plan": "free"},
  "settings": {
    "routing": {"regions": ["eu"]},
    "limits": {
      "requests": [{"per": "user", "period": "minute", "amount": 20}],
      "spend": [{"per": "user", "period": "day", "amount": "0.50"}]
    },
    "guardrails": {
      "secrets": {"action": "redact", "mode": "enforce"},
      "personal_data": {"action": "pseudonymize", "mode": "enforce"}
    }
  },
  "version": 1,
  "created_at": "2026-09-29T14:02:11.482Z",
  "updated_at": "2026-09-29T14:02:11.482Z"
}

DELETE/policies/{id}

Delete a policyPermission: manage

Its versions are kept, so requests that matched it still explain themselves.

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

idpath, requiredPolicyId

Responses

Example response · 200

{
  "object": "policy",
  "id": "policy_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "name": "Free plan",
  "description": "Tighter limits and EU-only routing for the free plan.",
  "match": {"plan": "free"},
  "settings": {
    "routing": {"regions": ["eu"]},
    "limits": {
      "requests": [{"per": "user", "period": "minute", "amount": 20}],
      "spend": [{"per": "user", "period": "day", "amount": "0.50"}]
    },
    "guardrails": {
      "secrets": {"action": "redact", "mode": "enforce"},
      "personal_data": {"action": "pseudonymize", "mode": "enforce"}
    }
  },
  "version": 1,
  "created_at": "2026-09-29T14:02:11.482Z",
  "updated_at": "2026-09-29T14:02:11.482Z"
}

GET/policies/{id}/versions

List a policy's versionsPermission: read

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

idpath, requiredPolicyId
limitqueryinteger
orderquery"asc" | "desc"
beforequeryinteger

A version number.

afterqueryinteger

A version number.

Responses

200PolicyVersionList

A page of versions, newest first by default.

4XX

An error: see Errors

5XX

A service is unavailable: see Errors

Example response · 200

{
  "object": "list",
  "data": [
    {
      "object": "policy_version",
      "policy_id": "policy_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
      "version": 1,
      "name": "Acme",
      "match": {"organization": "globex"},
      "settings": {
        "routing": {
          "connections": ["own", "environment"],
          "regions": ["eu", "global"],
          "models": ["claude-sonnet-5-5", "claude-haiku-4-5"],
          "data_terms": {"retention": "zero", "training": "no"}
        },
        "retention": {"content": "none"},
        "limits": {
          "requests": [{"per": "user", "period": "minute", "amount": 60}],
          "spend": [
            {"per": "user", "period": "day", "amount": "2.00"},
            {
              "per": "organization",
              "period": "month",
              "amount": "500.00"
            }
          ]
        },
        "guardrails": {
          "secrets": {"action": "redact", "mode": "enforce"},
          "personal_data": {
            "action": "pseudonymize",
            "mode": "enforce",
            "parts": ["user", "tool_result"],
            "kinds": ["email", "phone"],
            "exclusions": ["support@acme.example"]
          },
          "prompt_injection": {
            "action": "cut",
            "mode": "enforce",
            "parts": ["tool_result"]
          },
          "illegal_content": {"action": "block", "mode": "monitor"}
        },
        "uninspected": "allow",
        "abuse": {"suspend_at": 0.9}
      },
      "deleted": false,
      "created_by": {
        "type": "member",
        "id": "member_01J9ZQ6V8D3K4M5N6P7Q8R9S0T"
      },
      "created_at": "2026-09-29T14:02:11.482Z"
    }
  ],
  "list_metadata": {"before": null, "after": null}
}

GET/effective_policy

The effective policy for an identityPermission: read

Combines every policy that matches the identity, as the gateway would for a request carrying these values in its Alectura-* headers. An omitted parameter means the header is absent.

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

organizationqueryExternalId
userqueryExternalId
planqueryExternalId

Responses

200EffectivePolicy

The combined settings, with the policy behind each.

4XX

An error: see Errors

5XX

A service is unavailable: see Errors

Example response · 200

{
  "object": "effective_policy",
  "identity": {"organization": "acme", "user": "user_42", "plan": "pro"},
  "policies": [{"id": "policy_01J9ZQ6V8D3K4M5N6P7Q8R9S0T", "version": 1}],
  "settings": {
    "routing": {
      "connections": ["own", "environment"],
      "regions": ["eu", "global"],
      "models": ["claude-sonnet-5-5", "claude-haiku-4-5"],
      "data_terms": {"retention": "zero", "training": "no"}
    },
    "retention": {"content": "none"},
    "limits": {
      "requests": [{"per": "user", "period": "minute", "amount": 60}],
      "spend": [
        {"per": "user", "period": "day", "amount": "2.00"},
        {
          "per": "organization",
          "period": "month",
          "amount": "500.00"
        }
      ]
    },
    "guardrails": {
      "secrets": {"action": "redact", "mode": "enforce"},
      "personal_data": {
        "action": "pseudonymize",
        "mode": "enforce",
        "parts": ["user", "tool_result"],
        "kinds": ["email", "phone"],
        "exclusions": ["support@acme.example"]
      },
      "prompt_injection": {
        "action": "cut",
        "mode": "enforce",
        "parts": ["tool_result"]
      },
      "illegal_content": {"action": "block", "mode": "monitor"}
    },
    "uninspected": "allow",
    "abuse": {"suspend_at": 0.9}
  },
  "sources": {"routing.regions": ["policy_01M3PQG7FEV8Q4X0M5R7T9W2YA"]}
}

Connections

Ways to reach a model provider.

GET/connections

List connectionsPermission: read

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

limitqueryinteger
beforequerystring

An object id. Returns the page before it.

afterquerystring

An object id. Returns the page after it.

orderquery"asc" | "desc"
organization_idqueryOrganizationId

Only the connections this organization owns.

providerqueryProvider
statequeryConnectionState

Responses

Example response · 200

{
  "object": "list",
  "data": [
    {
      "object": "connection",
      "id": "conn_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
      "name": "OpenAI EU",
      "provider": "openai",
      "owner": {"type": "environment"},
      "base_url": "https://eu.api.openai.com/v1",
      "aws_region": null,
      "inference_profile": null,
      "region": "eu",
      "models": ["gpt-5", "gpt-5-mini"],
      "data_terms": {"retention": "zero", "training": "no"},
      "credential": {"type": "api_key", "hint": "Qk3x"},
      "aws_external_id": null,
      "state": "draft",
      "cooling_down_until": null,
      "created_at": "2026-09-29T14:02:11.482Z",
      "updated_at": "2026-09-29T14:02:11.482Z"
    }
  ],
  "list_metadata": {"before": null, "after": null}
}

POST/connections

Create a connectionPermission: manage

A new connection is a draft, and routes nothing until it is activated.

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

Idempotency-Keyheaderstring

Makes a retry return the first result for 24 hours. The same key with a different body is refused with 422 idempotency_key_reused.

Body

ConnectionCreate

Responses

Example request body

{
  "name": "OpenAI EU",
  "provider": "openai",
  "base_url": "https://eu.api.openai.com/v1",
  "models": ["gpt-5", "gpt-5-mini"],
  "data_terms": {"retention": "zero", "training": "no"},
  "credential": {"type": "api_key", "api_key": "sk-proj-…"}
}

Example response · 201

{
  "object": "connection",
  "id": "conn_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "name": "OpenAI EU",
  "provider": "openai",
  "owner": {"type": "environment"},
  "base_url": "https://eu.api.openai.com/v1",
  "aws_region": null,
  "inference_profile": null,
  "region": "eu",
  "models": ["gpt-5", "gpt-5-mini"],
  "data_terms": {"retention": "zero", "training": "no"},
  "credential": {"type": "api_key", "hint": "Qk3x"},
  "aws_external_id": null,
  "state": "draft",
  "cooling_down_until": null,
  "created_at": "2026-09-29T14:02:11.482Z",
  "updated_at": "2026-09-29T14:02:11.482Z"
}

GET/connections/{id}

Get a connectionPermission: read

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

idpath, requiredConnectionId

Responses

200Connection

The connection. Its credential is never returned.

4XX

An error: see Errors

5XX

A service is unavailable: see Errors

Example response · 200

{
  "object": "connection",
  "id": "conn_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "name": "OpenAI EU",
  "provider": "openai",
  "owner": {"type": "environment"},
  "base_url": "https://eu.api.openai.com/v1",
  "aws_region": null,
  "inference_profile": null,
  "region": "eu",
  "models": ["gpt-5", "gpt-5-mini"],
  "data_terms": {"retention": "zero", "training": "no"},
  "credential": {"type": "api_key", "hint": "Qk3x"},
  "aws_external_id": null,
  "state": "draft",
  "cooling_down_until": null,
  "created_at": "2026-09-29T14:02:11.482Z",
  "updated_at": "2026-09-29T14:02:11.482Z"
}

PATCH/connections/{id}

Update, activate or disable a connectionPermission: manage

Setting state to active runs the connection's test first, and fails with 422 connection_test_failed, listing the failed checks, unless every check passes. Replacing the credential of an active connection tests the new one the same way before it is used.

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

idpath, requiredConnectionId

Body

ConnectionUpdate

Responses

Example request body

{
  "name": "Acme",
  "models": ["models"],
  "data_terms": {"retention": "undeclared", "training": "undeclared"},
  "credential": {"type": "api_key", "api_key": "sk-proj-…"},
  "state": "draft"
}

Example response · 200

{
  "object": "connection",
  "id": "conn_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "name": "OpenAI EU",
  "provider": "openai",
  "owner": {"type": "environment"},
  "base_url": "https://eu.api.openai.com/v1",
  "aws_region": null,
  "inference_profile": null,
  "region": "eu",
  "models": ["gpt-5", "gpt-5-mini"],
  "data_terms": {"retention": "zero", "training": "no"},
  "credential": {"type": "api_key", "hint": "Qk3x"},
  "aws_external_id": null,
  "state": "draft",
  "cooling_down_until": null,
  "created_at": "2026-09-29T14:02:11.482Z",
  "updated_at": "2026-09-29T14:02:11.482Z"
}

DELETE/connections/{id}

Delete a connectionPermission: manage

Its credential is destroyed. Requests that used it keep its id.

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

idpath, requiredConnectionId

Responses

Example response · 200

{
  "object": "connection",
  "id": "conn_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "name": "OpenAI EU",
  "provider": "openai",
  "owner": {"type": "environment"},
  "base_url": "https://eu.api.openai.com/v1",
  "aws_region": null,
  "inference_profile": null,
  "region": "eu",
  "models": ["gpt-5", "gpt-5-mini"],
  "data_terms": {"retention": "zero", "training": "no"},
  "credential": {"type": "api_key", "hint": "Qk3x"},
  "aws_external_id": null,
  "state": "draft",
  "cooling_down_until": null,
  "created_at": "2026-09-29T14:02:11.482Z",
  "updated_at": "2026-09-29T14:02:11.482Z"
}

POST/connections/{id}/test

Test a connectionPermission: manage

Sends a small request for each of the connection's models and checks the answers, without changing the connection's state.

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

idpath, requiredConnectionId
Idempotency-Keyheaderstring

Makes a retry return the first result for 24 hours. The same key with a different body is refused with 422 idempotency_key_reused.

Responses

Example response · 200

{
  "object": "connection_test",
  "connection_id": "conn_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "passed": false,
  "checks": [
    {
      "name": "Acme",
      "passed": false,
      "reason": "Set by our scripts.",
      "message": "The provider answered 401.",
      "upstream_status": 1
    }
  ],
  "created_at": "2026-09-29T14:02:11.482Z"
}

Content store

Where content kept under team retention goes, in the team's own AWS account.

GET/content_store

Get the content storePermission: read

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

Responses

Example response · 200

{
  "object": "content_store",
  "bucket": "acme-alectura-content",
  "region": "eu-west-1",
  "prefix": "alectura/",
  "role_arn": "arn:aws:iam::123456789012:role/alectura-content",
  "external_id": "acme",
  "state": "draft",
  "created_at": "2026-09-29T14:02:11.482Z",
  "updated_at": "2026-09-29T14:02:11.482Z"
}

POST/content_store

Set the content storePermission: manage

Sets where the environment's team-held content goes, replacing the store it had. A new store, or one whose bucket, region, prefix or role changed, is a draft, and takes no content until its test passes. The environment's external id stays the same across changes. The bucket's region must be in the environment's own region (R20), such as eu-central-1 for an eu environment; any other is refused with 422 validation_failed, code outside_region.

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

Idempotency-Keyheaderstring

Makes a retry return the first result for 24 hours. The same key with a different body is refused with 422 idempotency_key_reused.

Body

ContentStoreSet

Responses

Example request body

{
  "bucket": "acme-alectura-content",
  "region": "eu-west-1",
  "prefix": "alectura/",
  "role_arn": "arn:aws:iam::123456789012:role/alectura-content"
}

Example response · 200

{
  "object": "content_store",
  "bucket": "acme-alectura-content",
  "region": "eu-west-1",
  "prefix": "alectura/",
  "role_arn": "arn:aws:iam::123456789012:role/alectura-content",
  "external_id": "acme",
  "state": "draft",
  "created_at": "2026-09-29T14:02:11.482Z",
  "updated_at": "2026-09-29T14:02:11.482Z"
}

DELETE/content_store

Remove the content storePermission: manage

From now on, content kept under team retention is kept nowhere. What the store holds stays there, the team's to keep or delete; Alectura reads none of it any more.

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

Idempotency-Keyheaderstring

Makes a retry return the first result for 24 hours. The same key with a different body is refused with 422 idempotency_key_reused.

Responses

Example response · 200

{
  "object": "content_store",
  "bucket": "acme-alectura-content",
  "region": "eu-west-1",
  "prefix": "alectura/",
  "role_arn": "arn:aws:iam::123456789012:role/alectura-content",
  "external_id": "acme",
  "state": "draft",
  "created_at": "2026-09-29T14:02:11.482Z",
  "updated_at": "2026-09-29T14:02:11.482Z"
}

POST/content_store/test

Test the content storePermission: manage

Assumes the store's role with the environment's external id, then writes, reads and deletes {prefix}{environment}/alectura-test in its bucket. When that works, the store becomes active.

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

Idempotency-Keyheaderstring

Makes a retry return the first result for 24 hours. The same key with a different body is refused with 422 idempotency_key_reused.

Responses

200ContentStoreTest

The test's result, and the store after it.

4XX

An error: see Errors

5XX

A service is unavailable: see Errors

Example response · 200

{
  "object": "content_store_test",
  "passed": false,
  "message": "The provider answered 401.",
  "content_store": {
    "object": "content_store",
    "bucket": "acme-alectura-content",
    "region": "eu-west-1",
    "prefix": "alectura/",
    "role_arn": "arn:aws:iam::123456789012:role/alectura-content",
    "external_id": "acme",
    "state": "draft",
    "created_at": "2026-09-29T14:02:11.482Z",
    "updated_at": "2026-09-29T14:02:11.482Z"
  }
}

API keys

Sending keys for the gateway, and management keys for this API.

GET/api_keys

List API keysPermission: read

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

limitqueryinteger
beforequerystring

An object id. Returns the page before it.

afterquerystring

An object id. Returns the page after it.

orderquery"asc" | "desc"
typequeryApiKeyType
statequeryApiKeyState

Responses

200ApiKeyList

A page of keys, without their secrets.

4XX

An error: see Errors

5XX

A service is unavailable: see Errors

Example response · 200

{
  "object": "list",
  "data": [
    {
      "object": "api_key",
      "id": "key_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
      "name": "Acme",
      "type": "sending",
      "permissions": ["send"],
      "label": "sk-alectura-eu-live-…2Yl4IC",
      "state": "active",
      "expires_at": null,
      "previous_secret_expires_at": "2026-09-29T14:02:11.482Z",
      "created_by": {
        "type": "member",
        "id": "member_01J9ZQ6V8D3K4M5N6P7Q8R9S0T"
      },
      "created_at": "2026-09-29T14:02:11.482Z",
      "updated_at": "2026-09-29T14:02:11.482Z"
    }
  ],
  "list_metadata": {"before": null, "after": null}
}

POST/api_keys

Create an API keyPermission: manage

The response is the only time the secret is shown. A retry with the same Idempotency-Key returns the key without its secret; rotate it to get a new one.

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

Idempotency-Keyheaderstring

Makes a retry return the first result for 24 hours. The same key with a different body is refused with 422 idempotency_key_reused.

Body

ApiKeyCreate

Responses

Example request body

{
  "name": "Acme",
  "type": "sending",
  "permissions": ["read"],
  "expires_at": "2026-09-29T14:02:11.482Z"
}

Example response · 201

{
  "object": "api_key",
  "id": "key_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "name": "Acme",
  "type": "sending",
  "permissions": ["send"],
  "label": "sk-alectura-eu-live-…2Yl4IC",
  "state": "active",
  "expires_at": null,
  "previous_secret_expires_at": "2026-09-29T14:02:11.482Z",
  "created_by": {"type": "member", "id": "member_01J9ZQ6V8D3K4M5N6P7Q8R9S0T"},
  "created_at": "2026-09-29T14:02:11.482Z",
  "updated_at": "2026-09-29T14:02:11.482Z",
  "secret": "sk-alectura-eu-live-0123456789abcdefghijABCDEFGHIJ01234567892Yl4IC"
}

GET/api_keys/{id}

Get an API keyPermission: read

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

idpath, requiredApiKeyId

Responses

Example response · 200

{
  "object": "api_key",
  "id": "key_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "name": "Acme",
  "type": "sending",
  "permissions": ["send"],
  "label": "sk-alectura-eu-live-…2Yl4IC",
  "state": "active",
  "expires_at": null,
  "previous_secret_expires_at": "2026-09-29T14:02:11.482Z",
  "created_by": {"type": "member", "id": "member_01J9ZQ6V8D3K4M5N6P7Q8R9S0T"},
  "created_at": "2026-09-29T14:02:11.482Z",
  "updated_at": "2026-09-29T14:02:11.482Z"
}

PATCH/api_keys/{id}

Rename, disable, enable or set the expiry of an API keyPermission: manage

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

idpath, requiredApiKeyId

Body

ApiKeyUpdate

Responses

Example request body

{"name": "Acme", "state": "active", "expires_at": null}

Example response · 200

{
  "object": "api_key",
  "id": "key_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "name": "Acme",
  "type": "sending",
  "permissions": ["send"],
  "label": "sk-alectura-eu-live-…2Yl4IC",
  "state": "active",
  "expires_at": null,
  "previous_secret_expires_at": "2026-09-29T14:02:11.482Z",
  "created_by": {"type": "member", "id": "member_01J9ZQ6V8D3K4M5N6P7Q8R9S0T"},
  "created_at": "2026-09-29T14:02:11.482Z",
  "updated_at": "2026-09-29T14:02:11.482Z"
}

DELETE/api_keys/{id}

Revoke an API keyPermission: manage

Every gateway task refuses the key within 10 seconds. A revoked key can't be restored.

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

idpath, requiredApiKeyId

Responses

Example response · 200

{
  "object": "api_key",
  "id": "key_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "name": "Acme",
  "type": "sending",
  "permissions": ["send"],
  "label": "sk-alectura-eu-live-…2Yl4IC",
  "state": "active",
  "expires_at": null,
  "previous_secret_expires_at": "2026-09-29T14:02:11.482Z",
  "created_by": {"type": "member", "id": "member_01J9ZQ6V8D3K4M5N6P7Q8R9S0T"},
  "created_at": "2026-09-29T14:02:11.482Z",
  "updated_at": "2026-09-29T14:02:11.482Z"
}

POST/api_keys/{id}/rotate

Rotate an API key's secretPermission: manage

Gives the key a new secret. The old secret keeps working for the grace period, so servers can move over without downtime.

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

Idempotency-Keyheaderstring

Makes a retry return the first result for 24 hours. The same key with a different body is refused with 422 idempotency_key_reused.

idpath, requiredApiKeyId

Body

grace_period_secondsinteger

Responses

Example request body

{"grace_period_seconds": 86400}

Example response · 200

{
  "object": "api_key",
  "id": "key_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "name": "Acme",
  "type": "sending",
  "permissions": ["send"],
  "label": "sk-alectura-eu-live-…2Yl4IC",
  "state": "active",
  "expires_at": null,
  "previous_secret_expires_at": "2026-09-29T14:02:11.482Z",
  "created_by": {"type": "member", "id": "member_01J9ZQ6V8D3K4M5N6P7Q8R9S0T"},
  "created_at": "2026-09-29T14:02:11.482Z",
  "updated_at": "2026-09-29T14:02:11.482Z",
  "secret": "sk-alectura-eu-live-0123456789abcdefghijABCDEFGHIJ01234567892Yl4IC"
}

Requests

What each request did, and its content.

GET/requests

List requestsPermission: read

About 2 seconds behind the gateway. Poll with after and order=asc for a live tail.

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

limitqueryinteger
beforequerystring

An object id. Returns the page before it.

afterquerystring

An object id. Returns the page after it.

orderquery"asc" | "desc"
organization_idqueryOrganizationId
user_idqueryUserId
conversation_idqueryConversationId
verdictqueryVerdict
modelquerystring
connection_idqueryConnectionId
policy_idqueryPolicyId
guardrailqueryGuardrail

Only requests with a finding from this guardrail.

created_afterquerystring (date-time)
created_beforequerystring (date-time)

Responses

Example response · 200

{
  "object": "list",
  "data": [
    {
      "object": "request",
      "id": "req_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
      "state": "pending",
      "created_at": "2026-09-29T14:02:11.482Z",
      "completed_at": null,
      "organization": {
        "id": "org_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
        "external_id": "acme"
      },
      "user": {
        "id": "org_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
        "external_id": "acme"
      },
      "plan": "pro",
      "conversation_id": "conv_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
      "api_key_id": "key_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
      "endpoint": "openai.chat_completions",
      "model": "claude-sonnet-5-5",
      "stream": false,
      "status": 1,
      "verdict": "passed",
      "refusal": {"code": "user_suspended"},
      "connection": {
        "id": "conn_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
        "provider": "openai",
        "region": "us"
      },
      "attempts": [
        {
          "connection": {
            "id": "conn_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
            "provider": "openai",
            "region": "us"
          },
          "started_at": "2026-09-29T14:02:11.482Z",
          "status": 1,
          "error": null,
          "duration_ms": 0.5
        }
      ],
      "policies": [
        {
          "id": "policy_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
          "version": 1
        }
      ],
      "findings": [
        {
          "object": "finding",
          "id": "finding_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
          "guardrail": "secrets",
          "kind": "injection_attempts",
          "action": "record",
          "mode": "monitor",
          "applied": false,
          "block": 1,
          "part": "system"
        }
      ],
      "coverage": [
        {
          "block": 1,
          "part": "system",
          "modality": "text",
          "inspected_by": ["secrets"],
          "reason": "images_uninspected"
        }
      ],
      "usage": {
        "input_tokens": 1,
        "output_tokens": 1,
        "cache_read_input_tokens": 1,
        "cache_creation_input_tokens": 1,
        "reasoning_tokens": 1,
        "estimated": false,
        "raw": {}
      },
      "cost": {"amount": "2.00", "currency": "USD", "estimated": false},
      "timings": {
        "overhead_ms": 0.5,
        "first_byte_ms": 0.5,
        "duration_ms": 0.5
      },
      "content": {
        "retained": false,
        "retention": "none",
        "expires_at": null,
        "reason": "Set by our scripts."
      }
    }
  ],
  "list_metadata": {"before": null, "after": null}
}

GET/requests/{id}

Get a requestPermission: read

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

idpath, requiredRequestId

Responses

200Request

The request's record. Its content is fetched separately.

4XX

An error: see Errors

5XX

A service is unavailable: see Errors

Example response · 200

{
  "object": "request",
  "id": "req_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "state": "pending",
  "created_at": "2026-09-29T14:02:11.482Z",
  "completed_at": null,
  "organization": {
    "id": "org_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
    "external_id": "acme"
  },
  "user": {
    "id": "org_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
    "external_id": "acme"
  },
  "plan": "pro",
  "conversation_id": "conv_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "api_key_id": "key_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "endpoint": "openai.chat_completions",
  "model": "claude-sonnet-5-5",
  "stream": false,
  "status": 1,
  "verdict": "passed",
  "refusal": {"code": "user_suspended"},
  "connection": {
    "id": "conn_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
    "provider": "openai",
    "region": "us"
  },
  "attempts": [
    {
      "connection": {
        "id": "conn_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
        "provider": "openai",
        "region": "us"
      },
      "started_at": "2026-09-29T14:02:11.482Z",
      "status": 1,
      "error": null,
      "duration_ms": 0.5
    }
  ],
  "policies": [{"id": "policy_01J9ZQ6V8D3K4M5N6P7Q8R9S0T", "version": 1}],
  "findings": [
    {
      "object": "finding",
      "id": "finding_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
      "guardrail": "secrets",
      "kind": "injection_attempts",
      "action": "record",
      "mode": "monitor",
      "applied": false,
      "block": 1,
      "part": "system"
    }
  ],
  "coverage": [
    {
      "block": 1,
      "part": "system",
      "modality": "text",
      "inspected_by": ["secrets"],
      "reason": "images_uninspected"
    }
  ],
  "usage": {
    "input_tokens": 1,
    "output_tokens": 1,
    "cache_read_input_tokens": 1,
    "cache_creation_input_tokens": 1,
    "reasoning_tokens": 1,
    "estimated": false,
    "raw": {}
  },
  "cost": {"amount": "2.00", "currency": "USD", "estimated": false},
  "timings": {"overhead_ms": 0.5, "first_byte_ms": 0.5, "duration_ms": 0.5},
  "content": {
    "retained": false,
    "retention": "none",
    "expires_at": null,
    "reason": "Set by our scripts."
  }
}

GET/requests/{id}/content

Get one version of a request's contentPermission: read_content

Rebuilds the version byte for byte, except that each detected secret is replaced by its keyed hash. An attachment is referenced by its hash, and fetched with the attachments endpoint. Every read is recorded as a request.content_read event.

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

idpath, requiredRequestId
versionquery, requiredContentVersion
viewquery"raw" | "events" | "assembled"

For a streamed response: raw is the stream as it arrived; events is newline-delimited JSON, one event per line with the milliseconds since the request began; assembled is the response as one JSON object, as if it hadn't been streamed.

Responses

200object

The content.

410Error

The content has passed its retention, or was never kept.

4XX

An error: see Errors

5XX

A service is unavailable: see Errors

GET/requests/{id}/attachments/{hash}

Get an attachmentPermission: read_content

Recorded as a request.content_read event.

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

idpath, requiredRequestId
hashpath, requiredstring

Responses

200string

The attachment's bytes, with its media type.

410Error

The attachment has passed its retention, or was never kept.

4XX

An error: see Errors

5XX

A service is unavailable: see Errors

GET/requests/{id}/conversation

The requests in this request's conversationPermission: read

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

idpath, requiredRequestId
limitqueryinteger
beforequerystring

An object id. Returns the page before it.

afterquerystring

An object id. Returns the page after it.

Responses

200RequestList

The conversation's requests, oldest first.

4XX

An error: see Errors

5XX

A service is unavailable: see Errors

Example response · 200

{
  "object": "list",
  "data": [
    {
      "object": "request",
      "id": "req_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
      "state": "pending",
      "created_at": "2026-09-29T14:02:11.482Z",
      "completed_at": null,
      "organization": {
        "id": "org_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
        "external_id": "acme"
      },
      "user": {
        "id": "org_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
        "external_id": "acme"
      },
      "plan": "pro",
      "conversation_id": "conv_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
      "api_key_id": "key_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
      "endpoint": "openai.chat_completions",
      "model": "claude-sonnet-5-5",
      "stream": false,
      "status": 1,
      "verdict": "passed",
      "refusal": {"code": "user_suspended"},
      "connection": {
        "id": "conn_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
        "provider": "openai",
        "region": "us"
      },
      "attempts": [
        {
          "connection": {
            "id": "conn_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
            "provider": "openai",
            "region": "us"
          },
          "started_at": "2026-09-29T14:02:11.482Z",
          "status": 1,
          "error": null,
          "duration_ms": 0.5
        }
      ],
      "policies": [
        {
          "id": "policy_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
          "version": 1
        }
      ],
      "findings": [
        {
          "object": "finding",
          "id": "finding_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
          "guardrail": "secrets",
          "kind": "injection_attempts",
          "action": "record",
          "mode": "monitor",
          "applied": false,
          "block": 1,
          "part": "system"
        }
      ],
      "coverage": [
        {
          "block": 1,
          "part": "system",
          "modality": "text",
          "inspected_by": ["secrets"],
          "reason": "images_uninspected"
        }
      ],
      "usage": {
        "input_tokens": 1,
        "output_tokens": 1,
        "cache_read_input_tokens": 1,
        "cache_creation_input_tokens": 1,
        "reasoning_tokens": 1,
        "estimated": false,
        "raw": {}
      },
      "cost": {"amount": "2.00", "currency": "USD", "estimated": false},
      "timings": {
        "overhead_ms": 0.5,
        "first_byte_ms": 0.5,
        "duration_ms": 0.5
      },
      "content": {
        "retained": false,
        "retention": "none",
        "expires_at": null,
        "reason": "Set by our scripts."
      }
    }
  ],
  "list_metadata": {"before": null, "after": null}
}

Findings

Detector matches, and the team's labels on them.

GET/findings/summary

Findings by guardrail and kind, with samplesPermission: read

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

fromquery, requiredstring (date-time)
toquery, requiredstring (date-time)
guardrailqueryGuardrail
organization_idqueryOrganizationId

Responses

Example response · 200

{
  "object": "findings_summary",
  "from": "2026-09-29T14:02:11.482Z",
  "to": "2026-09-29T14:02:11.482Z",
  "groups": [
    {
      "guardrail": "secrets",
      "kind": "injection_attempts",
      "action": "action",
      "mode": "monitor",
      "count": 1,
      "requests": 1,
      "samples": ["req_01J9ZQ6V8D3K4M5N6P7Q8R9S0T"]
    }
  ]
}

GET/findings/{id}/dispositions

List a finding's dispositionsPermission: read

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

idpath, requiredFindingId

Responses

200DispositionList

The finding's dispositions, newest first.

4XX

An error: see Errors

5XX

A service is unavailable: see Errors

Example response · 200

{
  "object": "list",
  "data": [
    {
      "object": "disposition",
      "id": "disposition_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
      "finding_id": "finding_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
      "label": "false_positive",
      "note": "Set by our scripts.",
      "created_by": {
        "type": "member",
        "id": "member_01J9ZQ6V8D3K4M5N6P7Q8R9S0T"
      },
      "created_at": "2026-09-29T14:02:11.482Z"
    }
  ],
  "list_metadata": {"before": null, "after": null}
}

POST/findings/{id}/dispositions

Label a findingPermission: manage

Appends a label. The finding itself never changes, and no policy does either.

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

idpath, requiredFindingId
Idempotency-Keyheaderstring

Makes a retry return the first result for 24 hours. The same key with a different body is refused with 422 idempotency_key_reused.

Body

DispositionCreate

Responses

Example request body

{"label": "false_positive", "note": "Set by our scripts."}

Example response · 201

{
  "object": "disposition",
  "id": "disposition_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "finding_id": "finding_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "label": "false_positive",
  "note": "Set by our scripts.",
  "created_by": {"type": "member", "id": "member_01J9ZQ6V8D3K4M5N6P7Q8R9S0T"},
  "created_at": "2026-09-29T14:02:11.482Z"
}

Summaries

Totals from rollups, minutes behind.

GET/summary

Totals for the environment, for one organization, or for one userPermission: read

A user's totals are kept by the day, so user_id takes interval=day only, and can't be given with organization_id.

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

fromquery, requiredstring (date-time)
toquery, requiredstring (date-time)
intervalquery"hour" | "day"

The width of each point in the series.

organization_idqueryOrganizationId
user_idqueryUserId

Responses

Example response · 200

{
  "object": "summary",
  "from": "2026-09-29T14:02:11.482Z",
  "to": "2026-09-29T14:02:11.482Z",
  "interval": "hour",
  "organization_id": "org_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "user_id": "user_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "totals": {
    "requests": 1,
    "verdicts": {"passed": 1, "modified": 1, "blocked": 1, "cut": 1},
    "errors": 1,
    "input_tokens": 1,
    "output_tokens": 1,
    "cost": {"amount": "2.00", "currency": "USD", "estimated": false},
    "findings": {
      "secrets": 1,
      "personal_data": 1,
      "prompt_injection": 1,
      "illegal_content": 1
    },
    "organizations": 1,
    "users": 1,
    "models": {"key": 1},
    "providers": {"key": 1}
  },
  "series": [
    {
      "start": "2026-09-29T14:02:11.482Z",
      "totals": {
        "requests": 1,
        "verdicts": {"passed": 1, "modified": 1, "blocked": 1, "cut": 1},
        "errors": 1,
        "input_tokens": 1,
        "output_tokens": 1,
        "cost": {
          "amount": "2.00",
          "currency": "USD",
          "estimated": false
        },
        "findings": {
          "secrets": 1,
          "personal_data": 1,
          "prompt_injection": 1,
          "illegal_content": 1
        },
        "organizations": 1,
        "users": 1,
        "models": {"key": 1},
        "providers": {"key": 1}
      }
    }
  ]
}

GET/summary/users

Totals for several users at oncePermission: read

Each user's summary by the day, as getSummary gives it for user_id, in the order of user_ids: a page of users' weeks in one call.

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

fromquery, requiredstring (date-time)
toquery, requiredstring (date-time)
user_idsquery, requiredUserId[]

Up to 100 users.

Responses

200SummaryList

A summary for each user, minutes behind.

4XX

An error: see Errors

5XX

A service is unavailable: see Errors

Example response · 200

{
  "object": "list",
  "data": [
    {
      "object": "summary",
      "from": "2026-09-29T14:02:11.482Z",
      "to": "2026-09-29T14:02:11.482Z",
      "interval": "hour",
      "organization_id": "org_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
      "user_id": "user_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
      "totals": {
        "requests": 1,
        "verdicts": {"passed": 1, "modified": 1, "blocked": 1, "cut": 1},
        "errors": 1,
        "input_tokens": 1,
        "output_tokens": 1,
        "cost": {
          "amount": "2.00",
          "currency": "USD",
          "estimated": false
        },
        "findings": {
          "secrets": 1,
          "personal_data": 1,
          "prompt_injection": 1,
          "illegal_content": 1
        },
        "organizations": 1,
        "users": 1,
        "models": {"key": 1},
        "providers": {"key": 1}
      },
      "series": [
        {
          "start": "2026-09-29T14:02:11.482Z",
          "totals": {
            "requests": 1,
            "verdicts": {"passed": 1, "modified": 1, "blocked": 1, "cut": 1},
            "errors": 1,
            "input_tokens": 1,
            "output_tokens": 1,
            "cost": {
              "amount": "2.00",
              "currency": "USD",
              "estimated": false
            },
            "findings": {
              "secrets": 1,
              "personal_data": 1,
              "prompt_injection": 1,
              "illegal_content": 1
            },
            "organizations": 1,
            "users": 1,
            "models": {"key": 1},
            "providers": {"key": 1}
          }
        }
      ]
    }
  ],
  "list_metadata": {"before": null, "after": null}
}

Signals

Observations about users and organizations drawn from many requests.

GET/signals

List signalsPermission: read

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

limitqueryinteger
beforequerystring

An object id. Returns the page before it.

afterquerystring

An object id. Returns the page after it.

orderquery"asc" | "desc"
organization_idqueryOrganizationId
user_idqueryUserId
statequerySignalState

Responses

Example response · 200

{
  "object": "list",
  "data": [
    {
      "object": "signal",
      "id": "signal_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
      "kind": "injection_attempts",
      "organization": {
        "id": "org_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
        "external_id": "acme"
      },
      "user": {
        "id": "org_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
        "external_id": "acme"
      },
      "score": 0.5,
      "window": {
        "from": "2026-09-29T14:02:11.482Z",
        "to": "2026-09-29T14:02:11.482Z"
      },
      "evidence": {
        "requests": ["req_01J9ZQ6V8D3K4M5N6P7Q8R9S0T"],
        "features": {"key": 0.5}
      },
      "state": "open",
      "created_at": "2026-09-29T14:02:11.482Z",
      "updated_at": "2026-09-29T14:02:11.482Z"
    }
  ],
  "list_metadata": {"before": null, "after": null}
}

GET/signals/{id}

Get a signalPermission: read

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

idpath, requiredSignalId

Responses

Example response · 200

{
  "object": "signal",
  "id": "signal_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "kind": "injection_attempts",
  "organization": {
    "id": "org_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
    "external_id": "acme"
  },
  "user": {
    "id": "org_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
    "external_id": "acme"
  },
  "score": 0.5,
  "window": {
    "from": "2026-09-29T14:02:11.482Z",
    "to": "2026-09-29T14:02:11.482Z"
  },
  "evidence": {
    "requests": ["req_01J9ZQ6V8D3K4M5N6P7Q8R9S0T"],
    "features": {"key": 0.5}
  },
  "state": "open",
  "created_at": "2026-09-29T14:02:11.482Z",
  "updated_at": "2026-09-29T14:02:11.482Z"
}

POST/signals/{id}/dismiss

Dismiss a signalPermission: manage

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

Idempotency-Keyheaderstring

Makes a retry return the first result for 24 hours. The same key with a different body is refused with 422 idempotency_key_reused.

idpath, requiredSignalId

Responses

Example response · 200

{
  "object": "signal",
  "id": "signal_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "kind": "injection_attempts",
  "organization": {
    "id": "org_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
    "external_id": "acme"
  },
  "user": {
    "id": "org_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
    "external_id": "acme"
  },
  "score": 0.5,
  "window": {
    "from": "2026-09-29T14:02:11.482Z",
    "to": "2026-09-29T14:02:11.482Z"
  },
  "evidence": {
    "requests": ["req_01J9ZQ6V8D3K4M5N6P7Q8R9S0T"],
    "features": {"key": 0.5}
  },
  "state": "open",
  "created_at": "2026-09-29T14:02:11.482Z",
  "updated_at": "2026-09-29T14:02:11.482Z"
}

System prompts

The system prompts the team's app sends, declared so signals know them before traffic shows them. Only a keyed fingerprint of each is kept.

GET/system_prompts

List declared system promptsPermission: read

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

limitqueryinteger
beforequerystring

An object id. Returns the page before it.

afterquerystring

An object id. Returns the page after it.

orderquery"asc" | "desc"

Responses

Example response · 200

{
  "object": "list",
  "data": [
    {
      "object": "system_prompt",
      "id": "prompt_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
      "name": "Acme",
      "fingerprint": "9f2c4e1ab07d5a31",
      "created_at": "2026-09-29T14:02:11.482Z"
    }
  ],
  "list_metadata": {"before": null, "after": null}
}

POST/system_prompts

Declare a system prompt as the app's ownPermission: manage

The usual system prompts are learned from traffic; a declared one is usual from the start, so a user whose requests lack every usual prompt gets the system_prompt_stripped signal. The text is fingerprinted with the environment's key and not kept. A request's system prompt matches when its text is exactly the same, its system blocks joined by line breaks; declaring the same text again is a conflict.

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

Idempotency-Keyheaderstring

Makes a retry return the first result for 24 hours. The same key with a different body is refused with 422 idempotency_key_reused.

Body

SystemPromptCreate

Responses

Example request body

{
  "text": "You are Acme Assist. Answer questions about Acme orders.",
  "name": "Acme"
}

Example response · 201

{
  "object": "system_prompt",
  "id": "prompt_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "name": "Acme",
  "fingerprint": "9f2c4e1ab07d5a31",
  "created_at": "2026-09-29T14:02:11.482Z"
}

GET/system_prompts/{id}

Get a declared system promptPermission: read

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

idpath, requiredSystemPromptId

Responses

Example response · 200

{
  "object": "system_prompt",
  "id": "prompt_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "name": "Acme",
  "fingerprint": "9f2c4e1ab07d5a31",
  "created_at": "2026-09-29T14:02:11.482Z"
}

DELETE/system_prompts/{id}

Withdraw a declared system promptPermission: manage

It stays usual only if traffic shows it to be.

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

idpath, requiredSystemPromptId

Responses

Example response · 200

{
  "object": "system_prompt",
  "id": "prompt_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "name": "Acme",
  "fingerprint": "9f2c4e1ab07d5a31",
  "created_at": "2026-09-29T14:02:11.482Z"
}

Events

Notices of what happened in the environment.

GET/events

List eventsPermission: read

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

limitqueryinteger
beforequerystring

An object id. Returns the page before it.

afterquerystring

An object id. Returns the page after it.

orderquery"asc" | "desc"
eventsqueryEventType[]

Only these event types.

created_afterquerystring (date-time)
created_beforequerystring (date-time)

Responses

Example response · 200

{
  "object": "list",
  "data": [
    {
      "object": "event",
      "id": "event_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
      "event": "organization.created",
      "data": {},
      "actor": {
        "type": "member",
        "id": "member_01J9ZQ6V8D3K4M5N6P7Q8R9S0T"
      },
      "environment_id": "env_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
      "created_at": "2026-09-29T14:02:11.482Z"
    }
  ],
  "list_metadata": {"before": null, "after": null}
}

GET/events/{id}

Get an eventPermission: read

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

idpath, requiredEventId

Responses

Example response · 200

{
  "object": "event",
  "id": "event_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "event": "organization.created",
  "data": {},
  "actor": {"type": "member", "id": "member_01J9ZQ6V8D3K4M5N6P7Q8R9S0T"},
  "environment_id": "env_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "created_at": "2026-09-29T14:02:11.482Z"
}

Webhooks

Endpoints that receive events, and their deliveries.

GET/webhook_endpoints

List webhook endpointsPermission: read

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

limitqueryinteger
beforequerystring

An object id. Returns the page before it.

afterquerystring

An object id. Returns the page after it.

orderquery"asc" | "desc"

Responses

Example response · 200

{
  "object": "list",
  "data": [
    {
      "object": "webhook_endpoint",
      "id": "webhook_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
      "url": "https://example.com/alectura/webhooks",
      "events": ["organization.created"],
      "state": "enabled",
      "disabled_reason": null,
      "created_at": "2026-09-29T14:02:11.482Z",
      "updated_at": "2026-09-29T14:02:11.482Z"
    }
  ],
  "list_metadata": {"before": null, "after": null}
}

POST/webhook_endpoints

Create a webhook endpointPermission: manage

The response is the only time the signing secret is shown.

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

Idempotency-Keyheaderstring

Makes a retry return the first result for 24 hours. The same key with a different body is refused with 422 idempotency_key_reused.

Body

WebhookEndpointCreate

Responses

Example request body

{
  "url": "https://example.com/alectura/webhooks",
  "events": ["user.suspended", "signal.detected"]
}

Example response · 201

{
  "object": "webhook_endpoint",
  "id": "webhook_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "url": "https://example.com/alectura/webhooks",
  "events": ["organization.created"],
  "state": "enabled",
  "disabled_reason": null,
  "created_at": "2026-09-29T14:02:11.482Z",
  "updated_at": "2026-09-29T14:02:11.482Z",
  "secret": "whsec_mJ3q8vXbT2kP9wR4sL7nY1cF6hD0gZ5aE8uB3oI2tK4"
}

GET/webhook_endpoints/{id}

Get a webhook endpointPermission: read

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

idpath, requiredWebhookEndpointId

Responses

Example response · 200

{
  "object": "webhook_endpoint",
  "id": "webhook_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "url": "https://example.com/alectura/webhooks",
  "events": ["organization.created"],
  "state": "enabled",
  "disabled_reason": null,
  "created_at": "2026-09-29T14:02:11.482Z",
  "updated_at": "2026-09-29T14:02:11.482Z"
}

PATCH/webhook_endpoints/{id}

Update, enable or disable a webhook endpointPermission: manage

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

idpath, requiredWebhookEndpointId

Body

WebhookEndpointUpdate

Responses

Example request body

{
  "url": "https://example.com/alectura/webhooks",
  "events": ["organization.created"],
  "state": "enabled"
}

Example response · 200

{
  "object": "webhook_endpoint",
  "id": "webhook_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "url": "https://example.com/alectura/webhooks",
  "events": ["organization.created"],
  "state": "enabled",
  "disabled_reason": null,
  "created_at": "2026-09-29T14:02:11.482Z",
  "updated_at": "2026-09-29T14:02:11.482Z"
}

DELETE/webhook_endpoints/{id}

Delete a webhook endpointPermission: manage

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

idpath, requiredWebhookEndpointId

Responses

Example response · 200

{
  "object": "webhook_endpoint",
  "id": "webhook_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "url": "https://example.com/alectura/webhooks",
  "events": ["organization.created"],
  "state": "enabled",
  "disabled_reason": null,
  "created_at": "2026-09-29T14:02:11.482Z",
  "updated_at": "2026-09-29T14:02:11.482Z"
}

POST/webhook_endpoints/{id}/rotate_secret

Rotate an endpoint's signing secretPermission: manage

For 24 hours, deliveries carry a v1 signature for each of the old and new secrets.

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

Idempotency-Keyheaderstring

Makes a retry return the first result for 24 hours. The same key with a different body is refused with 422 idempotency_key_reused.

idpath, requiredWebhookEndpointId

Responses

Example response · 200

{
  "object": "webhook_endpoint",
  "id": "webhook_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "url": "https://example.com/alectura/webhooks",
  "events": ["organization.created"],
  "state": "enabled",
  "disabled_reason": null,
  "created_at": "2026-09-29T14:02:11.482Z",
  "updated_at": "2026-09-29T14:02:11.482Z",
  "secret": "whsec_mJ3q8vXbT2kP9wR4sL7nY1cF6hD0gZ5aE8uB3oI2tK4"
}

POST/webhook_endpoints/{id}/test

Send a test deliveryPermission: manage

Delivers a webhook_endpoint.test event once, without retries, and returns the attempt.

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

idpath, requiredWebhookEndpointId
Idempotency-Keyheaderstring

Makes a retry return the first result for 24 hours. The same key with a different body is refused with 422 idempotency_key_reused.

Responses

Example response · 200

{
  "object": "delivery",
  "id": "delivery_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "webhook_endpoint_id": "webhook_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "event_id": "event_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "event": "organization.created",
  "state": "pending",
  "attempts": [
    {
      "at": "2026-09-29T14:02:11.482Z",
      "status": 1,
      "duration_ms": 0.5,
      "error": null
    }
  ],
  "next_attempt_at": "2026-09-29T14:02:11.482Z",
  "created_at": "2026-09-29T14:02:11.482Z"
}

GET/webhook_endpoints/{id}/deliveries

List an endpoint's deliveriesPermission: read

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

idpath, requiredWebhookEndpointId
limitqueryinteger
beforequerystring

An object id. Returns the page before it.

afterquerystring

An object id. Returns the page after it.

orderquery"asc" | "desc"
statequeryDeliveryState

Responses

Example response · 200

{
  "object": "list",
  "data": [
    {
      "object": "delivery",
      "id": "delivery_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
      "webhook_endpoint_id": "webhook_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
      "event_id": "event_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
      "event": "organization.created",
      "state": "pending",
      "attempts": [
        {
          "at": "2026-09-29T14:02:11.482Z",
          "status": 1,
          "duration_ms": 0.5,
          "error": null
        }
      ],
      "next_attempt_at": "2026-09-29T14:02:11.482Z",
      "created_at": "2026-09-29T14:02:11.482Z"
    }
  ],
  "list_metadata": {"before": null, "after": null}
}

POST/deliveries/{id}/retry

Retry a failed deliveryPermission: manage

Tries once more now, with the same delivery id.

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

Idempotency-Keyheaderstring

Makes a retry return the first result for 24 hours. The same key with a different body is refused with 422 idempotency_key_reused.

idpath, requiredDeliveryId

Responses

200Delivery

The delivery, with the new attempt.

410Error

The delivery's event has passed its retention.

4XX

An error: see Errors

5XX

A service is unavailable: see Errors

Example response · 200

{
  "object": "delivery",
  "id": "delivery_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "webhook_endpoint_id": "webhook_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "event_id": "event_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "event": "organization.created",
  "state": "pending",
  "attempts": [
    {
      "at": "2026-09-29T14:02:11.482Z",
      "status": 1,
      "duration_ms": 0.5,
      "error": null
    }
  ],
  "next_attempt_at": "2026-09-29T14:02:11.482Z",
  "created_at": "2026-09-29T14:02:11.482Z"
}

Jobs

Replays, evidence packs and assessments, which run in the background.

POST/replays

Replay a draft policy against past requestsPermission: manage

Evaluates the draft against stored requests in the window and reports what would have changed. Requests without retained content replay their routing settings only.

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

Idempotency-Keyheaderstring

Makes a retry return the first result for 24 hours. The same key with a different body is refused with 422 idempotency_key_reused.

Body

ReplayCreate

Responses

Example request body

{
  "policy_id": "policy_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "match": {"organization": "globex"},
  "settings": {
    "routing": {
      "connections": ["own", "environment"],
      "regions": ["eu", "global"],
      "models": ["claude-sonnet-5-5", "claude-haiku-4-5"],
      "data_terms": {"retention": "zero", "training": "no"}
    },
    "retention": {"content": "none"},
    "limits": {
      "requests": [{"per": "user", "period": "minute", "amount": 60}],
      "spend": [
        {"per": "user", "period": "day", "amount": "2.00"},
        {
          "per": "organization",
          "period": "month",
          "amount": "500.00"
        }
      ]
    },
    "guardrails": {
      "secrets": {"action": "redact", "mode": "enforce"},
      "personal_data": {
        "action": "pseudonymize",
        "mode": "enforce",
        "parts": ["user", "tool_result"],
        "kinds": ["email", "phone"],
        "exclusions": ["support@acme.example"]
      },
      "prompt_injection": {
        "action": "cut",
        "mode": "enforce",
        "parts": ["tool_result"]
      },
      "illegal_content": {"action": "block", "mode": "monitor"}
    },
    "uninspected": "allow",
    "abuse": {"suspend_at": 0.9}
  },
  "from": "2026-09-29T14:02:11.482Z",
  "to": "2026-09-29T14:02:11.482Z"
}

Example response · 202

{
  "object": "replay",
  "id": "replay_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "state": "queued",
  "policy": {
    "policy_id": "policy_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
    "match": {"organization": "globex"},
    "settings": {
      "routing": {
        "connections": ["own", "environment"],
        "regions": ["eu", "global"],
        "models": ["claude-sonnet-5-5", "claude-haiku-4-5"],
        "data_terms": {"retention": "zero", "training": "no"}
      },
      "retention": {"content": "none"},
      "limits": {
        "requests": [{"per": "user", "period": "minute", "amount": 60}],
        "spend": [
          {"per": "user", "period": "day", "amount": "2.00"},
          {
            "per": "organization",
            "period": "month",
            "amount": "500.00"
          }
        ]
      },
      "guardrails": {
        "secrets": {"action": "redact", "mode": "enforce"},
        "personal_data": {
          "action": "pseudonymize",
          "mode": "enforce",
          "parts": ["user", "tool_result"],
          "kinds": ["email", "phone"],
          "exclusions": ["support@acme.example"]
        },
        "prompt_injection": {
          "action": "cut",
          "mode": "enforce",
          "parts": ["tool_result"]
        },
        "illegal_content": {"action": "block", "mode": "monitor"}
      },
      "uninspected": "allow",
      "abuse": {"suspend_at": 0.9}
    }
  },
  "from": "2026-09-29T14:02:11.482Z",
  "to": "2026-09-29T14:02:11.482Z",
  "progress": 0.5,
  "result": {
    "requests": 1,
    "with_content": 1,
    "verdicts_changed": {"key": 1},
    "routing_changed": 1,
    "findings_removed": 1,
    "samples": ["req_01J9ZQ6V8D3K4M5N6P7Q8R9S0T"]
  },
  "error": null,
  "created_by": {"type": "member", "id": "member_01J9ZQ6V8D3K4M5N6P7Q8R9S0T"},
  "created_at": "2026-09-29T14:02:11.482Z",
  "completed_at": null
}

GET/replays/{id}

Get a replayPermission: read

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

idpath, requiredReplayId

Responses

200Replay

The replay, with its result once completed.

4XX

An error: see Errors

5XX

A service is unavailable: see Errors

Example response · 200

{
  "object": "replay",
  "id": "replay_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "state": "queued",
  "policy": {
    "policy_id": "policy_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
    "match": {"organization": "globex"},
    "settings": {
      "routing": {
        "connections": ["own", "environment"],
        "regions": ["eu", "global"],
        "models": ["claude-sonnet-5-5", "claude-haiku-4-5"],
        "data_terms": {"retention": "zero", "training": "no"}
      },
      "retention": {"content": "none"},
      "limits": {
        "requests": [{"per": "user", "period": "minute", "amount": 60}],
        "spend": [
          {"per": "user", "period": "day", "amount": "2.00"},
          {
            "per": "organization",
            "period": "month",
            "amount": "500.00"
          }
        ]
      },
      "guardrails": {
        "secrets": {"action": "redact", "mode": "enforce"},
        "personal_data": {
          "action": "pseudonymize",
          "mode": "enforce",
          "parts": ["user", "tool_result"],
          "kinds": ["email", "phone"],
          "exclusions": ["support@acme.example"]
        },
        "prompt_injection": {
          "action": "cut",
          "mode": "enforce",
          "parts": ["tool_result"]
        },
        "illegal_content": {"action": "block", "mode": "monitor"}
      },
      "uninspected": "allow",
      "abuse": {"suspend_at": 0.9}
    }
  },
  "from": "2026-09-29T14:02:11.482Z",
  "to": "2026-09-29T14:02:11.482Z",
  "progress": 0.5,
  "result": {
    "requests": 1,
    "with_content": 1,
    "verdicts_changed": {"key": 1},
    "routing_changed": 1,
    "findings_removed": 1,
    "samples": ["req_01J9ZQ6V8D3K4M5N6P7Q8R9S0T"]
  },
  "error": null,
  "created_by": {"type": "member", "id": "member_01J9ZQ6V8D3K4M5N6P7Q8R9S0T"},
  "created_at": "2026-09-29T14:02:11.482Z",
  "completed_at": null
}

POST/evidence_packs

Build an organization's evidence packPermission: manage

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

Idempotency-Keyheaderstring

Makes a retry return the first result for 24 hours. The same key with a different body is refused with 422 idempotency_key_reused.

Body

EvidencePackCreate

Responses

Example request body

{
  "organization_id": "org_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "from": "2026-09-29T14:02:11.482Z",
  "to": "2026-09-29T14:02:11.482Z"
}

Example response · 202

{
  "object": "evidence_pack",
  "id": "evidence_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "state": "queued",
  "organization_id": "org_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "from": "2026-09-29T14:02:11.482Z",
  "to": "2026-09-29T14:02:11.482Z",
  "error": null,
  "created_by": {"type": "member", "id": "member_01J9ZQ6V8D3K4M5N6P7Q8R9S0T"},
  "created_at": "2026-09-29T14:02:11.482Z",
  "completed_at": null,
  "expires_at": null
}

GET/evidence_packs/{id}

Get an evidence packPermission: read

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

idpath, requiredEvidencePackId

Responses

Example response · 200

{
  "object": "evidence_pack",
  "id": "evidence_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "state": "queued",
  "organization_id": "org_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "from": "2026-09-29T14:02:11.482Z",
  "to": "2026-09-29T14:02:11.482Z",
  "error": null,
  "created_by": {"type": "member", "id": "member_01J9ZQ6V8D3K4M5N6P7Q8R9S0T"},
  "created_at": "2026-09-29T14:02:11.482Z",
  "completed_at": null,
  "expires_at": null
}

GET/evidence_packs/{id}/download

Download a completed evidence packPermission: read

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

idpath, requiredEvidencePackId
formatquery"pdf" | "json"

Responses

200string

The pack.

410Error

The pack's files have been deleted.

4XX

An error: see Errors

5XX

A service is unavailable: see Errors

POST/assessments

Start an assessmentPermission: manage

Returns an upload URL. Uploading the logs to it starts the assessment, which runs apart from live traffic and never touches its data.

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

Idempotency-Keyheaderstring

Makes a retry return the first result for 24 hours. The same key with a different body is refused with 422 idempotency_key_reused.

Body

AssessmentCreate

Responses

Example request body

{"name": "Acme", "format": "openai_chat_jsonl"}

Example response · 201

{
  "object": "assessment",
  "id": "assessment_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "name": "Acme",
  "state": "awaiting_upload",
  "format": "openai_chat_jsonl",
  "upload": {
    "url": "https://example.com/alectura/webhooks",
    "method": "PUT",
    "max_bytes": 1,
    "expires_at": "2026-09-29T14:02:11.482Z"
  },
  "progress": {
    "step": "reading",
    "bytes_read": 1,
    "bytes_total": 1,
    "rows_read": 1,
    "accepted": 1,
    "rejected": {"key": 1},
    "users_seen": 1
  },
  "error": null,
  "created_by": {"type": "member", "id": "member_01J9ZQ6V8D3K4M5N6P7Q8R9S0T"},
  "created_at": "2026-09-29T14:02:11.482Z",
  "completed_at": null
}

GET/assessments/{id}

Get an assessmentPermission: read

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

idpath, requiredAssessmentId

Responses

Example response · 200

{
  "object": "assessment",
  "id": "assessment_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "name": "Acme",
  "state": "awaiting_upload",
  "format": "openai_chat_jsonl",
  "upload": {
    "url": "https://example.com/alectura/webhooks",
    "method": "PUT",
    "max_bytes": 1,
    "expires_at": "2026-09-29T14:02:11.482Z"
  },
  "progress": {
    "step": "reading",
    "bytes_read": 1,
    "bytes_total": 1,
    "rows_read": 1,
    "accepted": 1,
    "rejected": {"key": 1},
    "users_seen": 1
  },
  "error": null,
  "created_by": {"type": "member", "id": "member_01J9ZQ6V8D3K4M5N6P7Q8R9S0T"},
  "created_at": "2026-09-29T14:02:11.482Z",
  "completed_at": null
}

GET/assessments/{id}/report

Download a completed assessment's reportPermission: read

Parameters

Alectura-EnvironmentheaderEnvironmentId

The environment a session acts on. Required with a session; with a management key, it may be sent only if it names the key's own environment.

idpath, requiredAssessmentId
formatquery"pdf" | "json"

Responses

200string

The report.

410Error

The assessment's files have been deleted.

4XX

An error: see Errors

5XX

A service is unavailable: see Errors

Example response · 200

{
  "object": "assessment_report",
  "assessment_id": "assessment_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "name": "Acme",
  "format": "openai_chat_jsonl",
  "from": "2026-09-29T14:02:11.482Z",
  "to": "2026-09-29T14:02:11.482Z",
  "generated_at": "2026-09-29T14:02:11.482Z",
  "rows": {"read": 1, "accepted": 1, "rejected": {"key": 1}},
  "users_analyzed": 1,
  "suspicious_users": 1,
  "tokens": {"total": 1, "suspicious": 1},
  "suspicious_token_share": 0.5,
  "estimated_cost": {"total": "2.00", "suspicious": "2.00"},
  "users": [
    {
      "user": "user_42",
      "organization": "acme",
      "plan": "pro",
      "score": 0.5,
      "requests": 1,
      "tokens": 1,
      "estimated_cost": "2.00",
      "signals": [
        {
          "kind": "injection_attempts",
          "score": 0.5,
          "lines": [1]
        }
      ]
    }
  ],
  "unavailable_signals": ["unavailable_signals"]
}

Team

The team, its members, projects and environments, on us.api only. Sessions only.

GET/team

Get the signed-in member's team

Responses

Example response · 200

{
  "object": "team",
  "id": "team_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "name": "Acme",
  "created_at": "2026-09-29T14:02:11.482Z",
  "updated_at": "2026-09-29T14:02:11.482Z"
}

GET/team/members

List team members

Parameters

limitqueryinteger
beforequerystring

An object id. Returns the page before it.

afterquerystring

An object id. Returns the page after it.

orderquery"asc" | "desc"

Responses

200MemberList

A page of members, invited ones included.

4XX

An error: see Errors

5XX

A service is unavailable: see Errors

Example response · 200

{
  "object": "list",
  "data": [
    {
      "object": "member",
      "id": "member_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
      "email": "ada@example.com",
      "name": "Acme",
      "role": "admin",
      "state": "invited",
      "created_at": "2026-09-29T14:02:11.482Z",
      "updated_at": "2026-09-29T14:02:11.482Z"
    }
  ],
  "list_metadata": {"before": null, "after": null}
}

PATCH/team/members/{id}

Change a member's role

Parameters

idpath, requiredMemberId

Body

MemberUpdate

Responses

Example request body

{"role": "admin"}

Example response · 200

{
  "object": "member",
  "id": "member_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "email": "ada@example.com",
  "name": "Acme",
  "role": "admin",
  "state": "invited",
  "created_at": "2026-09-29T14:02:11.482Z",
  "updated_at": "2026-09-29T14:02:11.482Z"
}

DELETE/team/members/{id}

Remove a member

Locks the member out of every region within seconds, whatever their session says.

Parameters

idpath, requiredMemberId

Responses

Example response · 200

{
  "object": "member",
  "id": "member_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "email": "ada@example.com",
  "name": "Acme",
  "role": "admin",
  "state": "invited",
  "created_at": "2026-09-29T14:02:11.482Z",
  "updated_at": "2026-09-29T14:02:11.482Z"
}

POST/team/invitations

Invite someone to the team

Stytch emails a sign-in link. The invited member holds the role once they sign in.

Parameters

Idempotency-Keyheaderstring

Makes a retry return the first result for 24 hours. The same key with a different body is refused with 422 idempotency_key_reused.

Body

InvitationCreate

Responses

Example request body

{"email": "ada@example.com", "role": "admin"}

Example response · 201

{
  "object": "member",
  "id": "member_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "email": "ada@example.com",
  "name": "Acme",
  "role": "admin",
  "state": "invited",
  "created_at": "2026-09-29T14:02:11.482Z",
  "updated_at": "2026-09-29T14:02:11.482Z"
}

GET/projects

List projects

Parameters

limitqueryinteger
beforequerystring

An object id. Returns the page before it.

afterquerystring

An object id. Returns the page after it.

orderquery"asc" | "desc"

Responses

Example response · 200

{
  "object": "list",
  "data": [
    {
      "object": "project",
      "id": "project_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
      "name": "Acme",
      "created_at": "2026-09-29T14:02:11.482Z",
      "updated_at": "2026-09-29T14:02:11.482Z"
    }
  ],
  "list_metadata": {"before": null, "after": null}
}

POST/projects

Create a project

Parameters

Idempotency-Keyheaderstring

Makes a retry return the first result for 24 hours. The same key with a different body is refused with 422 idempotency_key_reused.

Body

ProjectCreate

Responses

Example request body

{"name": "Acme"}

Example response · 201

{
  "object": "project",
  "id": "project_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "name": "Acme",
  "created_at": "2026-09-29T14:02:11.482Z",
  "updated_at": "2026-09-29T14:02:11.482Z"
}

GET/environments

List the team's environments, in every region

Parameters

limitqueryinteger
beforequerystring

An object id. Returns the page before it.

afterquerystring

An object id. Returns the page after it.

orderquery"asc" | "desc"
project_idqueryProjectId

Responses

Example response · 200

{
  "object": "list",
  "data": [
    {
      "object": "environment",
      "id": "env_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
      "project_id": "project_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
      "name": "Acme",
      "region": "us",
      "production": false,
      "api_base_url": "https://eu.api.alecturalabs.com/v1",
      "gateway_base_url": "https://eu.gateway.alecturalabs.com",
      "created_at": "2026-09-29T14:02:11.482Z",
      "updated_at": "2026-09-29T14:02:11.482Z"
    }
  ],
  "list_metadata": {"before": null, "after": null}
}

POST/environments

Create an environment in a region

The environment lives in its region for good. Its region's host serves its config and traffic, and sets up its state there on first use, starting with a baseline policy that matches every request and allows only its own region.

Parameters

Idempotency-Keyheaderstring

Makes a retry return the first result for 24 hours. The same key with a different body is refused with 422 idempotency_key_reused.

Body

EnvironmentCreate

Responses

Example request body

{
  "project_id": "project_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "name": "Acme",
  "region": "us",
  "production": false
}

Example response · 201

{
  "object": "environment",
  "id": "env_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "project_id": "project_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "name": "Acme",
  "region": "us",
  "production": false,
  "api_base_url": "https://eu.api.alecturalabs.com/v1",
  "gateway_base_url": "https://eu.gateway.alecturalabs.com",
  "created_at": "2026-09-29T14:02:11.482Z",
  "updated_at": "2026-09-29T14:02:11.482Z"
}

GET/environments/{id}

Get an environment

Parameters

idpath, requiredEnvironmentId

Responses

Example response · 200

{
  "object": "environment",
  "id": "env_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "project_id": "project_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "name": "Acme",
  "region": "us",
  "production": false,
  "api_base_url": "https://eu.api.alecturalabs.com/v1",
  "gateway_base_url": "https://eu.gateway.alecturalabs.com",
  "created_at": "2026-09-29T14:02:11.482Z",
  "updated_at": "2026-09-29T14:02:11.482Z"
}

PATCH/environments/{id}

Rename an environment

Parameters

idpath, requiredEnvironmentId

Body

EnvironmentUpdate

Responses

Example request body

{"name": "Acme"}

Example response · 200

{
  "object": "environment",
  "id": "env_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "project_id": "project_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "name": "Acme",
  "region": "us",
  "production": false,
  "api_base_url": "https://eu.api.alecturalabs.com/v1",
  "gateway_base_url": "https://eu.gateway.alecturalabs.com",
  "created_at": "2026-09-29T14:02:11.482Z",
  "updated_at": "2026-09-29T14:02:11.482Z"
}

Webhook events

Each event is delivered to your endpoints as a signed POST with this body.

organization.createdEvent & object

An organization was created, by the API or by the first request that named it.

organization.updatedEvent & object

An organization's name or metadata changed.

organization.deletedEvent & object

An organization was deleted. Its key is already destroyed.

user.createdEvent & object

A user was created, by the API or by the first request that named it.

user.updatedEvent & object

A user's name or metadata changed.

system_prompt.createdEvent & object

A system prompt was declared as the app's own.

system_prompt.deletedEvent & object

A declared system prompt was withdrawn.

user.suspendedEvent & object

A user was suspended, by a team member, a key or a policy.

user.unsuspendedEvent & object

A user's suspension was lifted or expired.

organization.suspendedEvent & object

An organization was suspended, by a team member, a key or a policy.

organization.unsuspendedEvent & object

An organization's suspension was lifted or expired.

signal.detectedEvent & object

A signal job observed something about a user or organization.

policy.createdEvent & object

A policy was created.

policy.updatedEvent & object

A policy changed, making a new version.

policy.deletedEvent & object

A policy was deleted.

connection.createdEvent & object

A connection was created, as a draft.

connection.updatedEvent & object

A connection changed, including its state.

connection.deletedEvent & object

A connection was deleted.

api_key.createdEvent & object

An API key was created. The event never carries the secret.

api_key.updatedEvent & object

An API key was renamed, disabled, enabled, rotated or given an expiry.

api_key.revokedEvent & object

An API key was revoked.

webhook_endpoint.disabledEvent & object

An endpoint was disabled because a delivery to it failed five times. It goes to the other endpoints.

webhook_endpoint.testEvent & object

A test delivery, sent only to the endpoint being tested.

request.blockedEvent & object

A policy refused a request. Suspensions count.

request.cutEvent & object

A guardrail cut a response.

request.content_readEvent & object

Someone read a request's content or an attachment.

limit.threshold_crossedEvent & object

A limit passed 80% or 95% of its amount, or started refusing.

replay.completedEvent & object

A replay finished.

replay.failedEvent & object

A replay failed.

evidence_pack.completedEvent & object

An evidence pack is ready to download.

evidence_pack.failedEvent & object

An evidence pack failed.

assessment.completedEvent & object

An assessment's report is ready.

assessment.failedEvent & object

An assessment failed.

Schemas

Error

coderequiredstring
messagerequiredstring
errorsobject[]

Each item

fieldrequiredstring

A dotted path into the body, such as settings.routing.regions.

coderequiredstring
messagestring
request_idrequiredRequestId

ListMetadata

beforerequiredstring | null
afterrequiredstring | null

Timestamp

string (date-time)

Money

amountrequiredDecimal
currencyrequired"USD"
estimatedrequiredboolean

True for list prices from the pinned price map, rather than a provider's bill.

Decimal

string

ExternalId

The team's own identifier, as the Alectura-* headers carry it.

string

Metadata

map<string, string>

Actor

Who made a change.

typerequired"api_key" | "member" | "policy" | "system"
idrequiredstring | null

The key's, member's or policy's id; null for the system.

Example

{"type": "member", "id": "member_01J9ZQ6V8D3K4M5N6P7Q8R9S0T"}

Region

A region Alectura runs in.

"us" | "eu" | "au"

ProviderRegion

Where a provider processes a request. global is for endpoints that promise no region, such as Bedrock's global. inference profiles.

"us" | "eu" | "au" | "apac" | "global"

OrganizationId

string

UserId

string

OrganizationMembershipId

string

SuspensionId

string

SystemPromptId

string

PolicyId

string

ConnectionId

string

ApiKeyId

string

RequestId

string

ConversationId

string

FindingId

string

DispositionId

string

SignalId

string

EventId

string

WebhookEndpointId

string

DeliveryId

string

ReplayId

string

EvidencePackId

string

AssessmentId

string

TeamId

string

MemberId

string

ProjectId

string

EnvironmentId

string

Ref

A reference to an organization or user, with the team's identifier.

idrequiredstring
external_idrequiredExternalId

Example

{"id": "org_01J9ZQ6V8D3K4M5N6P7Q8R9S0T", "external_id": "acme"}

Organization

objectrequired"organization"
idrequiredOrganizationId
external_idrequiredExternalId
namerequiredstring | null
metadatarequiredMetadata
planrequiredstring | null

The plan named by its latest request that sent Alectura-Plan; null until one does.

suspendedrequiredboolean
staterequired"active" | "deleting"
first_seen_atrequiredstring (date-time) | null
last_seen_atrequiredstring (date-time) | null
created_atrequiredTimestamp
updated_atrequiredTimestamp

OrganizationUpdate

namestring | null
metadataMetadata

User

objectrequired"user"
idrequiredUserId
external_idrequiredExternalId
namerequiredstring | null
metadatarequiredMetadata
suspendedrequiredboolean
signalsUserSignal[]

The user's open signals, strongest first: those neither dismissed nor acted on. The management API's users carry them; a user in an event's data doesn't.

first_seen_atrequiredstring (date-time) | null
last_seen_atrequiredstring (date-time) | null
created_atrequiredTimestamp
updated_atrequiredTimestamp

UserSignal

An open signal on a user, as the users list shows it. getSignal has the rest.

idrequiredSignalId
kindrequiredstring

What was observed, as the signal's kind.

scorerequirednumber

UserUpdate

namestring | null
metadataMetadata

RelatedUserList

objectrequired"list"
datarequiredobject[]

Each item

objectrequired"related_user"
userrequiredRef
shared_fingerprintsrequiredinteger

How many prompt templates both users' requests share.

list_metadatarequiredListMetadata

Suspension

objectrequired"suspension"
idrequiredSuspensionId
organizationrequiredRef | null

Set when an organization is suspended.

userrequiredRef | null

Set when a user is suspended.

reasonrequiredstring

A short reason, such as signals for one a policy made.

noterequiredstring | null
created_byrequiredActor
created_atrequiredTimestamp
expires_atrequiredstring (date-time) | null
lifted_atrequiredstring (date-time) | null
lifted_byrequiredActor | null

SuspensionCreate

Names exactly one of organization_id and user_id.

organization_idOrganizationId
user_idUserId
reasonrequiredstring
notestring
expires_atTimestamp

Example

{
  "user_id": "user_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "reason": "abuse",
  "note": "Scraping answers at volume.",
  "expires_at": "2026-10-09T00:00:00.000Z"
}

SystemPrompt

A system prompt the team declared as its app's own. Its text isn't kept.

objectrequired"system_prompt"
idrequiredSystemPromptId
namerequiredstring | null
fingerprintrequiredstring

The keyed hash of the prompt's text, as requests' prompts are hashed.

created_atrequiredTimestamp

SystemPromptCreate

textrequiredstring

The prompt, exactly as the app sends it, several system blocks joined by line breaks. Only its fingerprint is kept.

namestring | null

Policy

objectrequired"policy"
idrequiredPolicyId
namerequiredstring
descriptionrequiredstring | null
matchrequiredMatch
settingsrequiredSettings
versionrequiredinteger
created_atrequiredTimestamp
updated_atrequiredTimestamp

Example

{
  "object": "policy",
  "id": "policy_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "name": "Free plan",
  "description": "Tighter limits and EU-only routing for the free plan.",
  "match": {"plan": "free"},
  "settings": {
    "routing": {"regions": ["eu"]},
    "limits": {
      "requests": [{"per": "user", "period": "minute", "amount": 20}],
      "spend": [{"per": "user", "period": "day", "amount": "0.50"}]
    },
    "guardrails": {
      "secrets": {"action": "redact", "mode": "enforce"},
      "personal_data": {"action": "pseudonymize", "mode": "enforce"}
    }
  },
  "version": 1,
  "created_at": "2026-09-29T14:02:11.482Z",
  "updated_at": "2026-09-29T14:02:11.482Z"
}

PolicyCreate

namerequiredstring
descriptionstring
matchrequiredMatch
settingsrequiredSettings

Example

{
  "name": "Free plan",
  "description": "Tighter limits and EU-only routing for the free plan.",
  "match": {"plan": "free"},
  "settings": {
    "routing": {"regions": ["eu"]},
    "limits": {
      "requests": [{"per": "user", "period": "minute", "amount": 20}],
      "spend": [{"per": "user", "period": "day", "amount": "0.50"}]
    },
    "guardrails": {
      "secrets": {"action": "redact", "mode": "enforce"},
      "personal_data": {"action": "pseudonymize", "mode": "enforce"}
    }
  }
}

PolicyUpdate

namestring
descriptionstring | null
matchMatch

Replaces the whole match, never merges into it: a field left out no longer selects.

settingsSettings

Example

{
  "settings": {
    "limits": {
      "spend": [{"per": "user", "period": "day", "amount": "1.00"}]
    }
  }
}

PolicyVersion

objectrequired"policy_version"
policy_idrequiredPolicyId
versionrequiredinteger
namerequiredstring
matchrequiredMatch
settingsrequiredSettings
deletedrequiredboolean

True for the version that deleted the policy.

created_byrequiredActor
created_atrequiredTimestamp

Match

Selects requests by their Alectura-* headers. Every field given must hold, and an omitted field matches anything. {} matches every request.

organizationMatchValue
userMatchValue
planMatchValue

Example

{"organization": "globex"}

MatchValue

A value, any of a list of values, or null for requests that don't send the header.

ExternalId | ExternalId[] | null

Settings

Each setting combines across matching policies by the rule in its description, and every rule only tightens. A setting no matching policy sets takes its default.

routingRoutingSettings
retentionRetentionSettings
limitsLimitSettings
guardrailsGuardrailSettings
uninspected"allow" | "block"

What to do with content nothing can inspect, such as images. block wins. Default allow, with the content recorded as uninspected.

abuseobject

What happens when a signal flags a user or organization for abuse.

Fields

suspend_atnumber

Suspend the user when a signal's score reaches this; an organization is never suspended automatically. The lowest wins. Default: never.

RoutingSettings

connections("own" | "environment")[]

Whose connections may serve a request, in order. own is the organization's own connections: an organization that owns any is served by them alone, so a request none of them can serve is refused with no_allowed_connection, while one that owns none, or a request without an organization, is served by the environment's. environment is the environment's, so [own, environment] falls back to them. Across policies, the members every policy allows, in the order of the most specific policy that sets it. Default ["own"]. A policy lists at least one; an effective policy's list is empty when its policies allow nothing in common.

regionsProviderRegion[]

Where a provider may process a request, in order of preference. Across policies, the members every policy allows, in the order of the most specific policy that sets it. Default: the environment's own region. A policy lists at least one; an effective policy's list is empty when its policies allow nothing in common, and then refuses every request.

modelsstring[]

The models a request may use; an id without a date matches every dated version. Across policies, the intersection. Default: any model an active connection serves.

data_termsobject

The data terms a connection must declare (Connection.data_terms) to serve a request. A connection whose terms are undeclared doesn't meet a requirement. When no connection that meets them serves the model, the request is refused with no_allowed_connection. Default: any terms.

Fields

retention"any" | "zero"

zero: only connections whose provider keeps nothing it's sent. Across policies, zero wins. Content retention none doesn't imply it.

training"any" | "no"

no: only connections whose provider doesn't train on what it's sent. Across policies, no wins.

Example

{
  "connections": ["own", "environment"],
  "regions": ["eu", "global"],
  "models": ["claude-sonnet-5-5", "claude-haiku-4-5"],
  "data_terms": {"retention": "zero", "training": "no"}
}

RetentionSettings

content"none" | "team" | "7d" | "30d" | "90d" | "365d"

How long a request's content is kept. Across policies, the earliest in this list. Default none. team means held by the team rather than by Alectura: in the environment's content store (/content_store), for as long as the team keeps it. Until the environment has an active content store, team keeps no content, as none. Records are kept 400 days whatever this says.

LimitSettings

For each pair of per and period, the lowest amount among matching policies wins; limits for different pairs all apply. requests and tokens take a minute or a day, and spend a day, a week or a month. A limit over a minute refuses with 429; over a day, week or month, with 402. Periods are calendar periods in UTC, and weeks start on Monday.

max_output_tokensinteger

Lowers a request's maximum output to this, and sets it when the request doesn't. The lowest wins.

requestsobject[]

Each item

perrequiredLimitScope
periodrequired"minute" | "day"
amountrequiredinteger
tokensobject[]

Input and output tokens together.

Each item

perrequiredLimitScope
periodrequired"minute" | "day"
amountrequiredinteger
spendobject[]

Estimated cost at list prices, in USD.

Each item

perrequiredLimitScope
periodrequired"day" | "week" | "month"
amountrequiredDecimal

Example

{
  "requests": [{"per": "user", "period": "minute", "amount": 60}],
  "spend": [
    {"per": "user", "period": "day", "amount": "2.00"},
    {
      "per": "organization",
      "period": "month",
      "amount": "500.00"
    }
  ]
}

LimitScope

A request without a user or organization isn't counted against limits for it.

"user" | "organization"

GuardrailSettings

Across policies: each guardrail's action and mode take the strictest value, in the order listed for each; parts and kinds the union; exclusions the intersection. A guardrail no matching policy sets doesn't run.

secretsobject

Credentials and private keys. In the request, redact replaces each with [redacted:kind] and block refuses it with blocked_by_guardrail. In the answer (output), streamed or not, redact redacts the same way, holding back the text a secret could still be growing into across deltas, and block cuts the answer with cut_by_guardrail.

Fields

actionrequired"record" | "redact" | "block"
moderequiredGuardrailMode
partsParts
personal_dataobject

Personal data of the kinds selected. In the request, pseudonymize replaces each value with a pseudonym, [[kind:hash8]], which the answer gets back as the value; redact replaces it with [redacted:kind]; block refuses the request. In the answer (output), redact redacts what the answer holds and block cuts it with cut_by_guardrail; under pseudonymize the answer's pseudonyms are restored and personal data the answer adds is recorded, since a pseudonym would reach the client in its place. person_name, street_address and date_of_birth are found in English text without a model (crates/guard/accuracy/README.md has how well).

Fields

actionrequired"record" | "pseudonymize" | "redact" | "block"
moderequiredGuardrailMode
partsParts
kinds("email" | "phone" | "card_number" | "iban" | "ip_address" | "national_id" | "person_name" | "street_address" | "date_of_birth")[]

Default all.

exclusionsstring[]

Exact values never treated as personal data, such as the team's support address.

prompt_injectionobject

Instructions that try to take over the model, in the request's parts, tool results included. It judges the request, not the answer, so its parts can't name output.

Fields

actionrequired"flag" | "cut"
moderequiredGuardrailMode
partsParts
illegal_contentobject

Requests for help with a crime, judged by a local model over the parts selected, tool results included. block refuses the request before the provider sees it, with blocked_by_guardrail; flag records the finding and lets it through. The kinds are MLCommons' hazard categories that are crimes wherever the request comes from, with illegal conventional weapons joined to chemical, biological, radiological, nuclear and explosive ones in weapons. It judges the request before the provider sees it, not the answer, so its parts can't name output. Its measured precision and recall per kind are published; start in monitor mode.

Fields

actionrequired"flag" | "block"
moderequiredGuardrailMode
partsParts
kinds("violent_crimes" | "non_violent_crimes" | "sex_crimes" | "child_sexual_exploitation" | "weapons")[]

Default all.

Example

{
  "secrets": {"action": "redact", "mode": "enforce"},
  "personal_data": {
    "action": "pseudonymize",
    "mode": "enforce",
    "parts": ["user", "tool_result"],
    "kinds": ["email", "phone"],
    "exclusions": ["support@acme.example"]
  },
  "prompt_injection": {"action": "cut", "mode": "enforce", "parts": ["tool_result"]},
  "illegal_content": {"action": "block", "mode": "monitor"}
}

GuardrailMode

monitor records what the guardrail would do; enforce does it. enforce wins.

"monitor" | "enforce"

Parts

The parts of a request a guardrail inspects. Default all of them that the guardrail reads. Only secrets and personal_data read output; a policy that names it for another guardrail is refused with 422 validation_failed.

Part[]

Part

output is the provider's answer, streamed or not; the rest are the request's input.

"system" | "user" | "assistant" | "tool_call" | "tool_result" | "output"

EffectivePolicy

objectrequired"effective_policy"
identityrequiredobject

Fields

organizationrequiredstring | null
userrequiredstring | null
planrequiredstring | null
policiesrequiredPolicyRef[]

The matching policies, at their current versions.

settingsrequiredSettings

The settings as they apply. One no matching policy sets shows at its default: routing to the environment's region on ["own"] connections, retention none and uninspected: allow; a guardrail or a limit no policy sets is absent, since its default is to do nothing.

sourcesrequiredmap<string, PolicyId[]>

For each setting, by its dotted path, the policies that decided its value. A setting that no policy sets is absent, and takes its default.

PolicyRef

idrequiredPolicyId
versionrequiredinteger

Provider

gemini is the Gemini API, in its own format. simulator answers inside the gateway with recorded responses, in the region of the environment's cell, so no provider is reached or paid: any team may connect it to try Alectura, and outside the demo team each environment may send it a burst of 20 requests and 60 a minute, past which a request no other connection can serve is refused 429 rate_limited.

"openai" | "anthropic" | "bedrock" | "gemini" | "simulator"

ConnectionState

Only an active connection routes. A connection is activated only after its test passes.

"draft" | "active" | "disabled"

DataTerms

What the provider's terms for this account say, as declared by whoever made the connection. Undeclared counts as retaining. Prompt caching in memory isn't retention.

retentionrequired"undeclared" | "zero" | "retains"
trainingrequired"undeclared" | "no" | "yes"

Credential

Write-only. Reading a connection returns only CredentialHint.

object | object

CredentialHint

typerequired"api_key" | "aws_role"
hintrequiredstring

The last four characters of a key, or a role's name.

Owner

Who owns the connection.

object | object

Connection

objectrequired"connection"
idrequiredConnectionId
namerequiredstring
providerrequiredProvider
ownerrequiredOwner
base_urlrequired"https://api.openai.com/v1" | "https://eu.api.openai.com/v1" | "https://api.anthropic.com" | "https://generativelanguage.googleapis.com" | null

For OpenAI, Anthropic and Gemini.

aws_regionrequiredstring | null

For Bedrock.

inference_profilerequired"us" | "eu" | "apac" | "au" | "global" | null

For Bedrock, a cross-region inference profile, or null for the region's own endpoint.

regionrequiredProviderRegion

Where the endpoint promises to process requests. Derived, never set.

modelsrequiredstring[]

The models it serves, by the ids clients send.

data_termsrequiredDataTerms
credentialrequiredCredentialHint
aws_external_idrequiredstring | null

For an aws_role credential, the external id the role's trust policy must require.

staterequiredConnectionState
cooling_down_untilrequiredstring (date-time) | null

Set while repeated failures keep the connection out of routing.

created_atrequiredTimestamp
updated_atrequiredTimestamp

Example

{
  "object": "connection",
  "id": "conn_01J9ZQ6V8D3K4M5N6P7Q8R9S0T",
  "name": "OpenAI EU",
  "provider": "openai",
  "owner": {"type": "environment"},
  "base_url": "https://eu.api.openai.com/v1",
  "aws_region": null,
  "inference_profile": null,
  "region": "eu",
  "models": ["gpt-5", "gpt-5-mini"],
  "data_terms": {"retention": "zero", "training": "no"},
  "credential": {"type": "api_key", "hint": "Qk3x"},
  "aws_external_id": null,
  "state": "draft",
  "cooling_down_until": null,
  "created_at": "2026-09-29T14:02:11.482Z",
  "updated_at": "2026-09-29T14:02:11.482Z"
}

ConnectionCreate

namerequiredstring
providerrequiredProvider
ownerOwner

Default the environment.

base_url"https://api.openai.com/v1" | "https://eu.api.openai.com/v1" | "https://api.anthropic.com" | "https://generativelanguage.googleapis.com"
aws_regionstring
inference_profile"us" | "eu" | "apac" | "au" | "global" | null
modelsrequiredstring[]
data_termsDataTerms
credentialCredential

Required, except for the simulator, which reaches no provider and needs no key.

Example

{
  "name": "OpenAI EU",
  "provider": "openai",
  "base_url": "https://eu.api.openai.com/v1",
  "models": ["gpt-5", "gpt-5-mini"],
  "data_terms": {"retention": "zero", "training": "no"},
  "credential": {"type": "api_key", "api_key": "sk-proj-…"}
}

ConnectionTest

objectrequired"connection_test"
connection_idrequiredConnectionId
passedrequiredboolean

True when every check passed.

checksrequiredobject[]

Each item

namerequiredstring

What was checked, such as credential, model:gpt-5, stream or usage.

passedrequiredboolean
reasonrequiredstring | null

Why it failed, such as invalid_credential, model_unavailable, invalid_stream, missing_usage or region_not_allowed.

messagerequiredstring | null
upstream_statusinteger | null

The provider's HTTP status, when it answered.

created_atrequiredTimestamp

ContentStore

Where team-held content goes: an S3 bucket in the team's own AWS account, reached through a role there whose trust policy allows Alectura's account with external_id. Content packs, attachments and pseudonyms are written under prefix, sealed with each organization's key, and read through the same role. Their lifecycle is the bucket's.

objectrequired"content_store"
bucketrequiredstring
regionrequiredstring
prefixrequiredstring

What every key starts with: empty, or ending in /.

role_arnrequiredstring
external_idrequiredstring

What the role's trust policy must require as sts:ExternalId.

staterequired"draft" | "active"

Only an active store takes content. A store becomes active when its test passes.

created_atrequiredTimestamp
updated_atrequiredTimestamp

ContentStoreSet

bucketrequiredstring
regionrequiredstring

The bucket's AWS region, which must be in the environment's region, so content never leaves it.

prefixstring
role_arnrequiredstring

ContentStoreTest

objectrequired"content_store_test"
passedrequiredboolean
messagerequiredstring | null

Why it failed, such as the role that couldn't be assumed or the key that couldn't be written.

content_storerequiredContentStore

ApiKeyType

Sending keys call the gateway; management keys call this API.

"sending" | "management"

ApiKeyState

"active" | "disabled" | "expired" | "revoked"

Permission

"send" | "read" | "read_content" | "manage"

ApiKey

objectrequired"api_key"
idrequiredApiKeyId
namerequiredstring
typerequiredApiKeyType
permissionsrequiredPermission[]

send alone for a sending key; any of the others for a management key.

labelrequiredstring

The key with all but its prefix and last six characters masked.

staterequiredApiKeyState
expires_atrequiredstring (date-time) | null
previous_secret_expires_atrequiredstring (date-time) | null

After a rotation, when the old secret stops working.

created_byrequiredActor
created_atrequiredTimestamp
updated_atrequiredTimestamp

ApiKeyWithSecret

ApiKey & object

ApiKeyCreate

namerequiredstring
typeApiKeyType

Default sending.

permissions("read" | "read_content" | "manage")[]

For a management key; a sending key always has send alone.

expires_atTimestamp

ApiKeyUpdate

namestring
state"active" | "disabled"
expires_atstring (date-time) | null

Verdict

"passed" | "modified" | "blocked" | "cut"

Guardrail

"secrets" | "personal_data" | "prompt_injection" | "illegal_content"

ContentVersion

What the client sent; what the provider received; what the provider sent back; what the client received.

"client_request" | "provider_request" | "provider_response" | "client_response"

Request

objectrequired"request"
idrequiredRequestId
staterequired"pending" | "completed" | "interrupted"

pending while the request is still running; interrupted if its end never arrived because the gateway task serving it stopped.

created_atrequiredTimestamp
completed_atrequiredstring (date-time) | null
organizationrequiredRef | null
userrequiredRef | null
planrequiredstring | null
conversation_idrequiredConversationId | null
api_key_idrequiredApiKeyId
endpointrequired"openai.chat_completions" | "openai.responses" | "anthropic.messages" | "gemini.generate_content" | null

Null for a request refused before its path named an endpoint.

modelrequiredstring | null

The model the request asked for; null for a request refused before its body was read.

streamrequiredboolean
statusrequiredinteger | null

The HTTP status the client received; null while pending.

verdictrequiredVerdict
refusalrequiredobject | null

Our refusal or cut, if there was one.

connectionrequiredConnectionRef | null

The connection that served the request, if any did.

attemptsrequiredobject[]

Every connection tried, in order.

Each item

connectionrequiredConnectionRef
started_atrequiredTimestamp
statusrequiredinteger | null

The provider's HTTP status; null if it never answered.

errorrequiredstring | null

Why the attempt failed, such as provider_timeout or the provider's own error code.

duration_msrequirednumber
policiesrequiredPolicyRef[]

The policies that matched, at their versions then.

findingsrequiredFinding[]
coveragerequiredobject[]

For each block, the detectors that ran on it, or why none did. A request that reached a provider ends with one more entry, part output, for the answer: read by the guardrails that select output, or not_selected. Findings in the answer name that entry's block.

Each item

blockrequiredinteger
partrequiredPart
modalityrequired"text" | "image" | "audio" | "video" | "file" | "reasoning"
inspected_byrequiredGuardrail[]
reasonrequired"images_uninspected" | "audio_uninspected" | "video_uninspected" | "files_uninspected" | "uninspectable" | "encrypted" | "not_selected" | null

Why no detector ran, or null when one did. images_uninspected, audio_uninspected and video_uninspected: no detector reads that modality. files_uninspected: a file with no text layer a detector reads, or one the body only points at. uninspectable: a part the gateway doesn't read. encrypted: signed or encrypted provider content, which passes through byte for byte. not_selected: no guardrail that runs selects the block's part.

usagerequiredUsage | null
costrequiredMoney | null
timingsrequiredobject

Fields

overhead_msrequirednumber

Time the gateway added, excluding the provider.

first_byte_msrequirednumber | null
duration_msrequirednumber | null
contentrequiredobject

Fields

retainedrequiredboolean
retentionrequired"none" | "team" | "7d" | "30d" | "90d" | "365d"
expires_atrequiredstring (date-time) | null
reasonrequiredstring | null

Why content wasn't kept, such as retention_none.

Usage

input_tokensrequiredinteger

Input tokens not read from or written to the cache.

output_tokensrequiredinteger

Output tokens, reasoning included.

cache_read_input_tokensrequiredinteger
cache_creation_input_tokensrequiredinteger
reasoning_tokensrequiredinteger | null
estimatedrequiredboolean

True when the provider reported no usage and the gateway counted.

rawrequiredobject | null

The provider's usage object, as it sent it.

Finding

objectrequired"finding"
idrequiredFindingId
guardrailrequiredGuardrail
kindrequiredstring

What the detector found, such as aws_access_key, email, instruction_override or weapons.

actionrequired"record" | "redact" | "pseudonymize" | "block" | "flag" | "cut"
moderequiredGuardrailMode
appliedrequiredboolean

False in monitor mode, where the action is only recorded.

blockrequiredinteger
partrequiredPart

ContentRead

objectrequired"content_read"
request_idrequiredRequestId
versionrequiredContentVersion | null
attachmentrequiredstring | null

The attachment's hash, when one was read.

readerrequiredActor

FindingsSummary

objectrequired"findings_summary"
fromrequiredTimestamp
torequiredTimestamp
groupsrequiredobject[]

Each item

guardrailrequiredGuardrail
kindrequiredstring
actionrequiredstring
moderequiredGuardrailMode
countrequiredinteger
requestsrequiredinteger

Distinct requests, each counted once however often a block was resent.

samplesrequiredRequestId[]

Disposition

objectrequired"disposition"
idrequiredDispositionId
finding_idrequiredFindingId
labelrequired"false_positive" | "confirmed"
noterequiredstring | null
created_byrequiredActor
created_atrequiredTimestamp

DispositionCreate

labelrequired"false_positive" | "confirmed"
notestring

Totals

requestsrequiredinteger
verdictsrequiredobject

Fields

passedrequiredinteger
modifiedrequiredinteger
blockedrequiredinteger
cutrequiredinteger
errorsrequiredinteger

Requests whose provider failed.

input_tokensrequiredinteger
output_tokensrequiredinteger
costrequiredMoney
findingsrequiredobject

Fields

secretsrequiredinteger
personal_datarequiredinteger
prompt_injectionrequiredinteger
illegal_contentrequiredinteger
organizationsrequiredinteger
usersrequiredinteger
modelsrequiredmap<string, integer>

The requests a provider served, by the model they asked for.

providersrequiredmap<string, integer>

The requests a provider served, by that provider.

SignalState

"open" | "dismissed" | "actioned"

Signal

objectrequired"signal"
idrequiredSignalId
kindrequiredstring

What was observed, such as injection_attempts, illegal_content, secret_probing, shared_template, topic_variety (far more conversations in an hour than the app's users hold) or shim_shape (requests whose parameters and client software the app's own traffic doesn't have, as an OpenAI-compatible shim's).

organizationrequiredRef | null
userrequiredRef | null
scorerequirednumber
windowrequiredobject

Fields

fromrequiredTimestamp
torequiredTimestamp
evidencerequiredobject

Fields

requestsrequiredRequestId[]
featuresrequiredmap<string, number>
staterequiredSignalState
created_atrequiredTimestamp
updated_atrequiredTimestamp

EventType

"organization.created" | "organization.updated" | "organization.deleted" | "user.created" | "user.updated" | "system_prompt.created" | "system_prompt.deleted" | "user.suspended" | "user.unsuspended" | "organization.suspended" | "organization.unsuspended" | "signal.detected" | "policy.created" | "policy.updated" | "policy.deleted" | "connection.created" | "connection.updated" | "connection.deleted" | "api_key.created" | "api_key.updated" | "api_key.revoked" | "webhook_endpoint.disabled" | "webhook_endpoint.test" | "request.blocked" | "request.cut" | "request.content_read" | "limit.threshold_crossed" | "replay.completed" | "replay.failed" | "evidence_pack.completed" | "evidence_pack.failed" | "assessment.completed" | "assessment.failed"

Event

objectrequired"event"
idrequiredEventId
eventrequiredEventType
datarequiredobject

The object the event is about, as it was then.

actorrequiredActor | null

Who caused it, or null when traffic did.

environment_idrequiredEnvironmentId
created_atrequiredTimestamp

LimitThreshold

objectrequired"limit_threshold"
limitrequiredobject

Fields

kindrequired"requests" | "tokens" | "spend"
perrequiredLimitScope
periodrequired"minute" | "day" | "week" | "month"
amountrequiredstring

As a decimal string for every kind.

organizationrequiredRef | null
userrequiredRef | null
thresholdrequired80 | 95 | 100

The percentage crossed; 100 when the limit starts refusing.

usedrequiredstring
resets_atrequiredTimestamp

WebhookEndpointState

"enabled" | "disabled"

WebhookEndpoint

objectrequired"webhook_endpoint"
idrequiredWebhookEndpointId
urlrequiredstring (uri)
eventsrequiredEventType[]

The events it receives; empty for all of them.

staterequiredWebhookEndpointState
disabled_reasonrequired"deliveries_failing" | "disabled_by_team" | null
created_atrequiredTimestamp
updated_atrequiredTimestamp

WebhookEndpointCreate

urlrequiredstring (uri)
eventsEventType[]

The events it receives; empty for every event, including types added later. webhook_endpoint.test goes only to the endpoint tested, so it can't be listed.

DeliveryState

"pending" | "succeeded" | "failed"

Delivery

One event sent to one endpoint. It is tried at once, then after 1 minute, 10 minutes, 1 hour and 12 hours; after the fifth failure it has failed, and the endpoint is disabled.

objectrequired"delivery"
idrequiredDeliveryId
webhook_endpoint_idrequiredWebhookEndpointId
event_idrequiredEventId
eventrequiredEventType
staterequiredDeliveryState
attemptsrequiredobject[]

Each item

atrequiredTimestamp
statusrequiredinteger | null
duration_msrequirednumber
errorrequiredstring | null

Such as timeout, connection_refused or tls_error.

next_attempt_atrequiredstring (date-time) | null
created_atrequiredTimestamp

JobState

"queued" | "running" | "completed" | "failed"

Replay

objectrequired"replay"
idrequiredReplayId
staterequiredJobState
policyrequiredobject

The draft that was replayed.

Fields

policy_idPolicyId | null
matchrequiredMatch
settingsrequiredSettings
fromrequiredTimestamp
torequiredTimestamp
progressrequirednumber
resultrequiredobject | null

What would have changed. Null until completed.

errorrequiredstring | null
created_byrequiredActor
created_atrequiredTimestamp
completed_atrequiredstring (date-time) | null

EvidencePack

objectrequired"evidence_pack"
idrequiredEvidencePackId
staterequiredJobState
organization_idrequiredOrganizationId
fromrequiredTimestamp
torequiredTimestamp
errorrequiredstring | null
created_byrequiredActor
created_atrequiredTimestamp
completed_atrequiredstring (date-time) | null
expires_atrequiredstring (date-time) | null

When the files are deleted, per the organization's retention.

Assessment

objectrequired"assessment"
idrequiredAssessmentId
namerequiredstring
staterequired"awaiting_upload" | "queued" | "running" | "completed" | "failed"
formatrequiredAssessmentFormat
uploadrequiredobject | null

Where to upload the logs, while the assessment awaits them.

progressrequiredobject | null

Where the assessment is while it is queued or running, as of its last checkpoint: null until it has read its first part of the upload, and once it ends.

errorrequiredstring | null
created_byrequiredActor
created_atrequiredTimestamp
completed_atrequiredstring (date-time) | null

AssessmentFormat

The provider formats are one request per line, with its response, in the provider's own format, wrapped with timestamp, user, organization and plan (and model for Gemini, whose request leaves it out). bedrock_invocation_logs_jsonl is Bedrock's model invocation logs as Bedrock writes them, the user, organization and plan taken from each invocation's requestMetadata (user, organization, plan), or the user from an Anthropic body's metadata.user_id. An upload is at most 5 GiB. The metadata formats carry no prompts: each row is timestamp, user, organization, plan, model, input_tokens, output_tokens, ip_hash and system_prompt_hash, as a JSON object per line or as CSV under a header line naming the columns. timestamp, user and model are required. The hashes can be any stable hash the prospect chooses. Signals that read what users wrote (shared templates, prompt injection, secrets) are reported as unavailable for a metadata assessment.

"openai_chat_jsonl" | "openai_responses_jsonl" | "anthropic_messages_jsonl" | "gemini_generate_content_jsonl" | "bedrock_invocation_logs_jsonl" | "metadata_jsonl" | "metadata_csv"

AssessmentReport

A completed assessment's report (J5.3): the users analyzed, the suspicious ones and their share of tokens, the cost estimated at list prices, and the most suspicious users, each signal naming lines of the upload behind it.

objectrequired"assessment_report"
assessment_idrequiredAssessmentId
namerequiredstring
formatrequiredAssessmentFormat
fromrequiredstring (date-time) | null

The earliest accepted row's time, or null when no row was accepted.

torequiredstring (date-time) | null

The latest accepted row's time, or null when no row was accepted.

generated_atrequiredTimestamp
rowsrequiredobject

Fields

readrequiredinteger

Lines that weren't blank.

acceptedrequiredinteger
rejectedrequiredmap<string, integer>

Rows rejected, by why.

users_analyzedrequiredinteger
suspicious_usersrequiredinteger
tokensrequiredobject

Fields

totalrequiredinteger
suspiciousrequiredinteger
suspicious_token_sharerequirednumber
estimated_costrequiredobject

In US dollars, at list prices.

Fields

totalrequiredDecimal
suspiciousrequiredDecimal
usersrequiredobject[]

The most suspicious users, most suspicious first.

Each item

userrequiredstring

The user's id as the upload names it.

organizationrequiredstring | null
planrequiredstring | null
scorerequirednumber
requestsrequiredinteger
tokensrequiredinteger
estimated_costrequiredDecimal
signalsrequiredobject[]

Each item

kindrequiredstring

As a signal's kind, such as shared_template.

scorerequirednumber
linesrequiredinteger[]

Lines of the upload behind the signal.

unavailable_signalsrequiredstring[]

Signals the assessment couldn't look for: those that read what users wrote, for a metadata assessment. Empty for the provider formats.

Role

"admin" | "developer" | "viewer"

TeamUpdate

namestring

Member

objectrequired"member"
idrequiredMemberId
emailrequiredstring (email)
namerequiredstring | null
rolerequiredRole
staterequired"invited" | "active"
created_atrequiredTimestamp
updated_atrequiredTimestamp

MemberUpdate

rolerequiredRole

InvitationCreate

emailrequiredstring (email)
rolerequiredRole

ProjectCreate

namerequiredstring

ProjectUpdate

namestring

Environment

objectrequired"environment"
idrequiredEnvironmentId
project_idrequiredProjectId
namerequiredstring
regionrequiredRegion
productionrequiredboolean

Production environments' keys say live; the rest say test.

api_base_urlrequiredstring
gateway_base_urlrequiredstring
created_atrequiredTimestamp
updated_atrequiredTimestamp

EnvironmentCreate

project_idrequiredProjectId
namerequiredstring
regionrequiredRegion
productionrequiredboolean

EnvironmentUpdate

namestring