Oxelone Docs

Search docs and API

Find a guide, a section of one, or an API operation by its name.

Open console (opens in a new tab)

API reference Resources

Activity

Interactions, file events, scans and comments.

13 operations

One subject's thread

GET/comments

Query parameters

subject_kindstring · null

artifact or issue.

subject_idstring · null

Response200

The thread, oldest first, tombstones included

commentsComment[]required

Oldest first, tombstones included. A discussion is read in the order it happened, and a withdrawn comment keeps its row and its position — its absence would leave the replies under it reading as remarks about nothing.

author_display_namestringrequired

The author's display name.

author_idstringrequired
created_atstringrequired
idstringrequired
subject_idstringrequired
subject_kindstringrequired

Errors

400

Missing or unknown subject_kind

403

Caller lacks the grant that reads this subject

404

No such subject in this workspace

Add a comment, or a reply

POST/comments

Recorded in the audit log by its ids, never its text.

Request bodyPostCommentRequest

bodystringrequired
subject_idstringrequired
subject_kindstringrequired
parent_idstring · null

The comment this replies to. Must itself be top-level, and must be on the same subject.

Response200

The stored comment

author_display_namestringrequired

The author's display name.

author_idstringrequired
created_atstringrequired
idstringrequired
subject_idstringrequired
subject_kindstringrequired
bodystring · null

null exactly when withdrawn_at is set, and the schema says the same thing as a CHECK in both directions: a tombstone cannot carry text and a live comment cannot be blank.

parent_idstring · null

null for a top-level comment; otherwise the comment this replies to. Never two levels deep.

withdrawn_atstring · null

Errors

400

Empty or over-long body, an unknown subject kind, or a reply to a reply

403

Caller lacks the grant that reads this subject

404

No such subject in this workspace

Withdraw your own comment

DELETE/comments/{comment}

Returns the tombstone, not 204: the drawer replaces the row in place rather than removing it, and giving it the row back means it does not have to re-fetch the thread to find out what happened.

Audited. Taking a statement back out of a record of what was decided is exactly the act somebody will later need to account for, and the row it leaves behind no longer says who wrote it — the tombstone keeps author_id, but only the audit log says when and by whom it was withdrawn.

Path parameters

commentstringrequired

Response200

The tombstone

author_display_namestringrequired

The author's display name.

author_idstringrequired
created_atstringrequired
idstringrequired
subject_idstringrequired
subject_kindstringrequired
bodystring · null

null exactly when withdrawn_at is set, and the schema says the same thing as a CHECK in both directions: a tombstone cannot carry text and a live comment cannot be blank.

parent_idstring · null

null for a top-level comment; otherwise the comment this replies to. Never two levels deep.

withdrawn_atstring · null

Errors

403

The comment belongs to somebody else

404

No such comment in this workspace

File events — fleet-wide, or one artifact's timeline

GET/file-events

One route for both, because they are one question asked at two scopes. A separate timeline endpoint would be a second place to add an event kind, and the day somebody added one to only the first is the day the drawer started lying by omission.

Query parameters

fstring · null

The filter expression. Fields: kind, machine, artifact, category, at.

The drawer's timeline is this and not a second parameter: all;artifact~in~<id>. An artifact_id shortcut beside f would be a second way to say one thing, and the two would answer differently the first time one of them learned about a new event kind.

qstring · null

Free text over the artifact's name and location.

cursorstring · null
limitinteger · null

Response200

eventsFileEvent[]required
artifact_categorystringrequired
artifact_idstringrequired
artifact_namestringrequired
atstringrequired
idstringrequired
kindstringrequired
totalintegerrequired

Everything the filter matched, not just this page.

next_cursorstring · null

Pass back as cursor for the next page. null means this was the last.

One file event

GET/file-events/{event}

One file event, by id. 404 for anything this workspace does not hold: an unknown id, another workspace's event, or a value that is not an id at all.

Path parameters

eventstringrequired

Response200

artifact_categorystringrequired
artifact_idstringrequired
artifact_namestringrequired
atstringrequired
idstringrequired
kindstringrequired
current_hashstring · null
detailSettingsChange · null
changesSettingChange[]required
moreintegerrequired
machine_idstring · null
previous_hashstring · null
scan_run_idstring · null

The scan that produced this event, when one is recorded. null for events recorded before scans were tracked, and on events the server wrote itself because a scanned location stopped being reported: no scan produced those.

Errors

404

No such event in this workspace

The Interactions log — intercepted prompts, newest first

