Työäly Gate · API reference

One request before an action. One decision back.

Updated 3 October 2026 · Everything under /v1 only gains fields · About Gate

The decision layer for AI agents. An agent sends what it intends to do, or the text and data it has about it, and Gate answers allow, review, deny or more_information with a confidence, reason codes, risk scores, what is missing, and an audit id. Gate never executes anything.

The machine-readable contract is docs/openapi.json (OpenAPI 3.1, generated from the code by python -m gate.cli openapi). Everything under /v1 only gains fields: a client written today keeps working.

Base URL and authentication

https://api.tyoaly.com
Authorization: Bearer tyo_test_…      # decides on your test environment
Authorization: Bearer tyo_live_…      # decides on your live environment

A key belongs to one organisation and one environment. Keys are shown once, when created, in the console or by Työäly; a revoked key answers 401 from the next request on.

One decision: POST /v1/gate/evaluate

The version-1 request: the action, who proposes it, and the context the agent has.

{
  "action":  {"type": "refund", "amount": 649, "currency": "EUR", "target": "order_8812"},
  "actor":   {"type": "ai_agent", "name": "support-agent"},
  "context": {"customer_tier": "business", "ticket": "Customer asks for a refund of a double charge."},
  "options": {"language": "auto", "mode": "standard"}
}
Field
action.type required lower case, ^[a-z][a-z0-9_.:-]{0,63}$, in your own vocabulary; the registry of known types (refund, cancel_subscription, send_message, modify_configuration, transfer, delete_records, …) gives Gate's rules something to hold on to
action.amount, action.currency optional the amount moved, ISO 4217 code; an action that moves money without an amount is answered more_information
action.target optional the record the action is about, up to 256 characters
action.description, action.parameters optional free text up to 2,000 characters; any object
actor.type ai_agent (default), human, system
actor.name required the agent's name, 1 to 128 characters; on an environment with registered agents it must be one of them
actor.permissions optional what the agent declares it may do; a declaration, not authorisation: on an environment with registered agents the stored list decides
context optional any JSON, or a string: what the agent knows; it reaches the decision model as prepared evidence
options.language optional auto (default) or a language code

The answer, always the same shape:

{
  "decision_id": "dec_0192f3…",
  "decision": "allow",
  "confidence": 0.91,
  "reason_codes": [],
  "missing": [],
  "missing_details": [],
  "risk": {"financial": 0.12, "fraud": 0.03, "data_loss": 0.0, "security": 0.01, "overall": 0.12},
  "semantic": {"evidence_supports_action": 0.93, "action_reversible": 0.88, "human_review_required": 0.06,
               "fraud_indicators": 0.03, "data_exfiltration_risk": 0.01, "data_loss_risk": 0.0,
               "financial_impact": 0.12, "blast_radius": 0.08},
  "policy_results": [{"policy": "high-value-refund", "matched": false, "effect": "review", "reason_code": "HIGH_VALUE_REFUND"}],
  "policy_version": "v1",
  "language": "en",
  "providers": {"decision": "jev"},
  "latency_ms": 412,
  "created_at": "2026-10-03T09:14:02.118Z",
  "action": {"type": "refund", "identified": true, "confidence": 1.0},
  "intake": {"path": "structured", "version": "v1", "input_quality": {}, "contradictions": []},
  "review": null
}
Field Meaning
decision allow: the agent may proceed. review: a person decides. deny: do not do it. more_information: fetch what missing names and ask again
confidence the decision model's own concentration, 0 to 1; deterministic answers (a cap, a permission, a missing amount) carry 1.0
reason_codes why, as stable codes (table below); empty on a plain allow
missing, missing_details the request fields a rule found absent, as paths (action.amount) and with the reason each is needed; supply them and ask again
risk financial, fraud, data_loss, security and their overall maximum, 0 to 1
semantic the model's answers to the eight questions, 0 to 1; public names that change only with a version
policy_results every rule that ran, matched or not, with its effect and reason code
providers which models answered: decision, and intake on the intake path
action, intake how Gate read the proposal: the type and its confidence, the path (structured or intake), input quality, contradictions found
review the person's verdict, once given (GET only): approved, denied or changed, by whom, when

Facts are computed in code and judgment comes from the model: amounts, limits, permissions, caps and registered agents are never left to a model; the model answers only semantic questions about the prepared evidence. Any provider failure, timeout or unreadable answer is review with PROVIDER_UNAVAILABLE, never allow.

Reason codes

