Guests & portal users
Guests are people from outside the organisation invited by email (for example to a site or a shared file). Portal users are PSA contacts given a client-portal sign-in.
| Method | Path | Summary |
|---|---|---|
| POST | /v1/admin/portal/contacts/:contactId/invite | Invite a PSA contact as a client-portal user |
| GET | /v1/admin/portal/contacts | List every client-portal login in the tenant |
| POST | /v1/admin/portal/contacts/:userId/revoke | Revoke a client-portal user's access |
| POST | /v1/admin/guests/invite | Invite a guest user by email |
| GET | /v1/admin/guests | List the tenant's guest users |
| POST | /v1/admin/guests/:guestId/resend | Resend a guest's set-password invite link |
| POST | /v1/admin/guests/:guestId/revoke | Revoke a guest's access |
#Invite a PSA contact as a client-portal user
/v1/admin/portal/contacts/:contactId/inviteInvite a PSA contact as a client-portal user. Requires the GLOBAL_ADMIN role. Contact must belong to a client and have an email on file; email must not already be a users.email (unique platform-wide). Creates a user_type=client_contact row and emails a 24-hour set-password link.
- Address
https://<your-org>.brambleit.cloud/api/v1/admin/portal/contacts/:contactId/invite- Requires
- Signed-in session,
X-API-Key, or a Bramble app access token (Authorization: Bearer).
Role:GLOBAL_ADMIN.
Path parameters
| Name | Type | Description |
|---|---|---|
contactIdrequired | integer |
Response 201
| Field | Type | Description |
|---|---|---|
message | string | |
user_id | integer |
Example response
{
"message": "Saved",
"user_id": 7
}Errors
| Status | Message |
|---|---|
| 400 | Contact must belong to a client before granting portal access |
| 400 | Contact has no email address on file |
| 404 | Contact not found |
| 409 | A user with this email already exists |
Example request
curl -X POST 'https://<your-org>.brambleit.cloud/api/v1/admin/portal/contacts/1/invite' \
-H "X-API-Key: $BRAMBLE_KEY"const res = await fetch('https://<your-org>.brambleit.cloud/api/v1/admin/portal/contacts/1/invite', {
method: 'POST',
headers: { 'X-API-Key': process.env.BRAMBLE_KEY },
});
const data = await res.json();import os, requests
r = requests.post(
"https://<your-org>.brambleit.cloud/api/v1/admin/portal/contacts/1/invite",
headers={"X-API-Key": os.environ["BRAMBLE_KEY"]},
)
r.raise_for_status()
data = r.json()$headers = @{ 'X-API-Key' = $env:BRAMBLE_KEY }
Invoke-RestMethod -Method POST -Uri 'https://<your-org>.brambleit.cloud/api/v1/admin/portal/contacts/1/invite' -Headers $headers#List every client-portal login in the tenant
/v1/admin/portal/contactsList every client-portal login in the tenant. Requires the GLOBAL_ADMIN role. Every user_type=client_contact user regardless of how it was created (staff invite from PSA, or self-service join link), with the associated client name attached.
- Address
https://<your-org>.brambleit.cloud/api/v1/admin/portal/contacts- Requires
- Signed-in session,
X-API-Key, or a Bramble app access token (Authorization: Bearer).
Role:GLOBAL_ADMIN.
Response 200
| Field | Type | Description |
|---|---|---|
contacts | array of any |
Example response
{
"contacts": []
}Example request
curl -X GET 'https://<your-org>.brambleit.cloud/api/v1/admin/portal/contacts' \
-H "X-API-Key: $BRAMBLE_KEY"const res = await fetch('https://<your-org>.brambleit.cloud/api/v1/admin/portal/contacts', {
method: 'GET',
headers: { 'X-API-Key': process.env.BRAMBLE_KEY },
});
const data = await res.json();import os, requests
r = requests.get(
"https://<your-org>.brambleit.cloud/api/v1/admin/portal/contacts",
headers={"X-API-Key": os.environ["BRAMBLE_KEY"]},
)
r.raise_for_status()
data = r.json()$headers = @{ 'X-API-Key' = $env:BRAMBLE_KEY }
Invoke-RestMethod -Method GET -Uri 'https://<your-org>.brambleit.cloud/api/v1/admin/portal/contacts' -Headers $headers#Revoke a client-portal user's access
/v1/admin/portal/contacts/:userId/revokeRevoke a client-portal user's access. Requires the GLOBAL_ADMIN role. Non-destructive (sets status=0, row kept) so access can be restored by inviting the same contact again; also kills any active sessions.
- Address
https://<your-org>.brambleit.cloud/api/v1/admin/portal/contacts/:userId/revoke- Requires
- Signed-in session,
X-API-Key, or a Bramble app access token (Authorization: Bearer).
Role:GLOBAL_ADMIN.
Path parameters
| Name | Type | Description |
|---|---|---|
userIdrequired | integer |
Response 200
| Field | Type | Description |
|---|---|---|
message | string |
Example response
{
"message": "Saved"
}Errors
| Status | Message |
|---|---|
| 404 | Portal user not found |
Example request
curl -X POST 'https://<your-org>.brambleit.cloud/api/v1/admin/portal/contacts/1/revoke' \
-H "X-API-Key: $BRAMBLE_KEY"const res = await fetch('https://<your-org>.brambleit.cloud/api/v1/admin/portal/contacts/1/revoke', {
method: 'POST',
headers: { 'X-API-Key': process.env.BRAMBLE_KEY },
});
const data = await res.json();import os, requests
r = requests.post(
"https://<your-org>.brambleit.cloud/api/v1/admin/portal/contacts/1/revoke",
headers={"X-API-Key": os.environ["BRAMBLE_KEY"]},
)
r.raise_for_status()
data = r.json()$headers = @{ 'X-API-Key' = $env:BRAMBLE_KEY }
Invoke-RestMethod -Method POST -Uri 'https://<your-org>.brambleit.cloud/api/v1/admin/portal/contacts/1/revoke' -Headers $headers#Invite a guest user by email
/v1/admin/guests/inviteInvite a guest user by email. Requires the GLOBAL_ADMIN role. Unlike staff creation, any email is accepted (no tenants_domains restriction) since users.email is now unique per (tenant_id, email) rather than platform-wide. Creates a user_type=guest row and emails a 7-day set-password link.
- Address
https://<your-org>.brambleit.cloud/api/v1/admin/guests/invite- Requires
- Signed-in session,
X-API-Key, or a Bramble app access token (Authorization: Bearer).
Role:GLOBAL_ADMIN.
Request body JSON
| Name | Type | Description |
|---|---|---|
email | string | Their email address. |
display_name | string | Their name. |
Response 201
| Field | Type | Description |
|---|---|---|
message | string | |
user_id | integer |
Example response
{
"message": "Saved",
"user_id": 7
}Errors
| Status | Message |
|---|---|
| 400 | A valid email is required |
| 409 | A user with this email already exists on this tenant |
Example request
curl -X POST 'https://<your-org>.brambleit.cloud/api/v1/admin/guests/invite' \
-H "X-API-Key: $BRAMBLE_KEY" \
-H "Content-Type: application/json" \
-d '{"email":"alex@example.com","display_name":"Example display name"}'const res = await fetch('https://<your-org>.brambleit.cloud/api/v1/admin/guests/invite', {
method: 'POST',
headers: { 'X-API-Key': process.env.BRAMBLE_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({"email":"alex@example.com","display_name":"Example display name"}),
});
const data = await res.json();import os, requests
r = requests.post(
"https://<your-org>.brambleit.cloud/api/v1/admin/guests/invite",
headers={"X-API-Key": os.environ["BRAMBLE_KEY"]},
json={"email":"alex@example.com","display_name":"Example display name"},
)
r.raise_for_status()
data = r.json()$headers = @{ 'X-API-Key' = $env:BRAMBLE_KEY }
$body = '{"email":"alex@example.com","display_name":"Example display name"}'
Invoke-RestMethod -Method POST -Uri 'https://<your-org>.brambleit.cloud/api/v1/admin/guests/invite' -Headers $headers -ContentType 'application/json' -Body $body#List the tenant's guest users
/v1/admin/guestsList the tenant's guest users. Requires the GLOBAL_ADMIN role. Each guest includes its assigned license tenant_package_ids, in the same shape the frontend already compares against for staff users' embedded licenses.
- Address
https://<your-org>.brambleit.cloud/api/v1/admin/guests- Requires
- Signed-in session,
X-API-Key, or a Bramble app access token (Authorization: Bearer).
Role:GLOBAL_ADMIN.
Response 200
| Field | Type | Description |
|---|---|---|
guests | array of object | |
guests[].id | integer | |
guests[].email | string | |
guests[].display_name | string, or null | |
guests[].status | boolean | |
guests[].created_at | string (date-time), or null |
Example response
{
"guests": [
{
"id": 42,
"email": "alex@example.com",
"display_name": "Example display name",
"status": false,
"created_at": "2026-11-12T09:30:00.000Z"
}
]
}Example request
curl -X GET 'https://<your-org>.brambleit.cloud/api/v1/admin/guests' \
-H "X-API-Key: $BRAMBLE_KEY"const res = await fetch('https://<your-org>.brambleit.cloud/api/v1/admin/guests', {
method: 'GET',
headers: { 'X-API-Key': process.env.BRAMBLE_KEY },
});
const data = await res.json();import os, requests
r = requests.get(
"https://<your-org>.brambleit.cloud/api/v1/admin/guests",
headers={"X-API-Key": os.environ["BRAMBLE_KEY"]},
)
r.raise_for_status()
data = r.json()$headers = @{ 'X-API-Key' = $env:BRAMBLE_KEY }
Invoke-RestMethod -Method GET -Uri 'https://<your-org>.brambleit.cloud/api/v1/admin/guests' -Headers $headers#Resend a guest's set-password invite link
/v1/admin/guests/:guestId/resendResend a guest's set-password invite link. Requires the GLOBAL_ADMIN role. Issues a fresh 7-day link for a guest who hasn't accepted yet or lost the original email, without re-collecting their details.
- Address
https://<your-org>.brambleit.cloud/api/v1/admin/guests/:guestId/resend- Requires
- Signed-in session,
X-API-Key, or a Bramble app access token (Authorization: Bearer).
Role:GLOBAL_ADMIN.
Path parameters
| Name | Type | Description |
|---|---|---|
guestIdrequired | integer |
Response 200
| Field | Type | Description |
|---|---|---|
message | string |
Example response
{
"message": "Saved"
}Errors
| Status | Message |
|---|---|
| 404 | Guest not found |
Example request
curl -X POST 'https://<your-org>.brambleit.cloud/api/v1/admin/guests/1/resend' \
-H "X-API-Key: $BRAMBLE_KEY"const res = await fetch('https://<your-org>.brambleit.cloud/api/v1/admin/guests/1/resend', {
method: 'POST',
headers: { 'X-API-Key': process.env.BRAMBLE_KEY },
});
const data = await res.json();import os, requests
r = requests.post(
"https://<your-org>.brambleit.cloud/api/v1/admin/guests/1/resend",
headers={"X-API-Key": os.environ["BRAMBLE_KEY"]},
)
r.raise_for_status()
data = r.json()$headers = @{ 'X-API-Key' = $env:BRAMBLE_KEY }
Invoke-RestMethod -Method POST -Uri 'https://<your-org>.brambleit.cloud/api/v1/admin/guests/1/resend' -Headers $headers#Revoke a guest's access
/v1/admin/guests/:guestId/revokeRevoke a guest's access. Requires the GLOBAL_ADMIN role. Non-destructive (sets status=0, row kept), same pattern as POST /admin/portal/contacts/{userId}/revoke; also kills any active sessions.
- Address
https://<your-org>.brambleit.cloud/api/v1/admin/guests/:guestId/revoke- Requires
- Signed-in session,
X-API-Key, or a Bramble app access token (Authorization: Bearer).
Role:GLOBAL_ADMIN.
Path parameters
| Name | Type | Description |
|---|---|---|
guestIdrequired | integer |
Response 200
| Field | Type | Description |
|---|---|---|
message | string |
Example response
{
"message": "Saved"
}Errors
| Status | Message |
|---|---|
| 404 | Guest not found |
Example request
curl -X POST 'https://<your-org>.brambleit.cloud/api/v1/admin/guests/1/revoke' \
-H "X-API-Key: $BRAMBLE_KEY"const res = await fetch('https://<your-org>.brambleit.cloud/api/v1/admin/guests/1/revoke', {
method: 'POST',
headers: { 'X-API-Key': process.env.BRAMBLE_KEY },
});
const data = await res.json();import os, requests
r = requests.post(
"https://<your-org>.brambleit.cloud/api/v1/admin/guests/1/revoke",
headers={"X-API-Key": os.environ["BRAMBLE_KEY"]},
)
r.raise_for_status()
data = r.json()$headers = @{ 'X-API-Key' = $env:BRAMBLE_KEY }
Invoke-RestMethod -Method POST -Uri 'https://<your-org>.brambleit.cloud/api/v1/admin/guests/1/revoke' -Headers $headersWas this page helpful?
Thanks for your feedback.