Contract
- shape
- entity
- authority
- act
- evidence
- none
- subscription
- false
- permission
- any one of: self.act (the signed-in caller, about themself only; it names no other user); a deactivated caller is refused first
- idempotency
- natural
- emits
- device.registered
- MCP tool
- none
- decision_set
- approve, reject
- REST
- POST https://api.containertradehq.com/v1/cap/register_device
Idempotency: keyed by the contract's own inputs: the same inputs replay the first call's result
Inputs
| name | type | required | validation |
|---|---|---|---|
| public_point | text | required | 80 to 100 characters The installation's P-256 public key, as its 65-byte uncompressed SEC1 point, standard base64. |
| platform | one_of | required | one of ios, android The app's platform. |
| app_version | text | required | 1 to 64 characters The app's version. |
| challenge | text | required | 1 to 64 characters A challenge POST /v1/device/challenge issued to the caller for this installation. |
| signature | text | required | 1 to 200 characters The installation key's ECDSA P-256/SHA-256 signature, DER, standard base64, over the registration message (installation, challenge, caller). |
| expo_push_token | text | optional | 1 to 255 characters The Expo push token the app was given. A new one replaces the previous. |
| managed | boolean | optional | A shared or kiosk device, enrolled by an org admin: it reads only. Absent is false. |
| unit_id | unit_id | optional | tradehq-unit-id A unit of the session's org the device belongs to (TRA-324's yard identity). |
Response
binding_id· string · The binding: the device's principal id.installation_id· string · The installation, derived from its key.managed· boolean · Whether it is a managed (shared) device.push· boolean · Whether it has a live push destination.
Full JSON Schema
{
"type": "object",
"properties": {
"binding_id": {
"type": "string",
"pattern": "^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$",
"format": "uuid",
"description": "The binding: the device's principal id.",
"x-data-class": "operational"
},
"installation_id": {
"type": "string",
"pattern": "^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$",
"format": "uuid",
"description": "The installation, derived from its key.",
"x-data-class": "operational"
},
"managed": {
"type": "boolean",
"description": "Whether it is a managed (shared) device.",
"x-data-class": "operational"
},
"push": {
"type": "boolean",
"description": "Whether it has a live push destination.",
"x-data-class": "operational"
}
},
"required": [
"binding_id",
"installation_id",
"managed",
"push"
],
"additionalProperties": false
} Refusals
public_key_invalid· 422 · public_point is not the standard base64 of an uncompressed P-256 point on the curvechallenge_invalid· 422 · the challenge was not issued to the caller for this installation, is spent, or has expired; ask for a fresh onesignature_invalid· 422 · the signature is not the installation key's over the installation, the challenge and the callerinstallation_bound_elsewhere· 422 · the installation is bound to another user; it can be bound again only once they revoke itmanaged_requires_org_admin· 422 · a managed (shared) device is enrolled only by an admin of the session's orgmanaged_differs· 422 · the installation is already bound to the caller with the other managed setting; revoke it and enroll it againunit_not_in_org· 422 · unit_id is not a unit of the session's orgpush_token_invalid· 422 · expo_push_token is not an Expo push token (ExponentPushToken[...])org_required· 422 · the session has selected no org to bind the device in
The platform refusals apply to every call: version, authentication, authority, validation and rate limits, each in the same envelope.
Surfaces
- Desktop: a browser holds no installation key; a device registers from the app
- MCP: an MCP client holds no installation key
- Voice: a key is proven by signing, which no voice surface can
- OneBox: no document originates a device
- Outbound: crosses to no counterparty
Events
device.registeredaudit_only
Related
None.