GET/interactions

Query parameters

fstring · null

The filter expression, e.g. all;service~in~anthropic;outcome~in~blocked.

The first segment is the join (all or any); each later segment is field~op~values, with op one of in, nin, before, after and values separated by commas. A malformed segment is ignored; a field this list does not have is a 400 naming it.

Fields: service, host, client_kind, client_name, tactic, outcome, prompt, machine, user, account, session, correlation, at. user is the OS account signed in to the machine; account is the account signed in to the AI service. all;session~in~<id> lists one session. correlation is the id a hook row shares with the network row it caused, so all;correlation~in~<id> returns both halves of one interaction.

prompt takes found (a prompt was read from the request), none (the request was read and held no prompt) or unread (the request was never read for a prompt). all;prompt~in~found is the log of what people actually typed.

qstring · null

Free text over the service, host, endpoint and declared tool name. ANDs with the expression whichever way its conditions are joined.

It does not reach the prompt. Searching bodies would let a caller confirm a string is in somebody's prompt without rendering it, which is the one thing a content grant exists to govern.

cursorstring · null

Where the previous page stopped. Opaque; an unreadable one starts over.

limitinteger · null

Rows wanted. Clamped to 200.

Response200

interactionsInteraction[]required
attachment_countintegerrequired

How many entries attachments holds.

attachmentsAttachment[]required

The files that rode this interaction, containers before members.

capture_tacticstringrequired
content_stateenumrequired

What happened to this row's prompt and response text, as one word: withheld, dropped, pending, captured or not_captured.

capturednot_captureddroppedwithheldpending
content_withheldbooleanrequired

`true` only when content exists on this row and this caller may not see it.

Without it, a caller reads null previews and cannot tell never captured from withheld from you, and those are different facts about different things: the first is a statement about the machine's capture tactic — nothing exists, nobody is being kept from anything — and the second is a statement about the reader. Rendering the second as the first tells an operator there is no content here when there is, which is the kind of quiet inaccuracy that surfaces during an incident review.

Per row, not per response. One page legitimately mixes both: a metadata-tactic interaction beside a content-tactic one genuinely has nothing to withhold, and a response-level flag would mark it as withheld and be wrong about it.

false for a caller holding interaction_content:read, and false for a row that never had content to begin with. It is a fact about this row and this reader, so it is computed in the projection beside the redaction it describes — one place, which is the only way the two cannot disagree.

decided_at_hookstring[]required

On a network row, the policies a tool's hook already decided for this prompt; the hook row shares this row's correlation_id. Filled on GET /interactions/{id}; empty on the list.

totalintegerrequired

Every interaction the filter matched, across all pages, not only this one.

next_cursorstring · null

Pass back as cursor for the next page. null means this was the last.

Errors

401

No valid session

403

Caller lacks machines:read in this workspace

List interactions grouped by session

GET/interactions/by-session

A page of sessions, newest activity first. A session is on the page when any of its interactions matches f and q, ordered by its newest matching one; matched says how many matched. Metadata only: read a session's interactions with GET /interactions/by-session/rows.

Query parameters

fstring · null

The filter expression, e.g. all;service~in~anthropic;outcome~in~blocked.

The first segment is the join (all or any); each later segment is field~op~values, with op one of in, nin, before, after and values separated by commas. A malformed segment is ignored; a field this list does not have is a 400 naming it.

Fields: service, host, client_kind, client_name, tactic, outcome, prompt, machine, user, account, session, correlation, at. user is the OS account signed in to the machine; account is the account signed in to the AI service. all;session~in~<id> lists one session. correlation is the id a hook row shares with the network row it caused, so all;correlation~in~<id> returns both halves of one interaction.

prompt takes found (a prompt was read from the request), none (the request was read and held no prompt) or unread (the request was never read for a prompt). all;prompt~in~found is the log of what people actually typed.

qstring · null

Free text over the service, host, endpoint and declared tool name. ANDs with the expression whichever way its conditions are joined.

It does not reach the prompt. Searching bodies would let a caller confirm a string is in somebody's prompt without rendering it, which is the one thing a content grant exists to govern.

cursorstring · null

Where the previous page stopped. Opaque; an unreadable one starts over.

limitinteger · null

Rows wanted. Clamped to 200.

Response200

sessionsInteractionSessionGroup[]required
blockedintegerrequired

Of count, the ones a decision blocked.

countintegerrequired

Every interaction in the session, whatever the filter says. On the group with no session, the ones that matched.