Code From Meaning
ACTION_NOT_PERMITTED rule, deny the actor declared permissions and the action type is not among them
AGENT_UNKNOWN rule, deny the environment enforces registered agents and this actor is not one
AGENT_NOT_PERMITTED rule, deny the registered agent may not propose this action type
RATE_LIMITED rule, review the environment reached its daily decision cap; no model was called
COST_CAP_REACHED rule, review the environment reached its monthly provider cost cap; no model was called
EVIDENCE_TOO_LARGE rule, review the context is too large to judge
MISSING_AMOUNT rule, more information an action that moves money has no amount
HIGH_VALUE_REFUND rule, review a refund above the limit, or whose sum had to be selected among competing candidates
DESTRUCTIVE_ACTION_TYPE, SENSITIVE_ACTION_TYPE, EXFILTRATION_ACTION_TYPE rule, at least review the action type itself: deletes records, changes bank details or access, moves data out
IRREVERSIBLE_HIGH_IMPACT rule on the answers, review hard to undo and wide in effect
FRAUD_INDICATORS, DATA_EXFILTRATION, DATA_LOSS_RISK rule on the answers the model sees signs of fraud, data leaving its boundary, or data loss
EVIDENCE_INSUFFICIENT rule on the answers, review the evidence does not support the action
HUMAN_REVIEW_REQUIRED rule on the answers, review the model says a person should look
LOW_CONFIDENCE rule on the answers, review the model's confidence below the environment's threshold
HUMAN_REVIEW_RECOMMENDED, REJECT_RECOMMENDED, MORE_INFORMATION_NEEDED the model's handling choice what the model would do with it
LOW_CONFIDENCE_REJECT policy version 2 the model rejected with low confidence, so a person decides instead
PROVIDER_UNAVAILABLE fail closed the decision model did not answer in time or at all
INTAKE_UNAVAILABLE, MISSING_ACTION_TYPE, MISSING_ACTOR, MISSING_TARGET, UNREGISTERED_ACTION, CONTRADICTORY_INPUT, INJECTION_SUSPECTED Intake what Gate could not read in text or arbitrary JSON, a type outside the registry (never allowed automatically), contradictions, text that instructs the evaluator

Idempotency

Send Idempotency-Key: <1 to 128 characters>. The same key with the same body returns the same decision for 24 hours; the same key with a different body is refused with 409.

Text and arbitrary JSON

When Työäly has switched Intake on for your environment, the same endpoint takes Content-Type: text/plain with the text as the body, or application/json with any object or array. Gate finds the proposal in it: candidates for the action, the amount and the target are extracted by code, the decision model only selects among them, and what cannot be found is asked for in missing. Unknown stays unknown: nothing is ever invented. Hints travel as headers, each at most 128 characters:

Header Hint
X-Tyoaly-Agent the agent that proposes, when the input does not say
X-Tyoaly-Action-Hint the action type meant
X-Tyoaly-Resource-Hint the record the action is about
X-Tyoaly-Language-Hint the language of the text

A version-1 request never costs an intake model call; clean structured input takes the structured path unchanged.

The record: GET /v1/decisions/{decision_id}

The decision as it was answered, from your own organisation only, with review filled in once a person has given a verdict. Records are kept 13 months; the content of a decision is kept under the retention mode of the environment (full 30 days, redacted, metadata, zero) and never in the record itself.

The verdict: POST /v1/decisions/{decision_id}/review

{"outcome": "approved", "reviewer": "anna@company.fi", "note": "sent as proposed"}

approved: the person carried the action out. denied: refused it. changed: did something else. The latest review of a decision is the one kept. This is advisory mode's ground truth from an integration that knows what happened; people without one answer the daily digest mail or the console, and all three land in the same agreement report.

Errors

{"error": "invalid_api_key", "message": "The API key is not valid"}
Status error
401 missing_api_key, invalid_api_key
404 decision_not_found, not_found
409 idempotency_conflict same key, different body
413 request_too_large the body above 256 KB, a review above 16 KB
415 unsupported_media_type a media type Gate does not read
422 invalid_request, invalid_idempotency_key with details naming the fields
429 throttled at the gateway; retry with backoff
503 store_unavailable Gate could not record the decision; nothing unrecorded is answered

Limits and caps

Body 256 KB
Provider time 1.5 s per model call; slower is review with PROVIDER_UNAVAILABLE
Daily decisions per environment, default 10,000; above it review with RATE_LIMITED
Monthly provider cost per environment, $2 test and $20 live by default; above it review with COST_CAP_REACHED

Example

curl -sS https://api.tyoaly.com/v1/gate/evaluate \
  -H "Authorization: Bearer $GATE_KEY" -H "Content-Type: application/json" \
  -d '{"action": {"type": "refund", "amount": 49, "currency": "EUR", "target": "order_8812"},
       "actor": {"type": "ai_agent", "name": "support-agent"},
       "context": {"ticket": "Customer asks for a refund of a double charge."}}'
curl -sS https://api.tyoaly.com/v1/gate/evaluate \
  -H "Authorization: Bearer $GATE_KEY" -H "Content-Type: text/plain" \
  -H "X-Tyoaly-Agent: support-agent" \
  --data-binary 'Please refund order 8812, 49 euros, the customer was charged twice.'