Tool reference
Every tool Ogen's MCP server registers: what it takes, what comes back, who may call it.
Contract version
Every tool result carries _meta.contract, a date such as 2026-09-04. It changes only when a tool's inputs or the fields it returns change, and this section lists what moved. Your agent can compare it to the date it was built against and stop, rather than misread a result.
| Contract | What changed |
|---|---|
2026-09-04 | First dated contract: 16 tools, six source kinds, commit_gated_action results carry disposition and reason. |
2026-09-04 | Same day, five more: approver-bound sign-in links (a routable approver's release requires the one-time email link, never a typed name); a duplicate hold returns the existing confirm_url/action_id with duplicate_of set; reason: "out_of_scope" on a scoped key reaching outside its own prefixes; a new GET /v1/activity; and self-serve DELETE /v1/tenant / POST /v1/tenant/undelete. commit_gated_action's approver field is now always a string, never omitted. |
2026-09-05 | + set_connection, list_connections, remove_connection (23 tools); bind_source accepts source.connection; held results carry approver_status and notified_reason; keys carry role; a viewer key's writes are refused with a plain message. |
2026-09-05 | + discover_fields (20 tools): see what a bound source exposes — field names and types, never values — plus suggested key names. + three source kinds: salesforce, netsuite, postgres (direct read-only SQL). |
2026-09-05 | Three more tools, 19 total: explain_hold (everything about one held action, plus a null-templated fix_proposal) and list_holds (a tenant's holds, newest first, capped at 100 — also GET /v1/holds). A new POST /v1/holds/decide batch-decides a list of hold ids, each decided on its own exactly as a single decide would be. Later the same day: set_assist (Ogen Assist, opt-in, your own model key); commit_gated_action results that hold now carry assist, and explain_hold / list_holds entries carry assist: { status, draft }. Additive only — a caller built against the morning's shape reads these results unchanged. |
2026-09-05 | + one more source kind: priority (Priority ERP over its own OData REST interface). set_connection/bind_source's connection shortcut now also covers it — see Set up Priority. |
2026-09-05 | + recall_live_facts (21 tools): read up to 25 keys in one call, each answered exactly as recall_live_fact would — independently, so one unresolved key never changes another's answer. Returns { results: [{ key, ...same shape as recall_live_fact }], as_of }. |
2026-09-08 | Two fields in what_it_caught (and GET /v1/proof) renamed to say what they count: one is now set_aside, and floats_released is now later_released. The old names are no longer returned. Every other field is unchanged, and so are the numbers themselves — nothing already counted stopped being counted. This is the one change so far that is not additive: a caller reading either old name by hand needs the new one. |
2026-09-24 | commit_gated_action results that hold now carry elicited and answers_count: whether your MCP client was asked, through elicitation, for answers to Ogen Assist's questions (local mode only; the hosted pods always say "skipped"), and how many were attached to the hold. An answer never decides the hold. Additive only — a caller built against the earlier shape reads these results unchanged. |
2026-09-25 | The release ticket. commit_gated_action takes an optional args object (only its SHA-256 is kept) and, once a person confirmed, answers disposition: "released" with a release_ticket. explain_hold / list_holds entries carry release_ticket while it is valid, then outcome, outcome_reference and outcome_reported_at; previous_hold gains previous_outcome. + report_outcome (26 tools). See the release ticket. |
2026-09-26 | 26 tools become 18. Four grouped tools take a required action: settings ("mode", "contact", "evidence", "assist" — was set_mode, set_contact, set_evidence, set_assist), connections ("set", "list", "remove" — was set_connection, list_connections, remove_connection), webhook ("set", "remove" — was register_webhook, remove_webhook) and reverse ("reverse", "restore" — was reverse_action, restore_fix). recall_live_fact takes keys for what recall_live_facts did. Every action keeps its old tool's inputs, role and plan. The old names are refused with one sentence naming the replacement. Not additive: a caller using an old name needs the new call. |
2026-09-30 | + settings action "door": an opt-in public page at <pod>/door/<slug> naming a tenant's registered action kinds, for a visiting agent that wants to know what it may ask before it asks it. Additive only. |
Tools
All 18. Eight are what an agent calls day to day; the other ten operate your tenant. Every call authenticates with the bearer key (or signed-in session) from your client config.
Live reads, no cache
Ogen never caches a value: every recall reads the source when your agent asks, and as_of says when. If your own code keeps a recall and acts on it later, the gap between as_of and the act is yours, and Ogen can't see it. So act from the recall you just made, and when a source is slow, register the act with register_action: commit_gated_action then goes by the fact as it stands when it runs.
The eight tools that are the product
Most agents use four of these: recall a fact, and act on it — commit_gated_action decides whether that is safe right now, on the spot or through a hold a named person releases. register_action and register_approver set that up once, so commit_gated_action knows what to check and who to ask. list_holds and explain_hold show what is waiting and why. teach_fix records a person’s correction so nobody is asked the same thing twice, and export_evidence hands over the read history that proves it happened. Eight tools, one flow — everything past this section runs your tenant, not your agent’s day.
recall_live_factFree · RecordReads the live value bound to a key — or up to 25 keys in one call — nothing is cached as truth.
Inputs, results and an exampleInputs
| Field | Type | Description |
|---|---|---|
key | string | One bound key to recall, e.g. customer.acme.address. |
keys | string[], instead of key | 1 to 25 bound keys, e.g. ["customer.acme.address", "order.42.status"]. Duplicates are read once. |
Give key or keys, never both.
Comes back
- resolved — the current value, as of the moment you asked.
- ambiguous — every live candidate that disagrees, never a pick.
- unavailable — nothing is bound for that key, or the source couldn't be reached.
With keys (until 2026-09-26, the separate recall_live_facts): { results: [{ key, ...the same shape }], as_of } — one entry per deduped key, in the order you asked, each answered independently, so one unresolved key never changes another's answer and one bad key never fails the batch.
Example
{ "status": "ambiguous", "candidates": [
{ "value": "12 Main St, Springfield", "confidence": 0.5 },
{ "value": "88 Industrial Ave, Springfield", "confidence": 0.5 }
], "guidance": "Two or more live sources disagree. Do not choose one or state any as the answer — this waits for a person." }
commit_gated_actionFree (demo kinds) · Record (any registered kind)Ask whether an action of this kind is authorized. It is authorized only when the fact is settled; otherwise it waits for a person, and it never guesses. An unregistered kind is refused. Ogen never performs the action itself — your own system does that, once this says yes.
Inputs, results and an exampleInputs
| Field | Type | Description |
|---|---|---|
kind | string | An action kind, e.g. one registered with register_action, or a free-tier demo kind. |
args | object, optional | The arguments you will run the action with. Ogen keeps only their fingerprint, for the release ticket a confirmation issues; they never choose the fact the action depends on. |
principal | { email }, optional | The person the agent is acting FOR — required when the kind's approver is the reserved word "principal", refused on any other kind. Nothing but the address. See The person the agent acts for. |
Comes back
{ committed, disposition, action_id, reason, guidance, confirm_url, notified, approver, webhook, mode }.
A result that holds also carries assist, elicited ("accepted" | "declined" |
"cancelled" | "unavailable" | "skipped" — whether your client was asked for answers
to Assist's questions, see Ogen Assist) and answers_count (how many were attached to the hold; never the answers).
committed is true only when disposition is "ran" — every other
disposition also carries a reason from a small closed set, so you can branch on it instead of
parsing guidance. mode ("gate" | "observe") is on every
result, so you can always tell which mode answered without a separate call. What each combination means,
and what to do next:
| Disposition | Reason | Means | Do next |
|---|---|---|---|
ran | — | Authorized against a settled fact. Nothing ran here — Ogen never performs the action. | Go ahead and perform it in your own system. |
drafted | cost_needs_person | The fact is resolved; the action is prepared but a person has to release it. | Wait, or point the person at confirm_url. |
held | cost_needs_person | The fact is resolved; this kind of action always waits for a named person. | Wait for the named approver, or point anyone at confirm_url. |
held | not_registered | Refused: no fact is registered for this kind at all, so nothing is held, nobody is asked and there is no confirm_url. | Register it with register_action, then retry. |
held | not_entitled | The kind is registered, but this key's tenant isn't entitled to run it right now (trial ended, or a paid year lapsed). | Start a free Record trial (POST /api/trial) or continue with Record (POST /api/checkout). |
held | too_many_open | Five actions of this kind are already waiting for a person, each asked with different arguments. Nothing new was held and nobody was emailed; oldest_open and confirm_url point at the oldest. | Wait for one to be decided or to expire, then ask again. |
escalated | fact_unresolved | The fact this action depends on is ambiguous or unavailable. It waits until the fact settles, then goes the way a settled fact would — to the named person if the kind needs one. | Resolve the fact (or wait for it to settle), or point a person at confirm_url. |
released | person_confirmed | A person already confirmed this kind and fact, and its release ticket is still valid. Nothing ran and nothing new was held. | Give release_ticket to the system that runs the action, then report_outcome. |
observed | observe_mode | Shadow mode is on: nothing fired and nothing was held, this call was only counted. See would_have. | Read would_have: "ran" | "held" to see what gate mode would have done; switch back with settings (action "mode") when ready. |
held | principal_required | This kind's approver is the reserved word "principal", and this ask carried no principal. Nothing was held. | Ask again with principal: { email } naming who the agent acts for. |
held | principal_not_gated | This ask carried a principal, but the kind's approver isn't "principal". Nothing was held. | Drop principal, or register the kind with approver: "principal" first. |
Example
{
"committed": false,
"disposition": "held",
"action_id": "act_9f2c1a",
"reason": "cost_needs_person",
"guidance": "The action was HELD for a named human's approval and did NOT fire. Do not perform it yourself.",
"confirm_url": "https://ogenhq.com/confirm/c_7b3e",
"notified": true,
"approver": "Dana",
"webhook": "sent",
"mode": "gate"
}
register_actionRecordTell Ogen which fact an action kind depends on, and how costly that action is to undo. Actions that are costly to undo wait for a person — and a kind that waits for a person has to name one.
Inputs, results and an exampleA kind that needs a person names one. Any cost other than read must carry an approver the tenant already registered with register_approver; without one the call is refused and says so. Kinds registered before this rule keep working unchanged.
Requires an owner key or a signed-in person. A plain operator key is refused with "this key is an operator; ask an owner, or sign in" — see Roles.
The person a hold is waiting on can be changed while the hold is open. Re-register the kind with a different registered approver and every hold still waiting on it is handed to that person instead: they get the link, and any sign-in link the previous approver was holding stops working. cost and key can't change while a hold is open.
Inputs
| Field | Type | Description |
|---|---|---|
kind | string | The action kind commit_gated_action will be called with. |
key | string | The bound key this kind depends on. |
cost | read | reversible | expensive | How costly this kind of action is to undo. The costlier it is to undo, the more a person is involved before it happens. |
approver | string | The name of the person who confirms a hold on this kind (see register_approver) — or the reserved word "principal", which waits for whoever commit_gated_action's own ask names instead (see The person the agent acts for). Required for any cost other than read, and for decide_with "passkey_only" (which a principal-gated kind can never use — a principal has no passkey). Omit it when re-registering and whoever is already named stays named; null clears it, which only a read kind with decide_with "token_or_passkey" may do. |
decide_with | token_or_passkey | passkey_only, optional | Which door may decide this kind's holds — a mailed one-time token or a passkey (the default), or a passkey only. Omit on a re-registration and whatever is already set stays set. |
hold_ttl_hours | integer 1–168, optional | How long a hold on this kind waits for a person. Default 24. Each hold's deadline is fixed when it's created; changing this never moves a hold already waiting. A longer window is a longer time for the fact to move — and the decision still goes by the fact as it stands when it runs. |
hold_ttl_skip_weekends | boolean, optional | Count only working days, in your timezone (settings, action "contact"), toward hold_ttl_hours. With the default Saturday–Sunday weekend, a payment held Friday 18:00 with 24 hours lapses Monday 18:00 instead of Saturday 18:00; the same action's weekend can make it Friday and Saturday instead. The reminder and the hand-over fall at 80% and 50% of the same working time, so a weekend never pulls them forward. Default false. Refused until the account has a timezone, and when that timezone is one Ogen doesn't know. |
fallback_approver | string, optional | A second registered person who is handed a hold on this kind once half its life has passed with no decision (What happens to a hold). Needs an approver, must be someone else, and must already be registered. Omit on a re-registration and whoever is set stays set; null clears it. |
release_when | object, optional | Release this kind without a person when its OWN bound fact resolves and satisfies the rule — exactly one of { fact_equals: "<string>" } or { fact_at_least: "<argument name>" } (see Release without a person — your own fact). Only on a cost expensive kind; never with decide_with passkey_only. Owner key only. Omit on a re-registration and whatever is set stays set; null clears it. |
Comes back
A confirmation that the kind is registered, with the key, cost and door it now maps to.
Example
Registered "email-globex" -> "customer.globex.address" (cost: reversible, decide_with: token_or_passkey). commit_gated_action will honor it from now on.
register_approverRecordTell Ogen where to reach a person by name, so a held action can be sent to them.
Inputs, results and an exampleRequires an owner key or a signed-in person. A plain operator key is refused with "this key is an operator; ask an owner, or sign in" — see Roles.
Inputs
| Field | Type | Description |
|---|---|---|
name | string | The approver's name — must match a register_action approver value exactly. |
email | string (email) | The approver's email address. |
replace | boolean, optional | true to move an existing name to a different email. The old address is told, and any passkeys set up under this name stop working. |
revoke_passkeys | boolean, optional | true to turn off every passkey this approver set up — a lost device, a person leaving. They can set up a new one from their next emailed link. |
Comes back
A confirmation that this name now resolves to that address for held-action email — plus passkeys_revoked, a count, whenever passkeys were turned off.
Example
{ "registered": true }
list_holdsRecordThis tenant's held actions — open, decided, or both — newest first, up to 100 at a
time. The same fields explain_hold returns for one hold, for every hold at once. Also reachable
as GET /v1/holds with your bearer key, for your own tooling.
Inputs
| Field | Type | Description |
|---|---|---|
status | "open" | "decided", optional | Omit for both. |
limit | number, optional | Default and cap 100. |
include | "expired", optional | Also list holds that expired with nobody deciding. Left out by default, so “open” means still waiting. GET /v1/holds?include=expired does the same. |
Comes back
{ holds: [ …one entry per hold, same shape as explain_hold… ] }
explain_holdFree · RecordEverything about ONE held action, for a person or their assistant to look at: what it waited on, what each source said, and a fix template a person can complete. Ogen never chooses.
Inputs, results and an exampleInputs
| Field | Type | Description |
|---|---|---|
action_id | string | The action_id returned by commit_gated_action. |
Comes back
The hold's kind, key, current live state (a resolved value, or every candidate with the source
label it came from — never a credential, and unlike recall_live_fact no confidence number), held_since, the named
approver if any, decide_with (which door may decide this kind — "token_or_passkey"
or "passkey_only"), its confirm_url, and a fix_proposal: { tool: "teach_fix",
input: { key, raw, canonical: null, taught_by: null } }. canonical and
taught_by are always null — a person fills them in. A decided or expired hold says so, and adds
decided_via — "token" (the mailed sign-in link), "passkey", or
"name" (a typed name, no routable approver) — never the credential id.
Example
{
"found": true,
"status": "pending",
"kind": "send-refund",
"key": "order.42.status",
"held_since": "2026-09-05T01:02:03.000Z",
"approver": "none — anyone with the link can decide",
"decide_with": "token_or_passkey",
"confirm_url": "https://ogenhq.com/confirm/…",
"fact": { "status": "ambiguous", "candidates": [
{ "value": "shipped", "source_label": "orders.example.com" },
{ "value": "returned", "source_label": "orders.example.com" }
] },
"fix_proposal": {
"tool": "teach_fix",
"input": { "key": "order.42.status", "raw": null, "canonical": null, "taught_by": null },
"note": "A person fills in canonical and taught_by. Ogen does not pick."
}
}
teach_fixRecordRecord a person's correction, so nobody is asked the same thing twice.
Inputs, results and an exampleInputs
| Field | Type | Description |
|---|---|---|
key | string | The bound key this fix applies to. |
raw | string | The raw value that was wrong. |
canonical | string | What it actually means. |
taught_by | string | The named person recording this fix — required. |
Comes back
The rule that was recorded, with a rule_id you can later hand to reverse (action "restore").
Example
{ "recorded": true, "rule_id": "a1b2c3d4e5f6a7b8" }
export_evidenceRecordReturn your stored read fingerprints for offline verification against your own secret.
Inputs, results and an exampleInputs
| Field | Type | Description |
|---|---|---|
since | string (ISO timestamp), optional | Only rows at or after this time. |
Comes back
Up to 1,000 rows: key, when, its status, and a fingerprint — never a plaintext value.
Example
{ "rows": [
{ "key": "customer.acme.address", "at": "2026-09-01T10:03:00Z", "state": "ambiguous", "fingerprint": "9f2c1a4e..." }
] }
Operating your tenant
The other ten set your tenant up and keep it running: an operator calls each of these, usually once, before or around the agent’s own calls above. Four of them — connections, settings, webhook and reverse — take an action, and each action keeps its own role. Until 2026-09-26 those actions were eleven tools of their own; a call to one of the old names is refused with a sentence naming its replacement.
Sources & connections
An operator wires these once, before an agent ever asks a live question.
bind_sourceRecordBind a key to a live, read-only source: a plain JSON endpoint, or one of the named source kinds. Every recall reads it fresh — nothing is cached as truth.
Inputs, results and an exampleInputs
| Field | Type | Description |
|---|---|---|
key | string | The key to bind. |
url | string (https URL), optional | For a plain JSON endpoint. Omit when using source. |
headers | object, optional | Plain-endpoint only — sent exactly as given on every read. Stored encrypted at rest. |
source | object, optional | Instead of a plain endpoint — a named kind (postgrest, airtable, gsheets, hubspot, mcp) plus its own fields. See Sources. A named connection (connections) goes in source.connection. |
alongside | boolean, optional | Bind a second (up to four) live source to this key instead of replacing the one it already has — see Sources. Omit it (the default) and this call still replaces the key's one source, removing any other source already bound alongside it. |
Comes back
{ bound: true, key, kind, label } — label is a safe, non-secret identifier (a host, a base id, a sheet id, an object name), never a credential. With alongside: true, also { slot, systems: [...], note } — every system now bound to this key, and a line saying the fact will wait whenever they disagree.
Example
{ "bound": true, "key": "order.99.status", "kind": "http", "label": "example.com" }
discover_fieldsRecord · Free on the demo keysSee what a bound source exposes before you name a key against it. Reads that source live, once, and hands back the field names it found and their types — string, number, boolean, object, array — never the underlying values. A nested JSON source is walked into dotted paths (billing_address.street); a table-style source reports the configured column and how many records it saw. Up to ten ready-to-use key names are proposed from what it found. The same result is on your tenant page (a "Fields" button on every bound source) and at GET /v1/sources/<key>/fields.
Inputs
| Field | Type | Description |
|---|---|---|
key | string | A key already bound with bind_source, or one of the demo keys. |
Comes back
{ key, kind, sample_count, fields: [{ path, type }], suggested_keys: [...] } — or the same unavailable shape recall_live_fact uses. A key bound to more than one system (Sources, alongside: true) comes back as { key, systems: [{ system, kind, fields, ... }, ...] } instead — one entry per system, so one system being unreachable never hides what another exposes.
connectionsRecordStore a credential set once, under a name, for salesforce/netsuite/hubspot/airtable/postgrest/postgres/priority, so bind_source's source.connection names it instead of repeating it. Never echoes a credential back.
Actions
| action | Fields | Role | What it does, and what comes back |
|---|---|---|---|
"set" | name, kind ("salesforce" | "netsuite" | "hubspot" | "airtable" | "postgrest" | "postgres" | "priority"), plus that kind's own credential fields: instance_url/client_id/client_secret (salesforce), account_id/consumer_key/consumer_secret/token_id/token_secret (netsuite), token (hubspot), base_id+token (airtable), base_url+api_key (postgrest), connection_string (postgres), base_url+username+password (priority) | owner or signed-in | Stores it. The same name again rotates it: every key bound to it reads the new credentials on its next read. Returns { connection: name, kind, label } — label is a short, non-secret description (a host, an account id). |
"list" | none | any role, viewer included | { connections: [{ name, kind, label, created_at, updated_at }] } — never a credential. |
"remove" | name | owner or signed-in | { removed: true, name }. Refused while any bound key still reads through it, naming those keys — rebind them (or bind them with inline credentials) first. |
A field that belongs to another action is refused, naming it. A plain operator key is refused on "set" and "remove" with "this key is an operator; ask an owner, or sign in" — a standing credential changes what every future bind through it reads. See Roles.
Example
{ "action": "set", "name": "sfdc-prod", "kind": "salesforce",
"instance_url": "https://acme.my.salesforce.com", "client_id": "…", "client_secret": "…" }
→ { "connection": "sfdc-prod", "kind": "salesforce", "label": "acme.my.salesforce.com" }
Settings & delivery
How the whole tenant behaves, and where a held action is announced.
settingsRecordThis tenant's standing settings: gate or observe mode, where Ogen reaches you, evidence recording, Ogen Assist, and the public discovery door. One action per call.
Actions, inputs and resultsActions
| action | Fields | Role | What it does, and what comes back |
|---|---|---|---|
"mode" | mode ("gate" | "observe"); acknowledge and confirm, only to switch to observe | owner or signed-in | gate (the default) holds and escalates as usual; observe never holds, only counts what it would have caught. Switching to observe turns holding off for every action kind, so it also needs acknowledge: true and confirm: "nothing will be held" — omit either and nothing changes. Switching back needs neither. A switch to observe emails your contact once, naming who flipped it and when. See Shadow mode. |
"contact" | email, timezone (an IANA name such as "Europe/London"), weekend ("sat-sun" | "fri-sat" | "none") — any alone, or several together | owner or signed-in | Where trial notices and an unanswered-hold note go, and where a weekend is for a kind whose holds skip weekends. The email is stored encrypted and never returned. A timezone Ogen doesn't know is refused. Returns { recorded: true }. |
"evidence" | enabled; secret, optional | operator | Keeps a keyed record of what each read saw, checkable later with your secret, never the value itself. Off by default. Omit secret and Ogen generates one, returned exactly once. See Evidence mode. |
"assist" | enabled; provider_key, model (default claude-opus-5), daily_cap (default 50, max 500), optional | owner or signed-in | Turns Ogen Assist on or off. On needs your own Anthropic key (Team tenants may omit it) — encrypted, never returned. Off clears the stored key and every open draft. Every hold then carries a drafted explanation and a fix template a person completes; Assist never confirms, rejects, or picks. See Ogen Assist. |
"door" | public; slug (3-32 lowercase letters, digits, hyphens — required the first time public is turned on) | owner or signed-in | Turns GET <pod>/door/<slug> on or off, and claims the slug it's served at. Off by default. The document names your registered action kinds, says every request waits on your say-so when your own facts disagree or the action is costly, and how to get in. A slug already taken is refused by name. Returns { public, slug?, url?, snippet?, well_known? } — snippet is a one-line <link rel="ogen-door"> tag to paste in your site's <head>, and well_known is the same thing as a /.well-known/ogen-door redirect, so a visiting agent can find your door without being told the URL first. Either is optional; it points, it does not gate. |
A field that belongs to another action is refused, naming it. Every action but "evidence" changes what every future act does, so a plain operator key is refused with "this key is an operator; ask an owner, or sign in". See Roles.
Example
{ "action": "mode", "mode": "observe", "acknowledge": true, "confirm": "nothing will be held" }
→ { "mode": "observe" }
webhookRecordA signed HTTP POST whenever an action is held or escalated (or, in observe mode, when it would have been). One URL per tenant.
Actions, inputs and resultsActions
| action | Fields | Role | What it does, and what comes back |
|---|---|---|---|
"set" | url (https); secret, optional — omit and Ogen generates one, returned once | owner or signed-in | Starts sending. Returns { registered: true, url_host }, plus secret once when Ogen generated it. See Actions & confirmations for the payload and signature. |
"remove" | none | owner or signed-in | Stops sending. Returns { removed: true }. |
A plain operator key is refused with "this key is an operator; ask an owner, or sign in" — see Roles.
Fixes, outcomes & proof
An operator reaches for these after the fact: reversing an action or restoring a fix, reporting what ran, certifying a packet, reading what a period of activity caught.
reverseRecordRecord that an action was reversed, so what went wrong is not repeated — or put a correction that was set aside back into force. A named person either way.
Actions, inputs and resultsActions
| action | Fields | Role | What it does, and what comes back |
|---|---|---|---|
"reverse" | action_id (from commit_gated_action), reversed_by; reason, optional | operator | Marks the action reversed. Returns { reversed: true }. |
"restore" | rule_id (a correction that was set aside), restored_by | operator | Puts that correction back into force. Returns { restored: true, rule_id }. |
report_outcomeRecordTell Ogen whether a confirmed action ran, with the release ticket its confirmation issued. For an agent that runs the action itself; a system without an Ogen key sends the same body to POST /v1/receipts. Ogen records it; it never runs the action.
Inputs
| Field | Type | Description |
|---|---|---|
ticket | string | The release_ticket. |
outcome | "ran" | "failed" | Whether your system ran the action. |
reference | string, optional | Your system's own id for what it did: 1 to 120 letters, digits, or _ . : - (like re_3NqX). Anything else is refused. |
error | string, optional | Why it did not run. Checked, never stored. |
Comes back
{ recorded: true, hold_id, action_id, kind, outcome, reference? }, or { recorded: false, reason, guidance }. Each ticket reports once.
certify_packetRecordCertify a packet of documents against what was read out of them. Checks whether each reading actually says what it claims, and whether documents naming the same field agree. Optionally checks a reading against a supplied record too.
Inputs, results and an exampleInputs
| Field | Type | Description |
|---|---|---|
documents | array of { id, kind, text } | Every document in the packet, verbatim. |
readings | array of { document_id, field, value, span } | What was read out of the documents — span is the character offset the value was claimed to sit at. |
records | array of { entity, values }, optional | External values on record for a field, to check a lone reading against. |
Comes back
Per field: whether it is certified, refuted, or unproven, which documents state it, and — when
documents disagree — what each one said. release is true only when every field is certified.
{ "release": true, "fields": [
{ "field": "total", "state": "certified", "documents": ["invoice", "po"], "note": "..." }
], "holds": [] }
what_it_caughtFree · RecordA short report of what Ogen did for you over a trailing window: what your agent asked, what it was able to act on, what waited for a person, and what a person decided. Every count is from calls already made — nothing here runs on a timer.
Inputs, results and an exampleInputs
| Field | Type | Description |
|---|---|---|
days | integer, optional, ≤ 90 | Window size in days. Default 7. |
Comes back
The same numbers as the public proof page:
| Field | What it counts |
|---|---|
reads | What your agent asked for, and how each answer came back: resolved, ambiguous, unavailable. |
holds | Actions that waited for a person instead of running. |
staleness_caught | Values that had moved since your agent last read them. |
set_aside | Corrections that stopped applying. |
later_released | Actions that waited for a person and went through afterwards. |
would_have_acted_on_stale | Times your agent would have acted on something other than a single, current, agreed value. |
- Two signals, read-only, never a release.
decided_within_10s_7dis{ fast, total }— of the holds decided in the trailing 7 days, how many were decided within 10 seconds of being created (a tell for an approver mailbox forwarded straight to a bot).confirmed_unchanged_streaksis a list of{ kind, streak }— action kinds whose last 10 or more decisions were all CONFIRM with no fix ever taught for the key, a nudge to teach_fix the fix once or narrow the kind.
Example
{ "tenant": "t_1a2b3c", "window_days": 7,
"reads": { "resolved": 41, "ambiguous": 6, "unavailable": 2 },
"holds": 5, "staleness_caught": 3, "set_aside": 0, "later_released": 1,
"would_have_acted_on_stale": 11,
"decided_within_10s_7d": { "fast": 3, "total": 5 },
"confirmed_unchanged_streaks": [{ "kind": "send-refund", "streak": 12 }] }
audit_logFree · RecordPaste a log of your agent's past reads and actions and see how many times it would have acted on stale or uncertain data. Nothing here is stored.
Inputs, results and an exampleInputs
| Field | Type | Description |
|---|---|---|
events | array, up to 2,000 | Each event: at (ISO timestamp), kind (read | act), plus optional key, value, candidates, acted, later_corrected. |
Comes back
{ acted_on_uncertain, stale_reads, repeated_corrections, headline }:
- acted_on_uncertain — times your agent acted while the fact was still disputed.
- stale_reads — reads that were already out of date.
- repeated_corrections — the same fact fixed more than once.
- headline — one sentence: how many times, total, your agent would have acted on stale or uncertain data in this log.
Example
{ "acted_on_uncertain": 2, "stale_reads": 1, "repeated_corrections": 0,
"headline": "Your agent would have acted on stale or uncertain data 3 times in this log." }