first_atstringrequired

observed_at of the session's first and last interaction.

last_atstringrequired
matchedintegerrequired

Of those, the ones the filter and the search matched — what opening the session lists. Equal to count when nothing narrows the list.

client_namestring · null

The tool's declared name, from the session's most recent row that declared one. null when none did, and on the group with no session.

totalintegerrequired

Sessions with at least one matching interaction; the group with no session counts as one.

next_cursorstring · null

Pass back as cursor for the next page. null means this was the last.

Errors

400

The filter names a field this list does not have

401

No valid session

403

Caller lacks machines:read in this workspace

One session's interactions

GET/interactions/by-session/rows

The interactions in one session that the filter matches, oldest first. Rows, permissions and content rules are the same as on GET /interactions.

Query parameters

sessionstring · null

The session whose interactions to read, verbatim. Exactly one of this and unsessioned.

unsessionedboolean · null

true reads the interactions that carry no session id — the list's No session group.

fstring · null

The list's filter expression, as on GET /interactions.

qstring · null

The list's free text, as on GET /interactions.

cursorstring · null

Where the previous page stopped. Opaque; an unreadable one starts over.

limitinteger · null

Rows wanted. Clamped to 200.

Response200

interactionsInteraction[]required
attachment_countintegerrequired

How many entries attachments holds.

attachmentsAttachment[]required

The files that rode this interaction, containers before members.

capture_tacticstringrequired
content_stateenumrequired

What happened to this row's prompt and response text, as one word: withheld, dropped, pending, captured or not_captured.

capturednot_captureddroppedwithheldpending
content_withheldbooleanrequired

`true` only when content exists on this row and this caller may not see it.

Without it, a caller reads null previews and cannot tell never captured from withheld from you, and those are different facts about different things: the first is a statement about the machine's capture tactic — nothing exists, nobody is being kept from anything — and the second is a statement about the reader. Rendering the second as the first tells an operator there is no content here when there is, which is the kind of quiet inaccuracy that surfaces during an incident review.

Per row, not per response. One page legitimately mixes both: a metadata-tactic interaction beside a content-tactic one genuinely has nothing to withhold, and a response-level flag would mark it as withheld and be wrong about it.

false for a caller holding interaction_content:read, and false for a row that never had content to begin with. It is a fact about this row and this reader, so it is computed in the projection beside the redaction it describes — one place, which is the only way the two cannot disagree.

decided_at_hookstring[]required

On a network row, the policies a tool's hook already decided for this prompt; the hook row shares this row's correlation_id. Filled on GET /interactions/{id}; empty on the list.

totalintegerrequired

Every interaction the filter matched, across all pages, not only this one.

next_cursorstring · null

Pass back as cursor for the next page. null means this was the last.

Errors

400

Neither or both of session and unsessioned, or a field this list does not have

401

No valid session

403

Caller lacks machines:read in this workspace

Session summaries

GET/interactions/sessions

Summaries of the sessions named by ids. Metadata only: counts, a tool name, an OS account and a machine. A session id with no interactions is left out of the answer.

Query parameters

idsstring[]required

Session ids, one per repeated ids parameter (?ids=a&ids=b).

Repeated rather than comma-separated because a session id is the AI service's own text and may itself hold a comma or leading and trailing spaces; each value is taken verbatim. At most 100, each at most 256 bytes; an id with no interactions is left out of the answer rather than being an error.

Response200

sessionsInteractionSession[]required
blockedintegerrequired

Of those, the ones a decision blocked.

countintegerrequired

Interactions in the session.

first_atstringrequired

observed_at of the first and last interaction — the endpoint's clock.

last_atstringrequired
session_idstringrequired
client_namestring · null

The tool's declared name, from the session's most recent row that declared one. null when none did.

Errors

400

More than 100 session ids

401

No valid session

403

Caller lacks machines:read in this workspace

One interaction, for the drawer

GET/interactions/{interaction}

The same projection the list returns, so a row and the drawer opened from it can never disagree about what an interaction is.

Path parameters

interactionstringrequired

Response200

attachment_countintegerrequired

How many entries attachments holds.

attachmentsAttachment[]required

The files that rode this interaction, containers before members.

extensionstringrequired

Lowercased; "" when the file had none.

idstringrequired
namestringrequired
parse_statusstringrequired

parsed | partial | unsupported | failed | encrypted_skipped | declined_decrypt.

password_protectedbooleanrequired
size_bytesintegerrequired
capture_tacticstringrequired
content_stateenumrequired

