Skip to content

Who used this account, and how it ended

GET
/audit
curl --request GET \
--url 'https://api.flotera.com/api/v1/audit?sort=asc' \
--cookie __Host-erm_session=<__Host-erm_session>

One chronological feed over three separate logs: account actions (audit — sign-ins, token issue and revoke, denials), AI client calls (mcp, refusals included) and notification delivery (notification).

They stay separate tables on purpose — they answer different questions, and merging them on write would lose that distinction for good. They are merged on read because a person needs one timeline: “signed in at 14:02, the model asked for a reboot at 14:03, refused at 14:03” reads as a story; three screens make you assemble it yourself.

Paging uses a <timestamp>|<id> cursor. A timestamp alone would skip rows that share one — and refusals arrive in bursts that share one.

No request bodies, no call arguments, no addresses: source IPs are stored hashed. An access log must not become a second copy of what it is meant to guard.

source
string

Comma-separated sources. Empty means all. An unknown name is rejected.

outcome
string
from
string format: date-time
to
string format: date-time
q
string

Substring of the action name.

sort
string
Allowed values: asc desc
limit
integer
>= 1 <= 500
cursor
string

Audit entries, newest first unless sorted otherwise.

Media typeapplication/json
object
entries
required
Array<object>
object
id
required
string format: uuid
at
required
string format: date-time
source
required
string
Allowed values: audit mcp notification
actor
required

Who acted — a user, an agent, the AI client, or the system.

string
action
required
string
target
string | null
outcome
required
string
detail

Machine-readable reason code, never free text.

string | null
next_cursor

Cursor for the next page; null when the feed is exhausted.

string | null
sources
required

Sources this server can return. The panel builds its filters from this, not from a list of its own — its own would fall behind.

Array<string>
Example
{
"entries": [
{
"source": "audit"
}
]
}

Request failed validation (code=validation_failed), with per-field errors.

Media typeapplication/problem+json

RFC 9457 problem document with a stable machine code.

object
type
required
string format: uri
title
required
string
<= 256 characters
status
required
integer
>= 100 <= 599
code
required

Stable machine-readable error code (03 §2.4).

string
Allowed values: unauthorized forbidden csrf_rejected not_found conflict idempotency_conflict validation_failed rate_limited payload_too_large unsupported_agent_version temporarily_unavailable offline_queue_full online_queue_full plan_required server_limit_reached feature_not_entitled account_in_grace account_frozen payment_pending payment_expired payment_amount_mismatch change_already_pending change_already_applied change_effective reserve_not_covered direction_changed
detail
string
<= 2048 characters
instance
string
<= 512 characters
request_id

UUID (v7 for new entities; v4 accepted during migration).

string format: uuid
errors
Array<object>
<= 100 items
object
path
required

JSON Pointer to the offending field.

string
<= 512 characters
code
required
string
<= 64 characters
Example
{
"type": "https://ermeon.com/problems/validation",
"code": "unauthorized"
}

Missing/invalid credentials (code=unauthorized).

Media typeapplication/problem+json

RFC 9457 problem document with a stable machine code.

object
type
required
string format: uri
title
required
string
<= 256 characters
status
required
integer
>= 100 <= 599
code
required

Stable machine-readable error code (03 §2.4).

string
Allowed values: unauthorized forbidden csrf_rejected not_found conflict idempotency_conflict validation_failed rate_limited payload_too_large unsupported_agent_version temporarily_unavailable offline_queue_full online_queue_full plan_required server_limit_reached feature_not_entitled account_in_grace account_frozen payment_pending payment_expired payment_amount_mismatch change_already_pending change_already_applied change_effective reserve_not_covered direction_changed
detail
string
<= 2048 characters
instance
string
<= 512 characters
request_id

UUID (v7 for new entities; v4 accepted during migration).

string format: uuid
errors
Array<object>
<= 100 items
object
path
required

JSON Pointer to the offending field.

string
<= 512 characters
code
required
string
<= 64 characters
Example
{
"type": "https://ermeon.com/problems/validation",
"code": "unauthorized"
}

A dependency the endpoint needs is not configured or is temporarily unavailable (code=unavailable). The rest of the API keeps working — an absent external integration must not take the service down.

Media typeapplication/problem+json

RFC 9457 problem document with a stable machine code.

object
type
required
string format: uri
title
required
string
<= 256 characters
status
required
integer
>= 100 <= 599
code
required

Stable machine-readable error code (03 §2.4).

string
Allowed values: unauthorized forbidden csrf_rejected not_found conflict idempotency_conflict validation_failed rate_limited payload_too_large unsupported_agent_version temporarily_unavailable offline_queue_full online_queue_full plan_required server_limit_reached feature_not_entitled account_in_grace account_frozen payment_pending payment_expired payment_amount_mismatch change_already_pending change_already_applied change_effective reserve_not_covered direction_changed
detail
string
<= 2048 characters
instance
string
<= 512 characters
request_id

UUID (v7 for new entities; v4 accepted during migration).

string format: uuid
errors
Array<object>
<= 100 items
object
path
required

JSON Pointer to the offending field.

string
<= 512 characters
code
required
string
<= 64 characters
Example
{
"type": "https://ermeon.com/problems/validation",
"code": "unauthorized"
}