Assignments
A badge is not a person. It is lent, returned, reassigned — and every one of those moves has a date. An assignment records which subject a credential belonged to over which period, so a badge handed to someone new next month leaves last month's reports exactly as they were.
The assignment model
Properties
- Name
credential- Type
- string
- Description
Required. The
external_idof the credential — the badge, tag or card.
- Name
subject- Type
- string
- Description
Required. The
external_idof the subject it belongs to.
- Name
valid_from- Type
- string
- Description
Required. ISO 8601, when the binding starts. Always give a UTC offset (
+01:00,Z): the API does not refuse a value without one, but cannot know which zone you meant. The SDKs refuse it before sending.
- Name
valid_to- Type
- string
- Description
Optional, same format. Omitted means still valid — the common case for a badge currently in someone's pocket. Must be after
valid_from.
- Name
relation- Type
- string
- Description
Optional, defaults to
assigned_to. What kind of binding this is.
Overlaps are refused by a database exclusion constraint, not by application logic — a credential cannot belong to two subjects at the same instant, ever, under any race condition. Sending the next holder closes the open assignment at their start; see Reassigning a badge.
Create assignments
Create, close or hand over up to 500 credential-to-subject bindings — a line sent again is read against what the badge already has (Reassigning a badge). Both entities are created undeclared if they do not exist yet — the same tolerance as everywhere else in the reference.
Required attributes
- Name
assignments- Type
- array
- Description
Up to 500 assignments.
Headers
- Name
Authorization- Type
- string
- Description
Bearer <api_key>.
Rejection codes
- Name
invalid_validity_period- Type
- code
- Description
valid_fromorvalid_tois not a date-time, orvalid_tois not aftervalid_from.
- Name
overlapping_assignment- Type
- code
- Description
This credential already has an assignment covering part of that window. Never merged silently — you decide which one is right.
Assignments require a Bearer API key. They are not reachable through a webhook key, which only carries event ingestion.
Request
curl https://api.sinio.ai/v1/assignments \
-H "Authorization: Bearer $SINIO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"assignments": [
{
"credential": "04A2B9C1",
"subject": "P-4582",
"relation": "assigned_to",
"valid_from": "2026-01-01T00:00:00+01:00"
}
]
}'
Response
{
"accepted": 1,
"rejected": 0,
"rejections": []
}
Overlap rejected
{
"accepted": 0,
"rejected": 1,
"rejections": [
{
"credential": "04A2B9C1",
"subject": "P-7781",
"code": "overlapping_assignment",
"message": "This credential already has an overlapping assignment"
}
]
}
Reassigning a badge
Send the list as your HR system holds it, as often as you like. POST /v1/assignments reads each line against what the badge already has:
- The same credential, subject and
valid_fromis the same assignment. Sent again unchanged, nothing happens; sent with avalid_to, it is closed; sent without one, it is open again. So the end date can come in a later replay, once you know it. - A new subject for the badge closes the assignment still open at the new
valid_from, then opens the new one. Handing a badge over is a single line. - Anything else that overlaps an existing window is rejected as
overlapping_assignment, line by line.
Month 1: the badge is in P-4582’s pocket
{
"assignments": [
{ "credential": "04A2B9C1", "subject": "P-4582", "valid_from": "2026-01-01T00:00:00+01:00" }
]
}
Month 9: handed over — P-4582’s assignment ends where P-7781’s begins
{
"assignments": [
{ "credential": "04A2B9C1", "subject": "P-4582", "valid_from": "2026-01-01T00:00:00+01:00", "valid_to": "2026-09-01T00:00:00+02:00" },
{ "credential": "04A2B9C1", "subject": "P-7781", "valid_from": "2026-09-01T00:00:00+02:00" }
]
}
The second line alone would do the same: P-4582's open assignment ends at P-7781's start. The window is half-open — valid_to is excluded — so one binding ending at the exact instant the next one starts is not an overlap.
Historical reports keep pointing at the subject who actually held the badge at the time. That is the entire reason assignments carry dates instead of being a simple foreign key.