What happened to this row's prompt and response text, as one word: withheld, dropped, pending, captured or not_captured.

capturednot_captureddroppedwithheldpending
content_withheldbooleanrequired

`true` only when content exists on this row and this caller may not see it.

Without it, a caller reads null previews and cannot tell never captured from withheld from you, and those are different facts about different things: the first is a statement about the machine's capture tactic — nothing exists, nobody is being kept from anything — and the second is a statement about the reader. Rendering the second as the first tells an operator there is no content here when there is, which is the kind of quiet inaccuracy that surfaces during an incident review.

Per row, not per response. One page legitimately mixes both: a metadata-tactic interaction beside a content-tactic one genuinely has nothing to withhold, and a response-level flag would mark it as withheld and be wrong about it.

false for a caller holding interaction_content:read, and false for a row that never had content to begin with. It is a fact about this row and this reader, so it is computed in the projection beside the redaction it describes — one place, which is the only way the two cannot disagree.

decided_at_hookstring[]required

On a network row, the policies a tool's hook already decided for this prompt; the hook row shares this row's correlation_id. Filled on GET /interactions/{id}; empty on the list.

decisionsDecision[]required

Everything decided about this interaction, oldest first. Empty means nothing has decided anything about it yet, since a later verdict can still attach to it. Empty does not mean it passed: evaluated_by says whether a policy checked it.

decided_atstringrequired
decided_bystringrequired

inline, policy or engine. Shown verbatim: "blocked on the laptop from the bundle" and "blocked by the server" are different facts to somebody chasing a false positive.

idstringrequired
outcomestringrequired

passed, alerted or blocked. An interaction that alerted and was blocked has two of these, deliberately.

pendingbooleanrequired

true while a verdict is still owed: the decision is undetermined and its policy has not finished evaluating the interaction yet. false on an undetermined decision means evaluation finished and still could not decide.

recorded_atstringrequired
evaluated_byEvaluatedBy[]required

The policies that evaluated this interaction, whether or not they matched: Enabled or Monitor policies whose conditions were checked. Non-empty with no objecting decision reads as Allowed; empty with no decision reads as Not evaluated. Empty on older interactions.

idstringrequired
namestring · null

The policy's name; null when it has since been deleted — it still evaluated this, and the id is the honest answer.

hoststringrequired
idstringrequired
methodstringrequired
observed_atstringrequired
received_atstringrequired
request_bytesintegerrequired
response_bytesintegerrequired
servicestringrequired
sourcestringrequired

Which capture produced this row: endpoint_agent or connector. New values may be added; treat an unknown one as a label, not an error.

account_person_idstring · null

The person service_account names. The address is matched without regard to letter case. null where the row carries no service account, or where no person has ever been seen with it.

action_kindstring · null

hook rows only: what the tool was doing (prompt, shell, file_read, mcp_call, tool_use, session_start).

can_revealboolean · null

Whether this caller may reveal them now: both grants, a key on this deployment, and something held.

capturestring · null

How it was captured: network, extension or hook. null on older interactions recorded before capture was tracked.

client_kindstring · null

Declared by the capture surface. null means nothing declared one, which is not the same as other.

client_namestring · null

The tool's own name, e.g. "Claude Code". Declared by the capture surface, never inferred from a User-Agent. client_kind says what form of client it was; this tells one tool from another. null means no capture surface declared a name, which is common, not that the tool is unknown.

connection_idstring · null

The connection whose sync ingested this interaction. null on every interaction a machine reported.

correlation_idstring · null

Joins a hook row to the network row the same call caused.

endpointstring · null

The path and query. null on some older interactions, which does not mean an empty path.

held_valuesinteger · null

How many originals are held (Restricted only).

log_redactionstring · null

The Redaction in logs mode this interaction's text was stored under. Absent on the list; set on GET /interactions/{id}.

machine_idstring · null

The machine that reported this interaction. null on an interaction a connection ingested (a Copilot turn, say, was reported by no machine); connection_id is set exactly when this is null.

modelstring · null

The model this request named, verbatim from the body, e.g. gpt-4o-mini, auto, claude-opus-4-1.

null is common: some services (Gemini, Bedrock) name the model in the URL, and a model is never guessed from a host or an endpoint.

os_userstring · null

The logged-in OS account. An identifiable person.

prompt_kindstring · null

What the person did: sent (a message they submitted) or draft (text that left the machine while they were still typing it). prompt_turns says how many requests were folded into a draft.

