Selah

Reference

API reference

Every endpoint an integration uses, with examples. All calls go to https://api.selahcore.com and authenticate with the X-API-Key header. The live schema at https://api.selahcore.com/openapi.json is authoritative for exact shapes and status codes.

What the engine enforces at each moment is a set of AOPs, your Agent Operating Procedures. Configuring a tenant is authoring its AOPs. If those terms are new, read Agent Operating Procedures and the Shadow AOP Ledger first.

Scopes

ScopeReachesHeld by
evaluateThe data plane: input, action, response, connector executionYour running agent
manageYour own tenant configuration, where you author AOPsA tenant configuring by API
adminThe administrative surface and the admin per tenant variantsThe platform and the dashboard proxy

The tenant is resolved from the key, never from the body.

The verdicts

Every check returns one of three, and they share the same rails: permit proceeds, hold needs a human, deny stops. For the input and response checks the verdict is returned as allow, escalate, or block, which map to permit, hold, and deny.

Data plane

Input check

POST /v1/gate/check, scope evaluate. Deterministic pre filter plus a light model check. Fail open.

// request
{ "agent_id": "agent_01", "text": "incoming message", "context": { "thread_id": "th_1" } }
// response
{ "decision": "allow", "reason": null, "shadow": false }

Action check

POST /v1/evaluate, scope evaluate. Fully deterministic AOP resolution, no model, returns in well under ten milliseconds. Fail closed.

// request
{
  "agent_id": "agent_01",
  "action": "process_refund",
  "parameters": { "amount": 4200, "currency": "USD", "order_id": "A-7781" },
  "context": { "idempotency_key": "evt_4f3a", "user_ref": "cust_991" }
}
// response
{ "decision": "hold", "reason": "amount exceeds AOP limit", "decision_id": "dec_01H", "shadow": false }

A permit returns a decision_id that a connector requires to execute.

Response check

POST /v1/validate/output, scope evaluate. Deterministic hard rules from your response AOPs, then a model layer for grounding, tone, and topic. Hard rules fail closed, the model layer fails open. Send the conversation thread in context so the model layer can judge grounding.

// request
{
  "agent_id": "agent_01",
  "response_text": "Sure, I can give you 30% off and free delivery.",
  "context": { "thread": [ {"role":"user","text":"any discount?"} ] }
}
// response
{ "decision": "block", "reason": "discount not in catalog", "rule_id": "no_offcatalog_discount", "flagged": true, "shadow": false }

A block or escalate always sends notification email to the tenant recipients and operators, subject to the tenant notification toggles.

Connector execution

POST /v1/connectors/{connector_id}/execute, scope evaluate. Fail closed. Executes a permitted action server side with stored credentials the agent never sees.

// request
{ "decision_id": "dec_01H", "payload": { "order_id": "A-7781", "amount": 4200 } }

Behavior: the engine verifies the decision exists for your tenant, is a permit or approved hold, and matches the action. Otherwise it refuses with no outbound call. A repeat with the same idempotency key returns the prior result and does not fire twice.

Tenant configuration: authoring AOPs

These exist as tenant scoped routes for direct integration with a manage key, and as admin per tenant variants for the dashboard with an admin key. From the dashboard, always use the admin per tenant variant, because the proxy holds the admin key and tenant scoped routes reject it.

CapabilityAdmin per tenant endpoint
Tenant settings, including the three service switchesPUT /v1/admin/tenants/{id}
Notification toggles and recipientsPUT /v1/admin/tenants/{id}/notifications
Shadow modePUT /v1/admin/tenants/{id}/shadow-mode
Rate limitPUT /v1/admin/tenants/{id}/rate-limit
Input gate daily capPUT /v1/admin/tenants/{id}/gate-cap
Response model daily capPUT /v1/admin/tenants/{id}/output-cap
Response AOPs, the source of truth and rulesGET and PUT /v1/admin/tenants/{id}/output-config
Agents, verticals, compliance enablement/v1/admin/tenants/{id}/agents, /verticals, /compliance/enable, /enabled
AOP packs enable and disable/v1/admin/tenants/{id}/packs, .../packs/enable, .../packs/disable
Sub tenant provisioning key, platformPOST /v1/admin/tenants/{id}/provision-key
Usage for one tenantGET /v1/admin/tenants/{id}/usage

Platform wide admin

CapabilityEndpoint
AOP pack catalog and versioningGET and POST /v1/admin/packs, POST /v1/admin/packs/{name}/versions
Activation funnel across tenantsGET /v1/admin/funnel
Usage summary across tenantsGET /v1/admin/usage
Purge expired personal dataPOST /v1/admin/pii/purge

Caps, switches, idempotency

  • Service switches. Each of the three checks can be off per tenant. A call to a disabled service passes through silently, is recorded under a distinct label, consumes no cap, and triggers at most one daily summary email reporting how many requests hit the disabled service.
  • Caps. The input check and the response model layer each have a per tenant daily cap. Over the cap the model work is skipped and the check fails open, recorded.
  • Shadow mode. Per tenant. Decisions are computed and recorded with a shadow flag, forming the Shadow AOP Ledger, but the returned verdict does not block.
  • Idempotency. Carry an idempotency key in the action context. It deduplicates connector execution so a retry never double acts.

Errors

Authentication failures return an unauthorized status. A tenant scoped route called with the admin key returns unauthorized by design; use the admin per tenant variant. The deterministic checks are built not to fail the request path; the model layers fail open and record the reason. Connector execution refuses cleanly and records when a permit is missing or invalid, rather than acting.