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
| Scope | Reaches | Held by |
|---|---|---|
evaluate | The data plane: input, action, response, connector execution | Your running agent |
manage | Your own tenant configuration, where you author AOPs | A tenant configuring by API |
admin | The administrative surface and the admin per tenant variants | The 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.
| Capability | Admin per tenant endpoint |
|---|---|
| Tenant settings, including the three service switches | PUT /v1/admin/tenants/{id} |
| Notification toggles and recipients | PUT /v1/admin/tenants/{id}/notifications |
| Shadow mode | PUT /v1/admin/tenants/{id}/shadow-mode |
| Rate limit | PUT /v1/admin/tenants/{id}/rate-limit |
| Input gate daily cap | PUT /v1/admin/tenants/{id}/gate-cap |
| Response model daily cap | PUT /v1/admin/tenants/{id}/output-cap |
| Response AOPs, the source of truth and rules | GET 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, platform | POST /v1/admin/tenants/{id}/provision-key |
| Usage for one tenant | GET /v1/admin/tenants/{id}/usage |
Platform wide admin
| Capability | Endpoint |
|---|---|
| AOP pack catalog and versioning | GET and POST /v1/admin/packs, POST /v1/admin/packs/{name}/versions |
| Activation funnel across tenants | GET /v1/admin/funnel |
| Usage summary across tenants | GET /v1/admin/usage |
| Purge expired personal data | POST /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.