Metadata, returned without content access. null on some older interactions.

prompt_pathstring · null

Where in the body the text came from — messages[].content. Provenance, shown beside the text, and what an operator uses to tell a real attribution from a lucky field name. A JSON address, not content.

prompt_textstring · null

What the person actually typed, read out of the request. Content: it is returned only to a caller allowed to read interaction content.

Three distinct answers. null with prompt_tier also null means the request was never read for a prompt (a metadata-only exchange, or an older interaction). "" with a prompt_tier of unknown_shape or undecodable means it was read and held no prompt. null with a prompt_tier present means the caller may not see it, which content_withheld also says.

prompt_tierstring · null

How prompt_text was found, and therefore how much to trust it: known_shape, named_field, unknown_shape or undecodable.

Metadata, returned without content access: that a request carried a prompt is a fact like its endpoint or byte counts.

prompt_turnsinteger · null

How many requests folded into this row. 1 for a send; for a draft, the length of the prefix chain — 5 for sel…selamlar.

Without it a collapsed draft looks like one request when it was five, and an operator asking how much this endpoint actually sent would be off by the whole chain.

redacted_valuesinteger · null

How many values in the stored text were replaced or masked.

request_previewstring · null

The start of the request body. Content.

null does not mean the prompt was empty. Either content was never captured (the machine's capture tactic collects none, or no body was seen), or the caller is not allowed to read interaction content and it was withheld. content_withheld tells the two apart.

response_previewstring · null
service_accountstring · null

The address the AI service is signed in as. An identifiable person, and null is common: it is only visible under a content tactic.

session_idstring · null

The AI service's own conversation id. null when unknown; one is never made up.

user_person_idstring · null

The person signed in to the machine: the person whose presence matches this row's machine and OS account.

Separate from account_person_id, because the account somebody uses for the AI service may belong to a different person from the one signed in to the machine. null where the row records no OS account, or where no person has been seen with that account on that machine yet.

Errors

404

No such interaction in this workspace

Uncovered traffic from a machine

GET/machines/{machine_id}/coverage

What this machine sent that no capture rule covers. Use it to tell a quiet machine from one whose traffic is going somewhere Oxelone does not record, such as a vendor's renamed endpoint. Metadata only; it needs the same permission as reading machines, not content access. A machine in another workspace, or a malformed id, is a 404; a machine whose traffic is fully covered returns 200 with an empty list.

Path parameters

machine_idstringrequired

Response200

Endpoints no rule covers, newest activity first

endpointsUnmatchedEndpoint[]required

Newest activity first, one row per path, not grouped. Paths that differ only by a generated segment appear as separate rows.

endpointstringrequired

The path, as the agent reported it, without query or fragment.

first_seenstringrequired
hitsintegerrequired

How many requests went there. A thousand requests are one row that counts to a thousand.

hoststringrequired
last_seenstringrequired
methodstringrequired

Errors

401

No valid session

403

Caller lacks machines:read in this workspace

404

No such machine in this workspace

The Scans surface

GET/scans

Query parameters

fstring · null

The filter expression. Fields: kind, outcome, machine, at.

cursorstring · null
limitinteger · null

Response200

scansScanRun[]required
artifacts_reportedintegerrequired
changed_somethingbooleanrequired

Whether this run changed the inventory. A run that did is always kept; of the runs that did not, only each machine's most recent few are.

content_changedintegerrequired
created_atstringrequired
disappearedintegerrequired
discoveredintegerrequired
totalintegerrequired
next_cursorstring · null

One scan run, for the drawer

GET/scans/{scan}

Path parameters

scanstringrequired

Response200

artifacts_reportedintegerrequired
changed_somethingbooleanrequired

Whether this run changed the inventory. A run that did is always kept; of the runs that did not, only each machine's most recent few are.

content_changedintegerrequired
created_atstringrequired
disappearedintegerrequired
discoveredintegerrequired
files_seenintegerrequired
idstringrequired
kindstringrequired
machine_idstringrequired
out_of_scopeintegerrequired
outcomestringrequired

open, completed, partial or failed. A run still open long after it started is a scan that never finished, which is itself a problem worth looking into.

rejectedintegerrequired
returnedintegerrequired
roots_scannedintegerrequired
unchangedintegerrequired
duration_msinteger · null

Elapsed milliseconds between started_at and finished_at.

failure_reasonstring · null
finished_atstring · null
scope_versionstring · null
started_atstring · null

Errors

404

No such scan in this workspace