52bf0279Introduce exact roster#
| Property | Value |
|---|---|
| Service | crossfire |
| Operation | introduceEnrollment |
| Method | POST |
| Path | /api/enrollments |
| Authentication | public |
| Success status | 201 |
| Response data | Unpaginated value |
| Request format | json |
| Maximum request body | 2097152 bytes (service default) |
| Permission codes | None declared |
Listed permission codes are alternatives, not token scopes. The service also checks access to the requested records and rejects stale revisions or controller generations.
Path parameters#
empty object; unknown fields rejected
Validation#
check.emptyReferenced definitions:
Query parameters#
custom validation:
none
; see function below
Query parameters are URL text. The validation function below specifies their format, defaults and combinations. Pagination applies only to operations that use it.
Additional checks#
The following checks apply in addition to the field limits.
Constraint on value:
export function none(input: unknown) {
const parsed = listQuery([])(input);
return parsed.ok ? success({}) : parsed;
}Validation#
query.noneReferenced definitions:
Request body#
object; fields below; unknown fields rejected (
enrollment
)
| Field path | Representation and constraints |
|---|---|
controller | object; fields below; unknown fields rejected (
controller
) |
controller.name | string; 1–100 UTF-16 units; well-formed Unicode; no C0/DEL controls |
controller.metadata | custom validation:
metadata
; see function below; optional property |
controllerCredential | string; 1–200 UTF-16 units; well-formed Unicode; no C0/DEL controls; optional property |
ownerMatrixId | well-formed Matrix user ID; maximum 255 UTF-16 units |
fleetKey | lowercase name; pattern [a-z][a-z0-9-]{0,39} |
instances | array; 1–100 entries; item: object; fields below; unknown fields rejected (
instance
) |
instances[].instanceKey | lowercase name; pattern [a-z][a-z0-9-]{0,39} |
instances[].name | lowercase name; pattern [a-z][a-z0-9-]{0,39} |
instances[].identity | object; fields below; unknown fields rejected (
accountProof
); optional property |
instances[].identity.agentId | lowercase opaque UUID |
instances[].identity.accessToken | string; 1–8192 UTF-16 units; well-formed Unicode; no C0/DEL controls |
instances[].coordinationPolicy | object; fields below; unknown fields rejected; constraint: Select unique identities; everyone requires no individual selections (
coordinationPolicy
) |
instances[].coordinationPolicy.wakeMode | validator choice('selected', 'humans', 'everyone') (
wakeMode
) |
instances[].coordinationPolicy.senders | array; 0–2000 entries; item: object; fields below; unknown fields rejected (
matrixWakeSelection
) |
instances[].coordinationPolicy.senders[].matrixUserId | well-formed Matrix user ID; maximum 255 UTF-16 units |
instances[].coordinationPolicy.senders[].includeAgents | boolean |
instances[].coordinationPolicy.permissions | array; 0–1 entries; item: room.agent.invite |
enrollmentId | lowercase opaque UUID |
claimSecret | 43-character base64url private claim (32 bytes) |
Additional checks#
The following checks apply in addition to the field limits.
Constraint on controller.metadata:
function metadata(input: unknown): Result<Record<string, string>> {
if (!input || typeof input !== 'object' || Array.isArray(input) || Object.keys(input).length > 16)
return failure('invalid', 'Controller metadata supports at most 16 text fields');
const output: Record<string, string> = {};
for (const [key, value] of Object.entries(input)) {
if (!/^[a-z][a-z0-9-]{0,39}$/u.test(key) || !check.text(256, 0)(value).ok || typeof value !== 'string')
return failure('invalid', 'Invalid controller metadata');
output[key] = value;
}
return success(output);
}Constraint on instances[].coordinationPolicy:
policy => (policy.wakeMode !== 'everyone' || policy.senders.length === 0)
&& new Set(policy.senders.map(sender => sender.matrixUserId)).size === policy.senders.lengthValidation#
req.enrollmentReferenced definitions:
Response data#
object; fields below; unknown fields rejected (
enrollmentIntroduction
)
| Field path | Representation and constraints |
|---|---|
enrollment | object; fields below; unknown fields rejected (
enrollmentDetails
) |
enrollment.enrollment | object; fields below; unknown fields rejected (
enrollment
) |
enrollment.enrollment.owner | object; fields below; unknown fields rejected (
principal
) |
enrollment.enrollment.owner.principalId | lowercase opaque UUID |
enrollment.enrollment.owner.matrixUserId | well-formed Matrix user ID; maximum 255 UTF-16 units |
enrollment.enrollment.owner.kind | human or agent |
enrollment.enrollment.owner.displayName | string; 1–255 UTF-16 units; well-formed Unicode; no C0/DEL controls |
enrollment.enrollment.owner.ownerId | lowercase opaque UUID |
enrollment.enrollment.owner.ownerMatrixId | well-formed Matrix user ID; maximum 255 UTF-16 units |
enrollment.enrollment.controllerName | string; 1–100 UTF-16 units; well-formed Unicode; no C0/DEL controls |
enrollment.enrollment.enrollmentId | lowercase opaque UUID |
enrollment.enrollment.ownerId | lowercase opaque UUID |
enrollment.enrollment.fleetKey | lowercase name; pattern [a-z][a-z0-9-]{0,39} |
enrollment.enrollment.verificationCode | string; 12–12 UTF-16 units; well-formed Unicode; no C0/DEL controls |
enrollment.enrollment.status | pending or approved or rejected or expired |
enrollment.enrollment.revision | exact JSON integer; 0…9007199254740991 |
enrollment.enrollment.createdAt | exact JSON integer; 0…9007199254740991 |
enrollment.enrollment.expiresAt | exact JSON integer; 0…9007199254740991 |
enrollment.enrollment.decidedByMemberId | lowercase opaque UUID; JSON null permitted |
enrollment.enrollment.decidedAt | exact JSON integer; 0…9007199254740991; JSON null permitted |
enrollment.instances | array; 0–100 entries; item: object; fields below; unknown fields rejected (
enrollmentItem
) |
enrollment.instances[].instanceKey | lowercase name; pattern [a-z][a-z0-9-]{0,39} |
enrollment.instances[].requestedName | lowercase name; pattern [a-z][a-z0-9-]{0,39} |
enrollment.instances[].currentName | lowercase name; pattern [a-z][a-z0-9-]{0,39}; JSON null permitted |
enrollment.instances[].outcome | claimed or existing |
enrollment.instances[].agentId | lowercase opaque UUID; JSON null permitted |
enrollment.instances[].coordinationPolicy | object; fields below; unknown fields rejected; constraint: Select unique identities; everyone requires no individual selections (
coordinationPolicy
) |
enrollment.instances[].coordinationPolicy.wakeMode | validator choice('selected', 'humans', 'everyone') (
wakeMode
) |
enrollment.instances[].coordinationPolicy.senders | array; 0–2000 entries; item: object; fields below; unknown fields rejected (
matrixWakeSelection
) |
enrollment.instances[].coordinationPolicy.senders[].matrixUserId | well-formed Matrix user ID; maximum 255 UTF-16 units |
enrollment.instances[].coordinationPolicy.senders[].includeAgents | boolean |
enrollment.instances[].coordinationPolicy.permissions | array; 0–1 entries; item: room.agent.invite |
approvalUrl | string; 1–2048 UTF-16 units; well-formed Unicode; no C0/DEL controls |
Additional checks#
The following checks apply in addition to the field limits.
Constraint on enrollment.instances[].coordinationPolicy:
policy => (policy.wakeMode !== 'everyone' || policy.senders.length === 0)
&& new Set(policy.senders.map(sender => sender.matrixUserId)).size === policy.senders.lengthValidation#
res.enrollmentIntroductionReferenced definitions:
Response envelope#
A successful JSON response contains data and meta. Replace the data placeholder below with the response fields described above. Errors contain error instead of data.
{
"data": "<value matching the response-data validator>",
"meta": {
"requestId": "00000000-0000-0000-0000-000000000001"
}
}