API reference
Enrollments
Enrollment codes that add a device or a connector to the workspace.
List pending enrollments
GET/v0/tenants/{tenant_id}/enrollments
Device enrollments that were issued but not used yet and have not expired ("waiting to enroll"). Never returns a token or code. A device that has joined disappears from this list and shows in GET /devices.
Token: read-only or full access · Created by: owner or security admin
Path parameters
- tenant_idstringrequired
Your workspace id (Settings → Workspace in the console; it is also in every console URL).
Query parameters
- kindstring
Only
deviceis supported. - statestring
Only
issuedis supported.
Responses
200 Pending enrollments (not paginated).
application/json
- itemsarray of Enrollmentrequired
Newest first.
items fields
- idstringrequired
- kindstring
device. - statestring
issued(not used yet). - device_namestringrequired
- created_atstring (date-time)
- created_by_integratorobject | null
Set when an integrator (partner) you approved created this record from its own account; null otherwise.
created_by_integrator fields
- kindstring
Always
partner. - partner_idstring
- partner_namestring
- memberstring | null
Which of the integrator's staff.
- member_idstring | null
- atstring (date-time)
- expires_atstring (date-time)required
- claim_expires_atstring | null (date-time)
Expiry of the live short code; null when no code is live (a new one can be issued in the console).
- next_cursornull
Always null: the list is bounded by the device quota.
400 invalid-kind invalid-state
invalid-kind: kind is not device.
invalid-state: state is not issued.
401 unauthorized invalid-token token-expired
unauthorized: No Authorization: Bearer crw_… header was sent.
invalid-token: The token is unknown or was revoked.
token-expired: The token is past its expiry date. Create a new one.
403 insufficient-role tenant-assertion-mismatch
insufficient-role: The token's role ceiling does not allow this call.
tenant-assertion-mismatch: The token belongs to another workspace than {tenant_id}.
404 tenant-not-found
tenant-not-found: No workspace with this id.
curl -sS -X GET "https://cdapi.cloudraw.com/v0/tenants/tq7x2m9k4ab/enrollments" \
-H "Authorization: Bearer $CLOUDRAW_TOKEN"$headers = @{ Authorization = "Bearer $env:CLOUDRAW_TOKEN" }
Invoke-RestMethod -Method Get -Uri "https://cdapi.cloudraw.com/v0/tenants/tq7x2m9k4ab/enrollments" -Headers $headersimport os, uuid, requests
r = requests.get(
"https://cdapi.cloudraw.com/v0/tenants/tq7x2m9k4ab/enrollments",
headers={"Authorization": f"Bearer {os.environ['CLOUDRAW_TOKEN']}"},
timeout=30,
)
r.raise_for_status()
print(r.json())const res = await fetch("https://cdapi.cloudraw.com/v0/tenants/tq7x2m9k4ab/enrollments", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.CLOUDRAW_TOKEN}`,
},
});
if (!res.ok) throw new Error((await res.json()).code);
console.log(await res.json());{
"items": [
{
"id": "en_7k2x9m0s1d",
"kind": "device",
"state": "issued",
"device_name": "omer-laptop",
"created_at": "2026-10-13T08:00:00.000Z",
"created_by_integrator": null,
"expires_at": "2026-10-20T08:00:00.000Z",
"claim_expires_at": "2026-10-13T09:00:00.000Z"
}
],
"next_cursor": null
}Create a device enrollment
POST/v0/tenants/{tenant_id}/enrollments
Issues a one-time enrollment for a new device and returns how to join it: a short code (claim_code, valid 1 hour, entered in Cloudraw Connect), a link with the same code (claim_url) and the enrollment token itself (jwt, valid 7 days). Give one of them to the user over a direct channel. Counts toward the device quota. Audited.
Token: full access · Created by: owner
Idempotency: send Idempotency-Key. The answer carries a secret shown once: a retry with the same key answers 409 already-issued instead of the secret.
Secret answer: the token and code are shown only in this answer. Lost them? Cancel the enrollment (DELETE /enrollments/{enrollment_id}) and create a new one.
Path parameters
- tenant_idstringrequired
Your workspace id (Settings → Workspace in the console; it is also in every console URL).
Headers
- Idempotency-Keystring
A unique value (e.g. a UUID) per logical operation. Retrying with the same key and body within 24 hours returns the first answer instead of doing the work twice.
Request body application/json
- kindstring
Default
device. - deliverystring
How you will hand the enrollment to the user (recorded on the device as
delivery; the answer is the same). Defaulttoken.ssoandprovisionare set by Cloudraw only. - device_namestring
Name for the device. Lowercased, other characters become
-, at most 40 characters. Defaultdevice-<n>. Must not be in use by another device. - person_idstring | null
Person the device will belong to. An unknown id is ignored (the device is unassigned).
Responses
201 The enrollment, with its secrets. Shown once: they are never returned again and are not kept for Idempotency-Key replays. Sent with Cache-Control: no-store; do not cache or log it.
application/json
- idstringrequired
Enrollment id; also the id of the device once it joins.
- kindstring
device. - statestring
issued. - jwtstringrequired
One-time enrollment token (shown once). Valid until
expires_at. - claim_codestringrequired
Short code the user types in Cloudraw Connect,
CRW-XXXXX-XXXXX(shown once). Valid 1 hour. - claim_urlstringrequired
Link that opens Cloudraw Connect with the code (shown once).
- claim_expires_atstring (date-time)
- qr_png_base64null
- expires_atstring (date-time)required
When the enrollment token expires (7 days).
400 invalid-delivery
invalid-delivery: delivery is not one of token, code, qr, email.
401 unauthorized invalid-token token-expired
unauthorized: No Authorization: Bearer crw_… header was sent.
invalid-token: The token is unknown or was revoked.
token-expired: The token is past its expiry date. Create a new one.
403 device-quota-reached insufficient-scope insufficient-role tenant-assertion-mismatch
device-quota-reached: The workspace already has as many devices as its plan allows.
insufficient-scope: The token is read-only and this call changes something.
insufficient-role: The token's role ceiling does not allow this call.
tenant-assertion-mismatch: The token belongs to another workspace than {tenant_id}.
404 tenant-not-found
tenant-not-found: No workspace with this id.
409 idempotency-key-reuse already-issued
idempotency-key-reuse: The same Idempotency-Key was used with a different body within 24 hours.
already-issued: This Idempotency-Key already created a secret; it is shown only once. Retry with a new key.
502 provisioning-failed
provisioning-failed: The device identity could not be created (for example the name is already in use, or a temporary failure). Nothing was issued; retry or choose another name.
503 busy
busy: Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds.
curl -sS -X POST "https://cdapi.cloudraw.com/v0/tenants/tq7x2m9k4ab/enrollments" \
-H "Authorization: Bearer $CLOUDRAW_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"device_name": "omer-laptop",
"person_id": "p4hd8s0qk2l"
}'$body = @'
{
"device_name": "omer-laptop",
"person_id": "p4hd8s0qk2l"
}
'@
$headers = @{ Authorization = "Bearer $env:CLOUDRAW_TOKEN"; "Idempotency-Key" = [guid]::NewGuid().ToString() }
Invoke-RestMethod -Method Post -Uri "https://cdapi.cloudraw.com/v0/tenants/tq7x2m9k4ab/enrollments" -Headers $headers -ContentType "application/json" -Body $bodyimport os, uuid, requests
r = requests.post(
"https://cdapi.cloudraw.com/v0/tenants/tq7x2m9k4ab/enrollments",
headers={"Authorization": f"Bearer {os.environ['CLOUDRAW_TOKEN']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"device_name": "omer-laptop",
"person_id": "p4hd8s0qk2l"
},
timeout=30,
)
r.raise_for_status()
print(r.json())const res = await fetch("https://cdapi.cloudraw.com/v0/tenants/tq7x2m9k4ab/enrollments", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CLOUDRAW_TOKEN}`,
"Idempotency-Key": crypto.randomUUID(),
"Content-Type": "application/json",
},
body: JSON.stringify({
"device_name": "omer-laptop",
"person_id": "p4hd8s0qk2l"
}),
});
if (!res.ok) throw new Error((await res.json()).code);
console.log(await res.json());{
"id": "en_7k2x9m0s1d",
"kind": "device",
"state": "issued",
"jwt": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJleGFtcGxlIn0.c2lnbmF0dXJl",
"claim_code": "CRW-7KQ2M-X9D4P",
"claim_url": "https://connect.example.com/d/CRW-7KQ2M-X9D4P",
"claim_expires_at": "2026-10-13T10:24:11.000Z",
"qr_png_base64": null,
"expires_at": "2026-10-20T09:24:11.000Z"
}Get an enrollment
GET/v0/tenants/{tenant_id}/enrollments/{enrollment_id}
Metadata of one device enrollment: name, token expiry and whether a short code is live (claim_expires_at). Never returns a code or token (claim_code and claim_url are always null). Sent with Cache-Control: no-store.
Token: read-only or full access · Created by: owner or security admin
Path parameters
- tenant_idstringrequired
Your workspace id (Settings → Workspace in the console; it is also in every console URL).
- enrollment_idstringrequired
Enrollment id (from
POST /enrollmentsorGET /enrollments).
Responses
200 The enrollment.
application/json
- idstringrequired
- device_namestring
- claim_codenull
Never returned here.
- claim_urlnull
- claim_expires_atstring | null (date-time)
- expires_atstring (date-time)required
- reveal_withobject
The call that issues a fresh short code (and invalidates the previous one).
reveal_with fields
- methodstring
- pathstring
401 unauthorized invalid-token token-expired
unauthorized: No Authorization: Bearer crw_… header was sent.
invalid-token: The token is unknown or was revoked.
token-expired: The token is past its expiry date. Create a new one.
403 insufficient-role tenant-assertion-mismatch
insufficient-role: The token's role ceiling does not allow this call.
tenant-assertion-mismatch: The token belongs to another workspace than {tenant_id}.
404 enrollment-not-found tenant-not-found
enrollment-not-found: No device enrollment with this id.
tenant-not-found: No workspace with this id.
curl -sS -X GET "https://cdapi.cloudraw.com/v0/tenants/tq7x2m9k4ab/enrollments/en_7k2x9m0s1d" \
-H "Authorization: Bearer $CLOUDRAW_TOKEN"$headers = @{ Authorization = "Bearer $env:CLOUDRAW_TOKEN" }
Invoke-RestMethod -Method Get -Uri "https://cdapi.cloudraw.com/v0/tenants/tq7x2m9k4ab/enrollments/en_7k2x9m0s1d" -Headers $headersimport os, uuid, requests
r = requests.get(
"https://cdapi.cloudraw.com/v0/tenants/tq7x2m9k4ab/enrollments/en_7k2x9m0s1d",
headers={"Authorization": f"Bearer {os.environ['CLOUDRAW_TOKEN']}"},
timeout=30,
)
r.raise_for_status()
print(r.json())const res = await fetch("https://cdapi.cloudraw.com/v0/tenants/tq7x2m9k4ab/enrollments/en_7k2x9m0s1d", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.CLOUDRAW_TOKEN}`,
},
});
if (!res.ok) throw new Error((await res.json()).code);
console.log(await res.json());{
"id": "en_7k2x9m0s1d",
"device_name": "omer-laptop",
"claim_code": null,
"claim_url": null,
"claim_expires_at": "2026-10-13T09:00:00.000Z",
"expires_at": "2026-10-20T08:00:00.000Z",
"reveal_with": {
"method": "POST",
"path": "/v0/tenants/tq7x2m9k4ab/enrollments/en_7k2x9m0s1d"
}
}Cancel a pending enrollment
DELETE/v0/tenants/{tenant_id}/enrollments/{enrollment_id}
Cancels an enrollment that has not been used: its token can no longer be exchanged and every short code for it stops working. Audited. An enrollment that was already used is a device: remove it with DELETE /devices/{device_id}.
Token: full access · Created by: owner
Path parameters
- tenant_idstringrequired
Your workspace id (Settings → Workspace in the console; it is also in every console URL).
- enrollment_idstringrequired
Enrollment id (from
POST /enrollmentsorGET /enrollments).
Responses
204 Cancelled.
401 unauthorized invalid-token token-expired
unauthorized: No Authorization: Bearer crw_… header was sent.
invalid-token: The token is unknown or was revoked.
token-expired: The token is past its expiry date. Create a new one.
403 insufficient-scope insufficient-role tenant-assertion-mismatch
insufficient-scope: The token is read-only and this call changes something.
insufficient-role: The token's role ceiling does not allow this call.
tenant-assertion-mismatch: The token belongs to another workspace than {tenant_id}.
404 enrollment-not-found enrollment-consumed tenant-not-found
enrollment-not-found: No pending device enrollment with this id.
enrollment-consumed: The enrollment was already used; remove the device instead.
tenant-not-found: No workspace with this id.
502 cancel-failed
cancel-failed: The enrollment could not be cancelled right now; nothing was changed. Retry.
503 busy
busy: Cloudraw is switching servers or cannot save right now. Retry after Retry-After seconds.
curl -sS -X DELETE "https://cdapi.cloudraw.com/v0/tenants/tq7x2m9k4ab/enrollments/en_7k2x9m0s1d" \
-H "Authorization: Bearer $CLOUDRAW_TOKEN"$headers = @{ Authorization = "Bearer $env:CLOUDRAW_TOKEN" }
Invoke-RestMethod -Method Delete -Uri "https://cdapi.cloudraw.com/v0/tenants/tq7x2m9k4ab/enrollments/en_7k2x9m0s1d" -Headers $headersimport os, uuid, requests
r = requests.delete(
"https://cdapi.cloudraw.com/v0/tenants/tq7x2m9k4ab/enrollments/en_7k2x9m0s1d",
headers={"Authorization": f"Bearer {os.environ['CLOUDRAW_TOKEN']}"},
timeout=30,
)
r.raise_for_status()
print(r.status_code)const res = await fetch("https://cdapi.cloudraw.com/v0/tenants/tq7x2m9k4ab/enrollments/en_7k2x9m0s1d", {
method: "DELETE",
headers: {
Authorization: `Bearer ${process.env.CLOUDRAW_TOKEN}`,
},
});
if (!res.ok) throw new Error((await res.json()).code);
console.log(res.status);