Events
This is the endpoint everything else exists for. You push facts — a badge read, a work order closed, a temperature reading — and sinio.ai derives episodes, durations and findings from them. On this page: the event model, the endpoint, and the two authentication surfaces that reach it.
The event model
An event is a fact with an identity that is stable on your side, a type, a moment and, optionally, a payload. The four structural roles sinio.ai knows how to resolve live in a fixed roles envelope, separate from the payload.
Properties
- Name
source_event_id- Type
- string
- Description
Required. The event's identity in your system, stable over time. Together with the project and the source, it is what makes replays free.
- Name
type- Type
- string
- Description
Required. The
codeof an event type. A code the project does not know yet is not an error — the event is stored aspending_classification.
- Name
occurred_at- Type
- string
- Description
Required. ISO 8601 with a UTC offset, written
YYYY-MM-DDThh:mm:sswith seconds, an optional fraction, thenZor±hh:mm— for instance2026-08-28T07:58:12+02:00. Anything else is rejected withinvalid_occurred_at— a timestamp with no offset is not a moment, and guessing one silently corrupts every duration derived from it.
- Name
payload- Type
- object
- Description
Optional,
{}when omitted. Free-form, up to 256 KB per event (beyond, that event alone is rejected withpayload_too_large): its content is never checked. Stored whole; only what the type's publishedinterpretation(and the readings its source declares) names is read from it. A badge read often has nothing else to say — leave it out.
- Name
count- Type
- integer
- Description
Optional, 1 to 1,000,000. How many units this one event stands for — a satisfaction button pressed ten times between two messages of a terminal is one event with a
countof 10. Omitted, the event counts once. Only this top-level field is read — a count insidepayloadis never used. Every total and satisfaction score is weighed by it.
- Name
roles- Type
- object
- Description
Optional. The four structural roles:
device,subject,location,actor, each the raw identifier your system uses, as a string. All optional, except asubjector anactorthat the event type'sinterpretationmarksrequired: true(deviceandlocationcan never be required). Any other key is refused — a ticket number or a firmware version belongs inpayload.
- Name
source_version- Type
- string
- Description
Optional. Your system's version of this event, stored with it for your own tracing. It plays no part in deduplication: whether a resend is a duplicate or a correction is decided on its content alone — see Batching & idempotency.
- Name
label- Type
- string
- Description
Optional. A human-readable name for the type, used only when the type is unknown — it gives whoever classifies it later something better to read than a raw code.
Send events
Ingest a batch of up to 500 events, in a request body of up to 10 MB. Acceptance is partial: valid events are stored even when others in the same batch are rejected.
A 200 confirms reception, not derivation — derivation runs on its own queue moments later. A body over 10 MB is refused as a whole with 413.
Required attributes
- Name
events- Type
- array
- Description
Up to 500 events. More is a
400for the whole call.
Optional attributes
- Name
mode- Type
- string
- Description
webhook(default) orbackfill. The declared mode decides whether the batch can raise alerts: a backfill raises none, and once it has arrived the project's processes, if it has any, read it again — see Backfill.
Headers
- Name
Authorization- Type
- string
- Description
Bearer <api_key>.
Request
curl https://api.sinio.ai/v1/events \
-H "Authorization: Bearer $SINIO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"events": [
{
"source_event_id": "evt_88213",
"source_version": "3",
"type": "badge_in",
"occurred_at": "2026-08-28T07:58:12+02:00",
"roles": {
"device": "BORNE-A12",
"subject": "P-4582",
"location": "SITE-A.HALL"
},
"payload": { "badge": "04A2B9C1", "reader_firmware": "2.4.1" }
}
]
}'
Response
{
"batch_id": "0192f3a4-7b1c-7e2d-9a10-4c5b6d7e8f90",
"accepted": 497,
"pending_classification": 1,
"duplicates": 1,
"revisions": 0,
"rejected": 1,
"rejections": [
{
"source_event_id": "evt_88240",
"code": "invalid_occurred_at",
"message": "occurred_at must be ISO 8601 with an offset, got: \"2026-08-28T07:58:12\""
}
],
"test_mode": false
}
Reading the response
- Name
batch_id- Type
- string
- Description
The identifier sinio.ai assigned to this call (a UUID), generated on its side — you cannot send one. Quote it when you contact support. It plays no part in deduplication.
- Name
accepted- Type
- integer
- Description
Stored, with a known type. In
webhookmode it is queued for derivation; inbackfillmode the project's processes read it once the batch has arrived.
- Name
pending_classification- Type
- integer
- Description
Stored, waiting for its type to be given a meaning. A success, not a rejection — the payload is kept whole and derived once the type is known.
- Name
duplicates- Type
- integer
- Description
No-ops: events whose content is identical to any revision you had already sent — the latest one, or one that has since been superseded.
- Name
revisions- Type
- integer
- Description
Corrections: same
source_event_id, different content (payload,occurred_at,rolesorcount). A new revision was written and a recomputation queued.
- Name
rejected- Type
- integer
- Description
The only failure count. Every one of them is detailed in
rejections.
- Name
rejections- Type
- array
- Description
One entry per rejected event:
source_event_id,code,message. The codes are listed in Errors.
- Name
test_mode- Type
- boolean
- Description
truewhen the key is in test mode, while a connection is being set up: the events were checked exactly as live ones and counted the same way, but kept aside — nothing is derived from them until the test is kept. See Authentication.
Unknown fields are refused, never ignored: a key this page does not list —
in the request, in an event or in roles — fails the whole call with a 400
(events.0.property foo should not exist for a key inside the first event). A misspelt role would otherwise lose
every identifier without a word. Only the content of payload is free.
Send events with a webhook key
The same body, the same mode, the same processing as POST /v1/events — only the authentication moves from the Authorization header into the URL, carried by a webhook token rather than an API key. It exists for systems that can be pointed at a URL and nothing else.
The key is a credential like any other, so treat the whole URL as a secret.
This is not a generic receiver: the body must be the sinio.ai event format. A third-party payload posted as-is will not be normalised for you.
Request
curl https://api.sinio.ai/v1/webhooks/$SINIO_WEBHOOK_KEY \
-H "Content-Type: application/json" \
-d '{
"events": [
{
"source_event_id": "evt_88213",
"type": "badge_in",
"occurred_at": "2026-08-28T07:58:12+02:00",
"roles": { "device": "BORNE-A12", "subject": "P-4582" }
}
]
}'
Response
{
"batch_id": "0192f3a4-7b1c-7e2d-9a10-4c5b6d7e8f90",
"accepted": 1,
"pending_classification": 0,
"duplicates": 0,
"revisions": 0,
"rejected": 0,
"rejections": [],
"test_mode": false
}