Event Catalog
Reference documentation for SmartphoneKey EventBridge events available to partners.
This catalog lists every event a partner can subscribe to. For each event you will find the source, when it fires, and the fields of its payload.
For how to subscribe and receive them, see Partner Webhooks.
All spk.api events share the same envelope structure. The domain payload is wrapped in a detail object that carries projection metadata plus the original event under data:
{
"source": "spk.api",
"detail-type": "<EventName>",
"detail": {
"partnerId": "<your-orgId>",
"aggregateType": "<LockAggregate|UserAggregate|HubAggregate|...>",
"aggregateId": "<aggregate id>",
"version": 7,
"timestamp": 1745922600123,
"data": { /* event-specific payload — see below */ }
}
}
detail.timestamp is the projection time as epoch milliseconds (a number). The ISO-8601 timestamp inside detail.data.timestamp is the domain-event time. The fields documented below describe detail.data — the actual domain event.
Lock events
LockCreated
| Source | spk.api |
| detail-type | LockCreated |
| aggregateType | LockAggregate |
A new lock has been created in the system.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
lockId | number | yes | Numeric lock ID |
uuid | string | yes | Lock UUID |
serialNumber | string | no | Hardware serial number |
keys | object[] | no | Initial key list |
keys[].uuid | string | yes | Key UUID |
keys[].indexNumber | number | no | Key slot index |
keys[].userId | string | no | User the key is assigned to |
ownerId | string | no | Owning user ID |
timestamp | string | yes | ISO-8601 time of the domain event |
thingName | string | no | AWS IoT thing name |
thingArn | string | no | AWS IoT thing ARN |
OwnerSet
| Source | spk.api |
| detail-type | OwnerSet |
| aggregateType | LockAggregate |
A lock's owner has been assigned or changed.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
lockId | number | yes | Numeric lock ID |
uuid | string | yes | Lock UUID |
timestamp | string | yes | ISO-8601 time of the domain event |
userId | string | yes | New owner user ID |
OrganizationSet
| Source | spk.api |
| detail-type | OrganizationSet |
| aggregateType | LockAggregate |
A lock has been moved to a different organization.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
lockId | number | yes | Numeric lock ID |
uuid | string | yes | Lock UUID |
timestamp | string | yes | ISO-8601 time of the domain event |
orgId | string | yes | Organization ID |
KeyAdded
| Source | spk.api |
| detail-type | KeyAdded |
| aggregateType | LockAggregate |
A physical key has been added to a lock.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
lockId | number | yes | Numeric lock ID |
uuid | string | yes | Lock UUID |
timestamp | string | yes | ISO-8601 time of the domain event |
keyUuid | string | yes | UUID of the key |
keyIndexNumber | number | no | Key slot index |
userId | string | no | User the key is assigned to |
messageId | string | no | |
requestedAt | number | no |
KeyRemoved
| Source | spk.api |
| detail-type | KeyRemoved |
| aggregateType | LockAggregate |
A physical key has been removed from a lock.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
lockId | number | yes | Numeric lock ID |
uuid | string | yes | Lock UUID |
timestamp | string | yes | ISO-8601 time of the domain event |
keyUuid | string | yes | UUID of the removed key |
keyIndexNumber | number | no | Key slot index |
messageId | string | no | |
requestedAt | number | no |
ResidentAdded
| Source | spk.api |
| detail-type | ResidentAdded |
| aggregateType | LockAggregate |
A resident has been granted access to a lock.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
lockId | number | yes | Numeric lock ID |
uuid | string | yes | Lock UUID |
timestamp | string | yes | ISO-8601 time of the domain event |
userId | string | yes | Resident user ID (resolved from the email) |
name | string | yes | Resident display name |
email | string | no | Resident email |
ResidentRemoved
| Source | spk.api |
| detail-type | ResidentRemoved |
| aggregateType | LockAggregate |
A resident's access to a lock has been revoked.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
lockId | number | yes | Numeric lock ID |
uuid | string | yes | Lock UUID |
timestamp | string | yes | ISO-8601 time of the domain event |
userId | string | yes | Resident user ID |
email | string | no | Resident email |
LockUuidChanged
| Source | spk.api |
| detail-type | LockUuidChanged |
| aggregateType | LockAggregate |
A lock's UUID has been replaced.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
lockId | number | yes | Numeric lock ID |
uuid | string | yes | Lock UUID |
timestamp | string | yes | ISO-8601 time of the domain event |
newUuid | string | yes | |
previousUuid | string | yes |
LockOpenRequested
| Source | spk.api |
| detail-type | LockOpenRequested |
| aggregateType | LockAggregate |
An unlock command was delivered to the lock.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
lockId | number | yes | Numeric lock ID |
uuid | string | yes | Lock UUID |
timestamp | string | yes | ISO-8601 time of the domain event |
reason | string | no | |
requestId | string | no | |
messageId | string | no | |
requestedAt | number | no |
LockOpenConfirmed
| Source | spk.api |
| detail-type | LockOpenConfirmed |
| aggregateType | LockAggregate |
The lock reported that an unlock was carried out.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
lockId | number | yes | Numeric lock ID |
uuid | string | yes | Lock UUID |
timestamp | string | yes | ISO-8601 time of the domain event |
messageId | string | yes | |
requestId | string | no | |
attempts | number | yes | |
latencyMs | number | yes |
LockOpenUnconfirmed
| Source | spk.api |
| detail-type | LockOpenUnconfirmed |
| aggregateType | LockAggregate |
An unlock was sent but the lock did not confirm the bolt moved, or did not answer in time.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
lockId | number | yes | Numeric lock ID |
uuid | string | yes | Lock UUID |
timestamp | string | yes | ISO-8601 time of the domain event |
messageIds | string[] | yes | |
requestId | string | no | |
attempts | number | yes | |
reason | "refused" | "no-state-change" | "no-ack" | yes | |
errorCode | number | string | no | |
detail | string | no |
KeyWriteRequested
| Source | spk.api |
| detail-type | KeyWriteRequested |
| aggregateType | LockAggregate |
A key write to physical NFC hardware was requested.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
lockId | number | yes | Numeric lock ID |
uuid | string | yes | Lock UUID |
timestamp | string | yes | ISO-8601 time of the domain event |
keyUuid | string | yes | |
keyIndexNumber | number | no |
LockIvrCallCompleted
| Source | spk.api |
| detail-type | LockIvrCallCompleted |
| aggregateType | LockAggregate |
An IVR call to a resident about this lock ended (telephony-api). Delivered at least once — deduplicate on callId.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
lockId | number | yes | Numeric lock ID |
uuid | string | yes | Lock UUID |
timestamp | string | yes | ISO-8601 time of the domain event |
callId | string | yes | The calling client's call id; the same call may be delivered twice |
userId | string | yes | Resident called (user ID); the phone number is never carried, not even masked |
status | "opened" | "denied" | "timeout" | "no_answer" | "busy" | "failed" | "ended" | yes | Final call status: opened, denied, timeout, no_answer, busy, failed or ended |
result | "open_failed" | "dial_failed" | "guest_not_connected" | "talk_limit" | "hangup_client" | "hangup_resident" | "provider_error" | null | yes | For failed / ended: open_failed, dial_failed, guest_not_connected, talk_limit, hangup_client, hangup_resident or provider_error; otherwise null |
choice | "0" | "1" | "9" | null | yes | Key the resident pressed: 9 open, 0 refuse, 1 talk; null when none |
provider | string | yes | Telephony provider that carried the call |
country | string | null | yes | ISO-3166 alpha-2 of the resident's number; null when unknown |
language | string | yes | Language the menu was played in |
createdAt | string | yes | ISO-8601 time the call was ordered |
answeredAt | string | no | ISO-8601 time the resident answered; absent when nobody answered |
endedAt | string | yes | ISO-8601 time the call reached its final status |
durationSecs | number | yes | Seconds from answer to end; 0 when nobody answered |
Temporary key events
TempKeyCreated
| Source | spk.api |
| detail-type | TempKeyCreated |
| aggregateType | LockAggregate |
Deprecated: a temporary key has been issued through a per-lock route.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
tempKeyUuid | string | yes | |
lockId | number | yes | Numeric lock ID |
lockUuid | string | yes | |
accessMode | "public" | "user-whitelist" | yes | |
allowedUserIds | string[] | no | |
validFrom | string | yes | |
validUntil | string | yes | |
maxUses | number | null | no | |
createdBy | string | yes | |
timestamp | string | yes | ISO-8601 time of the domain event |
TempKeyUsed
| Source | spk.api |
| detail-type | TempKeyUsed |
| aggregateType | LockAggregate |
Deprecated: a temporary key has been used to unlock (see TempKeyDoorOpened).
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
tempKeyUuid | string | yes | |
lockId | number | yes | Numeric lock ID |
lockUuid | string | yes | |
userId | string | no | User ID |
usedCount | number | yes | |
timestamp | string | yes | ISO-8601 time of the domain event |
TempKeyDeleted
| Source | spk.api |
| detail-type | TempKeyDeleted |
| aggregateType | LockAggregate |
Deprecated: a temporary key has been deleted through a per-lock route.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
tempKeyUuid | string | yes | |
lockId | number | yes | Numeric lock ID |
lockUuid | string | yes | |
deletedBy | string | yes | |
timestamp | string | yes | ISO-8601 time of the domain event |
TempKeyUpdated
| Source | spk.api |
| detail-type | TempKeyUpdated |
| aggregateType | LockAggregate |
Deprecated: a temporary key's rules changed through a per-lock route.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
tempKeyUuid | string | yes | |
lockId | number | yes | Numeric lock ID |
lockUuid | string | yes | |
changes | object | yes | |
changes.validFrom | string | no | |
changes.validUntil | string | no | |
changes.maxUses | number | null | no | |
changes.allowedUserIds | string[] | no | |
changes.accessMode | "public" | "user-whitelist" | no | |
updatedBy | string | yes | |
timestamp | string | yes | ISO-8601 time of the domain event |
TempKeyIssued
| Source | spk.api |
| detail-type | TempKeyIssued |
| aggregateType | TempKeyAggregate |
A temporary key has been issued for one or more doors.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
tempKeyUuid | string | yes | Temporary key UUID (also the aggregateId) |
issuedBy | string | yes | Organization or user ID that issued the key |
origin | "temp-keys" | "per-lock" | "import" | yes | 'temp-keys' (the key routes), 'per-lock' (a deprecated per-lock route) or 'import' (moved from b2c-api) |
key | object | yes | |
key.doors | object[] | yes | |
key.doors[].doorId | number | yes | Stable door id within the key (guest pages address doors by it) |
key.doors[].lockId | number | yes | Numeric ID of the lock the door opens |
key.doors[].lockUuid | string | yes | UUID of the lock the door opens |
key.doors[].accessMethod | "key" | "code" | "both" | yes | How a guest opens the door: 'key' (guest page), 'code' (entrance-panel PIN) or 'both' |
key.doors[].sortOrder | number | yes | |
key.validFrom | string | yes | |
key.validUntil | string | yes | |
key.accessMode | "public" | "user-whitelist" | yes | 'public' (anyone with the link or PIN) or 'user-whitelist' (only allowedUserIds) |
key.allowedUserIds | string[] | yes | |
key.maxUses | number | null | yes | Total opens the key allows across all its doors; null = unlimited |
key.usedCount | number | yes | Opens so far |
key.pinIssued | boolean | yes | True when the key has an entrance-panel PIN; the PIN itself is never sent |
key.createdBy | string | yes | |
key.createdAt | string | yes | |
key.revokedAt | string | null | yes | When the key was revoked; null while it is not |
timestamp | string | yes | ISO-8601 time of the domain event |
TempKeyChanged
| Source | spk.api |
| detail-type | TempKeyChanged |
| aggregateType | TempKeyAggregate |
A temporary key's validity, limit, access or guest instructions changed.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
tempKeyUuid | string | yes | Temporary key UUID (also the aggregateId) |
changed | "validFrom" | "validUntil" | "maxUses" | "accessMode" | "allowedUserIds" | "description"[] | yes | The fields that changed; 'description' names the guest instructions, whose text is never sent |
changedBy | string | yes | Organization or user ID that made the change |
key | object | yes | |
key.doors | object[] | yes | |
key.doors[].doorId | number | yes | Stable door id within the key (guest pages address doors by it) |
key.doors[].lockId | number | yes | Numeric ID of the lock the door opens |
key.doors[].lockUuid | string | yes | UUID of the lock the door opens |
key.doors[].accessMethod | "key" | "code" | "both" | yes | How a guest opens the door: 'key' (guest page), 'code' (entrance-panel PIN) or 'both' |
key.doors[].sortOrder | number | yes | |
key.validFrom | string | yes | |
key.validUntil | string | yes | |
key.accessMode | "public" | "user-whitelist" | yes | 'public' (anyone with the link or PIN) or 'user-whitelist' (only allowedUserIds) |
key.allowedUserIds | string[] | yes | |
key.maxUses | number | null | yes | Total opens the key allows across all its doors; null = unlimited |
key.usedCount | number | yes | Opens so far |
key.pinIssued | boolean | yes | True when the key has an entrance-panel PIN; the PIN itself is never sent |
key.createdBy | string | yes | |
key.createdAt | string | yes | |
key.revokedAt | string | null | yes | When the key was revoked; null while it is not |
timestamp | string | yes | ISO-8601 time of the domain event |
TempKeyRevoked
| Source | spk.api |
| detail-type | TempKeyRevoked |
| aggregateType | TempKeyAggregate |
A temporary key has been revoked; none of its doors open with it any more.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
tempKeyUuid | string | yes | Temporary key UUID (also the aggregateId) |
revokedBy | string | yes | Organization or user ID that revoked the key |
key | object | yes | |
key.doors | object[] | yes | |
key.doors[].doorId | number | yes | Stable door id within the key (guest pages address doors by it) |
key.doors[].lockId | number | yes | Numeric ID of the lock the door opens |
key.doors[].lockUuid | string | yes | UUID of the lock the door opens |
key.doors[].accessMethod | "key" | "code" | "both" | yes | How a guest opens the door: 'key' (guest page), 'code' (entrance-panel PIN) or 'both' |
key.doors[].sortOrder | number | yes | |
key.validFrom | string | yes | |
key.validUntil | string | yes | |
key.accessMode | "public" | "user-whitelist" | yes | 'public' (anyone with the link or PIN) or 'user-whitelist' (only allowedUserIds) |
key.allowedUserIds | string[] | yes | |
key.maxUses | number | null | yes | Total opens the key allows across all its doors; null = unlimited |
key.usedCount | number | yes | Opens so far |
key.pinIssued | boolean | yes | True when the key has an entrance-panel PIN; the PIN itself is never sent |
key.createdBy | string | yes | |
key.createdAt | string | yes | |
key.revokedAt | string | null | yes | When the key was revoked; null while it is not |
timestamp | string | yes | ISO-8601 time of the domain event |
TempKeyDoorOpened
| Source | spk.api |
| detail-type | TempKeyDoorOpened |
| aggregateType | TempKeyAggregate |
A door has been opened with a temporary key.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
tempKeyUuid | string | yes | Temporary key UUID (also the aggregateId) |
doorId | number | yes | The door of the key that opened |
lockId | number | yes | Numeric ID of the lock the door opens |
lockUuid | string | yes | UUID of the lock the door opens |
method | "slide" | "pin" | yes | 'slide' (guest page) or 'pin' (entrance panel) |
openedBy | string | null | yes | User ID of a signed-in guest; null for an anonymous guest page or a PIN |
key | object | yes | |
key.doors | object[] | yes | |
key.doors[].doorId | number | yes | Stable door id within the key (guest pages address doors by it) |
key.doors[].lockId | number | yes | Numeric ID of the lock the door opens |
key.doors[].lockUuid | string | yes | UUID of the lock the door opens |
key.doors[].accessMethod | "key" | "code" | "both" | yes | How a guest opens the door: 'key' (guest page), 'code' (entrance-panel PIN) or 'both' |
key.doors[].sortOrder | number | yes | |
key.validFrom | string | yes | |
key.validUntil | string | yes | |
key.accessMode | "public" | "user-whitelist" | yes | 'public' (anyone with the link or PIN) or 'user-whitelist' (only allowedUserIds) |
key.allowedUserIds | string[] | yes | |
key.maxUses | number | null | yes | Total opens the key allows across all its doors; null = unlimited |
key.usedCount | number | yes | Opens so far |
key.pinIssued | boolean | yes | True when the key has an entrance-panel PIN; the PIN itself is never sent |
key.createdBy | string | yes | |
key.createdAt | string | yes | |
key.revokedAt | string | null | yes | When the key was revoked; null while it is not |
timestamp | string | yes | ISO-8601 time of the domain event |
User events
UserCreated
| Source | spk.api |
| detail-type | UserCreated |
| aggregateType | UserAggregate |
A new user has been registered.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
userId | string | yes | User ID |
status | "ACTIVE" | "INACTIVE" | "SUSPENDED" | yes |
ProfileUpdated
| Source | spk.api |
| detail-type | ProfileUpdated |
| aggregateType | UserAggregate |
A user's profile fields have changed.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
userId | string | yes | User ID |
changes | object | yes | |
changes.firstName | object | no | |
changes.firstName.old | string | yes | |
changes.firstName.new | string | yes | |
changes.lastName | object | no | |
changes.lastName.old | string | yes | |
changes.lastName.new | string | yes | |
changes.phoneNumber | object | no | |
changes.phoneNumber.old | string | no | |
changes.phoneNumber.new | string | no |
UserPhoneNumberUpdated
| Source | spk.api |
| detail-type | UserPhoneNumberUpdated |
| aggregateType | UserAggregate |
A user's phone number has changed (only the masked number is carried).
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
userId | string | yes | User ID |
action | "set" | "removed" | yes | |
maskedPhoneNumber | string | no | Obfuscated number (last 4 digits, e.g. "***4567") — present only when action is "set" |
timestamp | string | yes | ISO-8601 time of the domain event |
UserEmailUpdated
| Source | spk.api |
| detail-type | UserEmailUpdated |
| aggregateType | UserAggregate |
A user's email address has changed.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
userId | string | yes | User ID |
action | "set" | "removed" | yes | |
maskedEmail | string | no | Obfuscated email (first initial + domain, e.g. "a***@example.com") — present only when action is "set" |
timestamp | string | yes | ISO-8601 time of the domain event |
PhysicalKeyAdded
| Source | spk.api |
| detail-type | PhysicalKeyAdded |
| aggregateType | UserAggregate |
A physical key has been issued to a user.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
userId | string | yes | User ID |
number | number | yes | Key number |
orgId | string | yes | Issuing organization |
orgName | string | no | Organization display name |
note | string | no | Free-form note |
addedAt | number | yes | Unix epoch ms |
PhysicalKeyRemoved
| Source | spk.api |
| detail-type | PhysicalKeyRemoved |
| aggregateType | UserAggregate |
A physical key has been removed from a user.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
userId | string | yes | User ID |
number | number | yes | Key number |
removedAt | number | yes | Unix epoch ms |
WalletKeyPrepared
| Source | spk.api |
| detail-type | WalletKeyPrepared |
| aggregateType | UserAggregate |
A wallet key (Apple/Google) is being provisioned.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
userId | string | yes | User ID |
keyId | string | yes | |
walletType | "APPLE" | "GOOGLE" | yes | |
keyIndex | number | no | |
deviceId | string | no | Device UUID |
orgId | string | null | no | Organization ID |
WalletKeyCommitted
| Source | spk.api |
| detail-type | WalletKeyCommitted |
| aggregateType | UserAggregate |
A wallet key has been issued and the pass is available.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
userId | string | yes | User ID |
keyId | string | yes | |
keyIndex | number | no | |
walletType | "APPLE" | "GOOGLE" | no | |
deviceId | string | no | Device UUID |
passId | string | yes | |
passUrl | string | yes | |
committedAt | string | yes |
WalletKeyRolledBack
| Source | spk.api |
| detail-type | WalletKeyRolledBack |
| aggregateType | UserAggregate |
A wallet key provisioning attempt was rolled back.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
userId | string | yes | User ID |
preparedKeyId | string | yes | |
reason | string | yes | |
rolledBackAt | string | yes |
WalletKeyRemoved
| Source | spk.api |
| detail-type | WalletKeyRemoved |
| aggregateType | UserAggregate |
A wallet key has been removed from a user.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
userId | string | yes | User ID |
keyId | string | yes | |
reason | string | yes | |
removedAt | string | yes | Unix epoch ms |
WalletKeyOrgAssigned
| Source | spk.api |
| detail-type | WalletKeyOrgAssigned |
| aggregateType | UserAggregate |
An admin assigned a wallet key to its issuing organization.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
userId | string | yes | User ID |
keyId | string | yes | |
orgId | string | yes | Organization the key now belongs to |
previousOrgId | string | null | no | Organization it belonged to before, if any |
auditId | string | yes |
AccessibleLockAdded
| Source | spk.api |
| detail-type | AccessibleLockAdded |
| aggregateType | UserAggregate |
A user has been granted access to a lock.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
userId | string | yes | User ID |
lockId | string | yes | Lock UUID |
lockName | string | yes | Lock display name |
accessLevel | "OWNER" | "ADMIN" | "USER" | "GUEST" | yes | |
grantedBy | string | yes | User ID who granted access |
AccessibleLockRemoved
| Source | spk.api |
| detail-type | AccessibleLockRemoved |
| aggregateType | UserAggregate |
A user has lost access to a lock.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
userId | string | yes | User ID |
lockId | string | yes | Numeric lock ID |
removedBy | string | yes | |
reason | string | yes | |
removedAt | string | yes | Unix epoch ms |
UserSuspended
| Source | spk.api |
| detail-type | UserSuspended |
| aggregateType | UserAggregate |
A user has been suspended.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
userId | string | yes | User ID |
reason | string | yes | |
suspendedBy | string | yes | |
suspendedAt | string | yes |
UserReactivated
| Source | spk.api |
| detail-type | UserReactivated |
| aggregateType | UserAggregate |
A previously suspended user has been reactivated.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
userId | string | yes | User ID |
reactivatedBy | string | yes | |
reactivatedAt | string | yes |
WalletKeyAdded
| Source | spk.api |
| detail-type | WalletKeyAdded |
| aggregateType | UserAggregate |
A wallet key was added (legacy single-step path).
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
userId | string | yes | User ID |
walletKey | object | yes | |
walletKey.keyId | string | yes | |
walletKey.keyIndex | number | yes | |
walletKey.walletType | "APPLE" | "GOOGLE" | yes | |
walletKey.deviceId | string | yes | |
walletKey.passUrl | string | no | |
walletKey.serialNumber | string | no | |
walletKey.addedAt | string | yes |
LicensePlateAdded
| Source | spk.api |
| detail-type | LicensePlateAdded |
| aggregateType | UserAggregate |
A license plate has been registered to a user.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
userId | string | yes | User ID |
plate | string | yes | License plate string |
label | string | yes | Friendly label |
addedAt | number | yes | Unix epoch ms |
LicensePlateRemoved
| Source | spk.api |
| detail-type | LicensePlateRemoved |
| aggregateType | UserAggregate |
A license plate has been removed from a user.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
userId | string | yes | User ID |
plate | string | yes |
DeviceAdded
| Source | spk.api |
| detail-type | DeviceAdded |
| aggregateType | UserAggregate |
A device has been linked to a user.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
userId | string | yes | User ID |
deviceId | string | yes | Device UUID |
deviceType | "matter" | "camera" | "rtsp-camera" | yes | |
orgId | string | yes | Organization ID |
name | string | no | |
addedBy | string | no | |
addedAt | string | yes | Unix epoch ms |
DeviceRemoved
| Source | spk.api |
| detail-type | DeviceRemoved |
| aggregateType | UserAggregate |
A device has been unlinked from a user.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
userId | string | yes | User ID |
deviceId | string | yes | Device UUID |
deviceType | "matter" | "camera" | "rtsp-camera" | yes | |
removedBy | string | yes | |
reason | string | yes | |
removedAt | string | yes | Unix epoch ms |
DevicePushMutedUpdated
| Source | spk.api |
| detail-type | DevicePushMutedUpdated |
| aggregateType | UserAggregate |
A user muted or unmuted alarm push notifications for one of their devices.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
userId | string | yes | User ID |
deviceId | string | yes | Device UUID |
muted | boolean | yes | |
timestamp | string | yes | ISO-8601 time of the domain event |
CallToOpenLockChosen
| Source | spk.api |
| detail-type | CallToOpenLockChosen |
| aggregateType | UserAggregate |
Locks or Matter devices were chosen to open when the user calls the call-to-open number, each on its own digit; replaces the previous choice whole; a preference, not an access grant.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
userId | string | yes | User ID |
target | object | yes | The chosen target on the lowest digit ({kind, id}) |
target.kind | "lock" | "matter" | yes | Which of the user's lists the id is in: lock (accessible locks) or matter (Matter devices) |
target.id | string | yes | A lock aggregate id or a Matter device id, never a phone number |
targets | object[] | no | Every chosen target with the digit that picks it ({kind, id, digit}), ordered by digit; absent on an event written before a choice held several, whose one target is on 1 |
targets[].kind | "lock" | "matter" | yes | Which of the user's lists the id is in: lock (accessible locks) or matter (Matter devices) |
targets[].id | string | yes | A lock aggregate id or a Matter device id, never a phone number |
targets[].digit | string | yes | The key that picks this target in a call: one digit, 0-9, unique within the choice |
chosenBy | object | yes | |
chosenBy.kind | "user" | "organization" | yes | user for the user themselves, organization for an API key |
chosenBy.orgId | string | null | yes | The API key's organization; null when the user acted themselves |
timestamp | string | yes | ISO-8601 time of the domain event |
CallToOpenLockCleared
| Source | spk.api |
| detail-type | CallToOpenLockCleared |
| aggregateType | UserAggregate |
The user's call-to-open choice was cleared whole by a ClearCallToOpenLock command; removing a chosen lock or device from the user's lists drops that target from the choice, without this event.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
userId | string | yes | User ID |
previousTarget | object | yes | The cleared target on the lowest digit ({kind, id}) |
previousTarget.kind | "lock" | "matter" | yes | Which of the user's lists the id is in: lock (accessible locks) or matter (Matter devices) |
previousTarget.id | string | yes | A lock aggregate id or a Matter device id, never a phone number |
previousTargets | object[] | no | Every cleared target with its digit ({kind, id, digit}), ordered by digit; absent on an event written before a choice held several |
previousTargets[].kind | "lock" | "matter" | yes | Which of the user's lists the id is in: lock (accessible locks) or matter (Matter devices) |
previousTargets[].id | string | yes | A lock aggregate id or a Matter device id, never a phone number |
previousTargets[].digit | string | yes | The key that picks this target in a call: one digit, 0-9, unique within the choice |
clearedBy | object | yes | |
clearedBy.kind | "user" | "organization" | yes | user for the user themselves, organization for an API key |
clearedBy.orgId | string | null | yes | The API key's organization; null when the user acted themselves |
timestamp | string | yes | ISO-8601 time of the domain event |
CallToOpenCallRecorded
| Source | spk.api |
| detail-type | CallToOpenCallRecorded |
| aggregateType | UserAggregate |
A call from the user's own phone number was admitted to open the user's call-to-open choice (the lock open is requested next and may still fail; LockOpenRequested on the lock is the open itself); written only for an admitted call, never for a refused one, and without the phone number; an admitted call counts towards the user's call-to-open rate limit and repeated-call check even when its open then fails.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
userId | string | yes | User ID |
callId | string | yes | Opaque id of the call; also the requestId of the LockOpenRequested it caused |
target | object | yes | The chosen lock or Matter device the call was admitted to open ({kind, id}) |
target.kind | "lock" | "matter" | yes | Which of the user's lists the id is in: lock (accessible locks) or matter (Matter devices) |
target.id | string | yes | A lock aggregate id or a Matter device id, never a phone number |
digit | string | no | The digit the caller pressed in the call's menu to pick the target; absent when the call named none (a choice of one target) |
timestamp | string | yes | ISO-8601 time of the domain event |
UserSubscriptionStatusUpdated
| Source | spk.api |
| detail-type | UserSubscriptionStatusUpdated |
| aggregateType | UserAggregate |
An organization's subscription status entry for a user changed (mobile app access); carries only the changed fields (delivered only to the organization whose entry changed).
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
userId | string | yes | User ID |
orgId | string | yes | The organization whose entry changed; the delivery's detail.partnerId is the same id |
changes | object | yes | Only the entitlements that changed, e.g. mobileAppAccess |
changes.mobileAppAccess | boolean | no | Whether the user may use the mobile app for this organization; an app entitlement, not door access |
changedBy | object | yes | Who made the change: kind organization (that organization's own API key) or super (an administrator acting for it) |
changedBy.kind | "organization" | "super" | yes | organization for that organization's own API key, super for an administrator acting for it |
timestamp | string | yes | ISO-8601 time of the domain event |
Hub events
HubProvisioned
| Source | spk.api |
| detail-type | HubProvisioned |
| aggregateType | HubAggregate |
A hub has been provisioned (manufactured / known to the system).
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
hubId | string | yes | Hub UUID |
serial | string | yes | Hardware serial |
model | string | yes | Hardware model |
thingName | string | yes | AWS IoT thing name |
vendorName | string | no | |
provisionedAt | number | yes | Unix epoch ms |
HubClaimed
| Source | spk.api |
| detail-type | HubClaimed |
| aggregateType | HubAggregate |
A hub has been claimed by an organization and site.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
hubId | string | yes | Hub UUID |
orgId | string | yes | Claiming organization |
siteId | string | yes | Site the hub is installed at |
claimedBy | string | yes | User ID who claimed it |
claimedAt | number | yes | Unix epoch ms |
HubReClaimed
| Source | spk.api |
| detail-type | HubReClaimed |
| aggregateType | HubAggregate |
A hub has been moved from one organization/site to another.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
hubId | string | yes | Hub UUID |
previousOrgId | string | yes | |
previousSiteId | string | yes | |
newOrgId | string | yes | |
newSiteId | string | yes | |
reclaimedBy | string | yes | |
reason | string | yes | |
reclaimedAt | number | yes |
HubRoleSet
| Source | spk.api |
| detail-type | HubRoleSet |
| aggregateType | HubAggregate |
A hub's primary/secondary role has been set.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
hubId | string | yes | Hub UUID |
isPrimary | boolean | yes | |
setBy | string | yes | |
setAt | number | yes |
HubSuspended
| Source | spk.api |
| detail-type | HubSuspended |
| aggregateType | HubAggregate |
A hub has been suspended.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
hubId | string | yes | Hub UUID |
reason | string | yes | |
suspendedBy | string | yes | |
suspendedAt | number | yes |
HubDecommissioned
| Source | spk.api |
| detail-type | HubDecommissioned |
| aggregateType | HubAggregate |
A hub has been decommissioned.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
hubId | string | yes | Hub UUID |
reason | string | yes | |
decommissionedBy | string | yes | |
decommissionedAt | number | yes |
MigrationStarted
| Source | spk.api |
| detail-type | MigrationStarted |
| aggregateType | HubAggregate |
A hub-to-hub device migration has started.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
migrationId | string | yes | |
sourceHubId | string | yes | |
targetHubId | string | yes | |
targetThingName | string | yes | |
deviceIds | string[] | yes | |
startedBy | string | yes | |
startedAt | number | yes |
DeviceMigrationStatusUpdated
| Source | spk.api |
| detail-type | DeviceMigrationStatusUpdated |
| aggregateType | HubAggregate |
A device's migration status has changed.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
migrationId | string | yes | |
deviceId | string | yes | Device UUID |
status | "Queued" | "Migrating" | "Migrated" | "Blocked" | "Failed" | yes | |
error | string | no | |
updatedAt | number | yes |
MigrationCompleted
| Source | spk.api |
| detail-type | MigrationCompleted |
| aggregateType | HubAggregate |
A hub-to-hub device migration has finished.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
migrationId | string | yes | |
status | "Completed" | "Completed with errors" | "Failed" | yes | |
completedAt | number | yes |
Camera events
CameraRegistered
| Source | spk.api |
| detail-type | CameraRegistered |
| aggregateType | CameraAggregate |
A camera has been registered.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
cameraId | string | yes | Camera ID |
threeDeyeCameraId | string | yes | 3dEye-side camera ID |
cameraType | "generic" | "onvif" | "pnp" | yes | |
name | string | yes | |
orgId | string | yes | Organization ID |
ownerId | string | yes | Owning user ID |
httpUrl | string | yes | |
rtspUrl | string | yes | |
registrationCode | string | no | Registration code used |
registeredAt | number | yes | Unix epoch ms |
CameraUpdated
| Source | spk.api |
| detail-type | CameraUpdated |
| aggregateType | CameraAggregate |
A camera's metadata or stream URLs have changed.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
cameraId | string | yes | Camera ID |
name | string | no | |
httpUrl | string | no | |
rtspUrl | string | no | |
updatedAt | number | yes |
CameraDisabled
| Source | spk.api |
| detail-type | CameraDisabled |
| aggregateType | CameraAggregate |
A camera has been disabled.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
cameraId | string | yes | Camera ID |
reason | string | yes | |
disabledBy | string | yes | |
disabledAt | number | yes |
CameraDeleted
| Source | spk.api |
| detail-type | CameraDeleted |
| aggregateType | CameraAggregate |
A camera has been deleted.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
cameraId | string | yes | Camera ID |
deletedBy | string | yes | |
deletedAt | number | yes |
CameraLinkedToLock
| Source | spk.api |
| detail-type | CameraLinkedToLock |
| aggregateType | CameraAggregate |
A camera has been associated with a lock.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
cameraId | string | yes | Camera ID |
lockId | string | yes | Numeric lock ID |
CameraUnlinkedFromLock
| Source | spk.api |
| detail-type | CameraUnlinkedFromLock |
| aggregateType | CameraAggregate |
A camera has been disassociated from a lock.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
cameraId | string | yes | Camera ID |
CameraRoleCreated
| Source | spk.api |
| detail-type | CameraRoleCreated |
| aggregateType | CameraRoleAggregate |
A 3dEye access role has been created.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
roleId | string | yes | |
threeDeyeRoleId | string | yes | |
name | string | yes | |
description | string | yes | |
orgId | string | yes | Organization ID |
createdAt | number | yes |
CameraRoleDeleted
| Source | spk.api |
| detail-type | CameraRoleDeleted |
| aggregateType | CameraRoleAggregate |
A 3dEye access role has been deleted.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
roleId | string | yes | |
deletedAt | number | yes |
CameraRoleUserAssigned
| Source | spk.api |
| detail-type | CameraRoleUserAssigned |
| aggregateType | CameraRoleAggregate |
A user has been added to a camera role.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
roleId | string | yes | |
userId | string | yes | User ID |
threeDeyeUserId | string | yes | |
assignedAt | number | yes |
CameraRoleUserRemoved
| Source | spk.api |
| detail-type | CameraRoleUserRemoved |
| aggregateType | CameraRoleAggregate |
A user has been removed from a camera role.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
roleId | string | yes | |
userId | string | yes | User ID |
threeDeyeUserId | string | yes | |
removedAt | number | yes | Unix epoch ms |
CameraRoleCameraAssigned
| Source | spk.api |
| detail-type | CameraRoleCameraAssigned |
| aggregateType | CameraRoleAggregate |
A camera has been added to a role.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
roleId | string | yes | |
cameraId | string | yes | Camera ID |
permissions | string[] | yes | |
assignedAt | number | yes |
CameraRoleCameraRemoved
| Source | spk.api |
| detail-type | CameraRoleCameraRemoved |
| aggregateType | CameraRoleAggregate |
A camera has been removed from a role.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
roleId | string | yes | |
cameraId | string | yes | Camera ID |
removedAt | number | yes | Unix epoch ms |
RTSP camera events
RtspCameraRegistered
| Source | spk.api |
| detail-type | RtspCameraRegistered |
| aggregateType | RtspCameraAggregate |
An RTSP camera has been registered; placement on a video worker follows.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
cameraId | string | yes | Camera ID |
name | string | yes | |
rtspUrl | string | no | |
rtspHash | string | yes | |
streamId | string | yes | |
username | string | no | |
password | string | no | |
httpSnapshotUrl | string | no | |
ownerId | string | no | |
orgId | string | no | Organization ID |
placementMode | "async" | no | |
createdAt | string | yes |
RtspCameraUpdated
| Source | spk.api |
| detail-type | RtspCameraUpdated |
| aggregateType | RtspCameraAggregate |
An RTSP camera's name or source has changed.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
cameraId | string | yes | Camera ID |
name | string | no | |
rtspUrl | string | no | |
rtspHash | string | no | |
streamId | string | no | |
username | string | no | |
password | string | no | |
httpSnapshotUrl | string | no | |
sourceChanged | true | no | |
updatedAt | string | yes |
RtspCameraDeleted
| Source | spk.api |
| detail-type | RtspCameraDeleted |
| aggregateType | RtspCameraAggregate |
An RTSP camera has been deleted.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
cameraId | string | yes | Camera ID |
deletedAt | string | yes | |
deletedBy | string | no |
RtspCameraAccessGranted
| Source | spk.api |
| detail-type | RtspCameraAccessGranted |
| aggregateType | RtspCameraAggregate |
A user has been granted access to an RTSP camera.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
cameraId | string | yes | Camera ID |
userId | string | yes | User ID |
role | "viewer" | "manager" | yes | |
grantedAt | string | yes | |
grantedBy | string | no |
RtspCameraAccessRevoked
| Source | spk.api |
| detail-type | RtspCameraAccessRevoked |
| aggregateType | RtspCameraAggregate |
A user's access to an RTSP camera has been revoked.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
cameraId | string | yes | Camera ID |
userId | string | yes | User ID |
revokedAt | string | yes | |
revokedBy | string | no |
RtspCameraStreamStarted
| Source | spk.api |
| detail-type | RtspCameraStreamStarted |
| aggregateType | RtspCameraAggregate |
An RTSP camera's stream has been started.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
cameraId | string | yes | Camera ID |
startedAt | string | yes | |
startedBy | string | no | |
workerId | string | no | Video worker ID |
placementGeneration | number | no |
RtspCameraStreamStopped
| Source | spk.api |
| detail-type | RtspCameraStreamStopped |
| aggregateType | RtspCameraAggregate |
An RTSP camera's stream has been stopped.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
cameraId | string | yes | Camera ID |
stoppedAt | string | yes | |
stoppedBy | string | no |
RtspCameraPlaced
| Source | spk.api |
| detail-type | RtspCameraPlaced |
| aggregateType | RtspCameraAggregate |
An RTSP camera has been placed on a video worker and its stream confirmed.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
cameraId | string | yes | Camera ID |
workerId | string | yes | Video worker ID |
placementGeneration | number | yes | |
sourceEventVersion | number | yes | |
placedAt | string | yes |
RtspCameraPlacementFailed
| Source | spk.api |
| detail-type | RtspCameraPlacementFailed |
| aggregateType | RtspCameraAggregate |
An RTSP camera could not be placed on any video worker.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
cameraId | string | yes | Camera ID |
placementGeneration | number | yes | |
sourceEventVersion | number | yes | |
error | string | yes | |
failedAt | string | yes |
RtspCameraRecordingConfigured
| Source | spk.api |
| detail-type | RtspCameraRecordingConfigured |
| aggregateType | RtspCameraAggregate |
An RTSP camera's recording retention was set (0 = recording off).
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
cameraId | string | yes | Camera ID |
retentionDays | number | yes | |
storageProfile | "platform" | no | |
changedBy | object | yes | |
changedBy.kind | "owner" | "admin" | "manager" | yes | |
changedBy.userId | string | yes | |
updatedAt | string | yes |
RtspCameraRecordingsPurgeRequested
| Source | spk.api |
| detail-type | RtspCameraRecordingsPurgeRequested |
| aggregateType | RtspCameraAggregate |
A purge of an RTSP camera's older recordings was requested.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
cameraId | string | yes | Camera ID |
requestId | string | yes | |
cutoff | string | yes | |
olderThanDays | number | yes | |
requestedBy | object | yes | |
requestedBy.kind | "owner" | "admin" | "manager" | yes | |
requestedBy.userId | string | yes | |
requestedAt | string | yes |
RtspCameraRecordingsPurged
| Source | spk.api |
| detail-type | RtspCameraRecordingsPurged |
| aggregateType | RtspCameraAggregate |
A requested recordings purge has finished.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
cameraId | string | yes | Camera ID |
requestId | string | no | |
cutoff | string | yes | |
olderThanDays | number | yes | |
deleted | number | yes | |
complete | boolean | yes | |
purgedBy | object | yes | |
purgedBy.kind | "owner" | "admin" | "manager" | yes | |
purgedBy.userId | string | yes | |
purgedAt | string | yes |
RtspCameraRuntimeStatusChanged
| Source | spk.api |
| detail-type | RtspCameraRuntimeStatusChanged |
| aggregateType | RtspCamera |
An RTSP camera's runtime status changed, as reported by its video worker (delivered only for organization-owned cameras).
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
cameraId | string | yes | Camera ID |
from | string | null | yes | Previous runtime status |
to | string | yes | New runtime status |
error | string | no | Why the stream is not running, when known (never contains the RTSP URL) |
workerId | string | no | Video worker ID |
changedAt | string | yes | When the change was observed (ISO-8601) |
observedAt | string | yes |
RtspCameraMonitoringConfigured
| Source | spk.api |
| detail-type | RtspCameraMonitoringConfigured |
| aggregateType | RtspCameraAggregate |
An RTSP camera's availability monitoring was switched on or off.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
cameraId | string | yes | Camera ID |
enabled | boolean | yes | |
changedBy | string | yes | |
updatedAt | string | yes |
RtspCameraUnavailabilityConfirmed
| Source | spk.api |
| detail-type | RtspCameraUnavailabilityConfirmed |
| aggregateType | RtspCamera |
A monitored RTSP camera is still unavailable; repeated at most every five minutes while it stays so (delivered only for organization-owned cameras).
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
cameraId | string | yes | Camera ID |
runtimeStatus | string | yes | The runtime status the camera is in (e.g. unreachable, gray, stalled) |
reason | string | no | Why, when known: the probe verdict or the runtime error (never contains the RTSP URL) |
workerId | string | no | Video worker ID |
unavailableSince | string | yes | When the camera entered that status (ISO-8601) |
checkedAt | string | yes | When the probe or heartbeat that confirmed it ran (ISO-8601) |
Video worker events
VideoWorkerStarted
| Source | spk.api |
| detail-type | VideoWorkerStarted |
| aggregateType | VideoWorker |
A video worker (VMS box) started up; one event per organization with cameras on it, listing only that organization's cameras.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
workerId | string | yes | Video worker ID |
vmsStartedAt | string | yes | When the VMS process started (ISO-8601) |
vmsVersion | string | no | VMS build version, when reported |
cameraIds | string[] | yes | This organization's cameras assigned to the worker |
detectedAt | string | yes | When the control plane saw the first heartbeat after the start (ISO-8601) |
Matter device events
MatterDeviceCreated
| Source | spk.api |
| detail-type | MatterDeviceCreated |
| aggregateType | MatterDeviceAggregate |
A Matter device has been registered.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
deviceId | string | yes | Device UUID |
thingName | string | yes | AWS IoT thing name |
hubId | string | yes | Hub UUID |
deviceType | string | yes | |
createdAt | number | yes |
ReportedShadowUpdated
| Source | spk.api |
| detail-type | ReportedShadowUpdated |
| aggregateType | MatterDeviceAggregate |
A device reported new shadow state.
Not delivered to webhooks. It can be named in a subscription, but it is never published to EventBridge — subscribe to
Shadow Updateto track device shadow state.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
deviceId | string | yes | Device UUID |
thingName | string | yes | AWS IoT thing name |
reported | object | yes | |
updatedAt | number | yes |
DesiredShadowUpdated
| Source | spk.api |
| detail-type | DesiredShadowUpdated |
| aggregateType | MatterDeviceAggregate |
A new desired shadow state was pushed.
Not delivered to webhooks. It can be named in a subscription, but it is never published to EventBridge — subscribe to
Shadow Updateto track device shadow state.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
deviceId | string | yes | Device UUID |
thingName | string | yes | AWS IoT thing name |
desired | object | yes | |
updatedAt | number | yes | |
requestedByUserId | string | no |
MatterPinSet
| Source | spk.api |
| detail-type | MatterPinSet |
| aggregateType | MatterDeviceAggregate |
A PIN credential slot was provisioned on a Matter door lock (the PIN itself is never carried).
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
deviceId | string | yes | Device UUID |
thingName | string | yes | AWS IoT thing name |
userIndex | number | yes | |
credentialIndex | number | yes | |
timestamp | number | yes | ISO-8601 time of the domain event |
MatterPinCleared
| Source | spk.api |
| detail-type | MatterPinCleared |
| aggregateType | MatterDeviceAggregate |
A PIN credential slot was cleared on a Matter door lock.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
deviceId | string | yes | Device UUID |
thingName | string | yes | AWS IoT thing name |
userIndex | number | no | |
credentialIndex | number | yes | |
timestamp | number | yes | ISO-8601 time of the domain event |
AppPinSendRequested
| Source | spk.api |
| detail-type | AppPinSendRequested |
| aggregateType | MatterDeviceAggregate |
An app-PIN delivery attempt was sent to the lock.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
deviceId | string | yes | Device UUID |
thingName | string | yes | AWS IoT thing name |
timestamp | number | yes | ISO-8601 time of the domain event |
messageId | string | yes | |
attempt | number | yes | |
userIndex | number | yes | |
credentialIndex | number | yes | |
pinMinLength | number | null | yes | |
pinMaxLength | number | null | yes |
AppPinShadowWriteFailed
| Source | spk.api |
| detail-type | AppPinShadowWriteFailed |
| aggregateType | MatterDeviceAggregate |
An app-PIN write could not be made to the device shadow; the attempt will be retried.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
deviceId | string | yes | Device UUID |
thingName | string | yes | AWS IoT thing name |
timestamp | number | yes | ISO-8601 time of the domain event |
command | "SetCredential" | "ClearCredential" | yes | |
messageId | string | null | yes | |
error | string | yes |
AppPinAcked
| Source | spk.api |
| detail-type | AppPinAcked |
| aggregateType | MatterDeviceAggregate |
The lock acknowledged an app-PIN write.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
deviceId | string | yes | Device UUID |
thingName | string | yes | AWS IoT thing name |
timestamp | number | yes | ISO-8601 time of the domain event |
outcome | "success" | "failure" | "duplicate" | "occupied" | "invalid-field" | "not-found" | yes | |
matchedMessageId | string | yes | |
errorCode | number | string | no | |
userIndex | number | no | |
provisionState | "pending" | "sent" | "verified" | "unverified" | "failed" | yes |
AppPinClearRequested
| Source | spk.api |
| detail-type | AppPinClearRequested |
| aggregateType | MatterDeviceAggregate |
An app-PIN slot clear was sent to the lock.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
deviceId | string | yes | Device UUID |
thingName | string | yes | AWS IoT thing name |
timestamp | number | yes | ISO-8601 time of the domain event |
credentialIndex | number | yes | |
messageId | string | null | no |
AppPinGaveUp
| Source | spk.api |
| detail-type | AppPinGaveUp |
| aggregateType | MatterDeviceAggregate |
The lock refused every app-PIN attempt; delivery stopped.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
deviceId | string | yes | Device UUID |
thingName | string | yes | AWS IoT thing name |
timestamp | number | yes | ISO-8601 time of the domain event |
reason | string | yes | |
attemptCount | number | yes | |
lastOutcome | string | null | yes |
AppPinRedriven
| Source | spk.api |
| detail-type | AppPinRedriven |
| aggregateType | MatterDeviceAggregate |
App-PIN delivery was restarted from the beginning.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
deviceId | string | yes | Device UUID |
thingName | string | yes | AWS IoT thing name |
timestamp | number | yes | ISO-8601 time of the domain event |
reason | string | yes | |
priorState | "pending" | "sent" | "verified" | "unverified" | "failed" | null | yes | |
priorAttempts | number | yes | |
priorInfraFailures | number | yes | |
evidenceMessageId | string | no |
AppPinRetired
| Source | spk.api |
| detail-type | AppPinRetired |
| aggregateType | MatterDeviceAggregate |
App-PIN delivery was dropped because the lock does not require a remote PIN.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
deviceId | string | yes | Device UUID |
thingName | string | yes | AWS IoT thing name |
timestamp | number | yes | ISO-8601 time of the domain event |
reason | string | yes | |
credentialIndex | number | yes |
AppPinDeliveryFailed
| Source | spk.api |
| detail-type | AppPinDeliveryFailed |
| aggregateType | MatterDeviceAggregate |
The bridge answered an app-PIN write without the lock carrying it out; the attempt will be retried.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
deviceId | string | yes | Device UUID |
thingName | string | yes | AWS IoT thing name |
timestamp | number | yes | ISO-8601 time of the domain event |
command | "SetCredential" | "ClearCredential" | yes | |
messageId | string | null | yes | |
reason | "unreachable" | "no-ack" | "refused" | yes | |
error | string | yes |
MatterDeviceNameSet
| Source | spk.api |
| detail-type | MatterDeviceNameSet |
| aggregateType | MatterDeviceAggregate |
The display name of a Matter device has been set.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
deviceId | string | yes | Device UUID |
thingName | string | yes | AWS IoT thing name |
name | string | yes | |
timestamp | number | yes | ISO-8601 time of the domain event |
Alarm events
AlarmTriggered
| Source | spk.api |
| detail-type | AlarmTriggered |
| aggregateType | MatterDeviceAggregate |
A Matter sensor (smoke, CO, occupancy, …) reported an alarm condition.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
deviceId | string | yes | Device UUID |
channel | "boolean_state" | "smoke" | "smoke_interconnect" | "co" | "occupancy" | "device_fault" | yes | |
alarmType | "contact" | "water_leak" | "smoke" | "co" | "motion" | "water_freeze" | "rain" | "device_fault" | yes | |
severity | "warning" | "critical" | yes | |
matterPath | string | yes | Matter endpoint/cluster/attribute path that tripped (e.g. 1/69/0) |
deviceTypeId | number | no | |
endpoint | number | no | |
deviceTypeSource | "shadow" | "sticky" | "command" | "shadow_borrowed" | "shadow_disputed" | no | |
rawValue | number | no | Raw reported value that produced the alarm |
alarmsEnabled | boolean | no | Device alarm mode at the moment of this transition; false = no push was due. Absent on events recorded before AA-311, which means on. |
timestamp | string | yes | ISO-8601 time of the domain event |
AlarmCleared
| Source | spk.api |
| detail-type | AlarmCleared |
| aggregateType | MatterDeviceAggregate |
A previously triggered alarm condition has cleared.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
deviceId | string | yes | Device UUID |
channel | "boolean_state" | "smoke" | "smoke_interconnect" | "co" | "occupancy" | "device_fault" | yes | |
alarmType | "contact" | "water_leak" | "smoke" | "co" | "motion" | "water_freeze" | "rain" | "device_fault" | yes | |
matterPath | string | yes | |
deviceTypeId | number | no | |
endpoint | number | no | |
deviceTypeSource | "shadow" | "sticky" | "command" | "shadow_borrowed" | "shadow_disputed" | no | |
rawValue | number | no | |
alarmsEnabled | boolean | no | Device alarm mode at the moment of this transition; false = no push was due. Absent on events recorded before AA-311, which means on. |
timestamp | string | yes | ISO-8601 time of the domain event |
AlarmModeSet
| Source | spk.api |
| detail-type | AlarmModeSet |
| aggregateType | MatterDeviceAggregate |
Alarm pushes of a Matter device were switched on or off.
Payload fields (detail.data):
| Field | Type | Required | Description |
|---|---|---|---|
deviceId | string | yes | Device UUID — same value as the MatterDevice thingName / aggregate id |
enabled | boolean | yes | The new alarm mode; false = the device sends no alarm push |
changedByUserId | string | no | The user (token caller) who changed the mode; absent when an organization API key changed it |
changedByOrgId | string | no | The API key's organization that changed the mode; absent when a user's token changed it |
IoT events
Shadow Update
| Source | spk.iot.shadow |
| detail-type | Shadow Update |
An IoT hub device updated its AWS IoT Device Shadow.
This event has a different envelope from spk.api events — there is no detail.data wrapper. The shadow fields live directly on detail.
Payload fields (top-level detail):
| Field | Type | Required | Description |
|---|---|---|---|
partnerId | string | null | yes | Partner associated with this device |
thingName | string | yes | AWS IoT thing name |
reportedState | string | null | yes | State the device reported back (JSON string) |
desiredState | string | null | yes | Target state set by the application (JSON string) |
deltaState | string | yes | Difference between desired and reported state (JSON string) |
metadata | string | null | yes | AWS IoT shadow metadata with timestamps per field (JSON string) |
version | string | number | null | yes | Shadow document version |
shadowName | string | null | no | Named shadow the update came from (e.g. state, device_info) |
bridgeUuid | string | null | no | |
deviceType | string | null | no | |
nodeId | string | null | no | |
thingTypeName | string | null | no |
reportedState, desiredState, deltaState and metadata are stringified JSON embedded inside the outer JSON object. Call JSON.parse() on each before reading its contents.