Customers

Customers (organisations), their agreements, and their links to RMM sites and to a Bramble organisation.

MethodPathSummary
GET/v1/app/psa/customersList customers
POST/v1/app/psa/customersCreate customer
POST/v1/app/psa/customers/:idUpdate customer
POST/v1/app/psa/customers/:id/deleteDelete customer
GET/v1/app/psa/customers/:id/contactsContacts for a customer
GET/v1/app/psa/customers/:id/ticketsTickets for a customer
GET/v1/app/psa/customers/:id/devices════════════════════════════════════════════════════════════════════════════════ CUSTOMER ↔ RMM DEVICES (RMM-license gated) ════════════════════════════════…
GET/v1/app/psa/rmm-sitesRMM sites (to link to customers)
POST/v1/app/psa/customers/:id/link-siteLink a customer to an RMM site
GET/v1/app/psa/customers/:id/linksOne customer record (ticket #85, services/customerLinks.js): the RMM sites and the customer's own Bramble organisation linked to a PSA customer, plus what co…
GET/v1/app/psa/customers/:id/agreementA customer's agreement
POST/v1/app/psa/customers/:id/agreementAdd an agreement line
PUT/v1/app/psa/customers/:id/agreement/:lineIdUpdate an agreement line
DELETE/v1/app/psa/customers/:id/agreement/:lineIdRemove an agreement line
PUT/v1/app/psa/customers/:id/bramble-tenantLink a customer to its Bramble organisation
POST/v1/app/psa/customers/:id/unlink-siteUnlink a customer from an RMM site

#List customers

GET/v1/app/psa/customers
Address
https://<your-org>.brambleit.cloud/api/v1/app/psa/customers
Requires
Signed-in session, X-API-Key, or a Bramble app access token (Authorization: Bearer).
Licence: PSA.

Response 200

FieldTypeDescription
customersarray of object
customers[].idinteger
customers[].tenant_idinteger
customers[].namestring
customers[].domainstring, or null
customers[].phonestring, or null
customers[].addressstring, or null
customers[].notesstring, or null
customers[].account_manager_idinteger, or null
customers[].created_atstring (date-time), or null
customers[].updated_atstring (date-time), or null
customers[].statusstring
customers[].org_typestring, or null
customers[].short_namestring, or null
customers[].websitestring, or null
customers[].alert_notestring, or null
customers[].primary_contact_idinteger, or null
customers[].logo_file_idinteger, or null
customers[].bramble_tenant_idinteger, or null
customers[].customer_type_idinteger, or null
customers[].contact_countboolean
customers[].open_ticket_countboolean
Example response
JSON
{
  "customers": [
    {
      "id": 42,
      "tenant_id": 1,
      "name": "Example name",
      "domain": "string",
      "phone": "string",
      "address": "string",
      "notes": "string",
      "account_manager_id": 7,
      "created_at": "2026-11-12T09:30:00.000Z",
      "updated_at": "2026-11-12T09:30:00.000Z",
      "status": "active",
      "org_type": "string",
      "short_name": "Example short name",
      "website": "string",
      "alert_note": "string",
      "primary_contact_id": 7,
      "logo_file_id": 7,
      "bramble_tenant_id": 7,
      "customer_type_id": 7,
      "contact_count": false,
      "open_ticket_count": false
    }
  ]
}

Example request

Bash
curl -X GET 'https://<your-org>.brambleit.cloud/api/v1/app/psa/customers' \
  -H "X-API-Key: $BRAMBLE_KEY"

#Create customer

POST/v1/app/psa/customers
Address
https://<your-org>.brambleit.cloud/api/v1/app/psa/customers
Requires
Signed-in session, X-API-Key, or a Bramble app access token (Authorization: Bearer).
Licence: PSA.

Request body JSON

NameTypeDescription
namerequiredstring
domainstring
phoneany
addressany
notesarray of any
account_manager_idinteger

Response 200

FieldTypeDescription
customerany
Example response
JSON
{
  "customer": null
}

Errors

StatusMessage
400name is required

Example request

Bash
curl -X POST 'https://<your-org>.brambleit.cloud/api/v1/app/psa/customers' \
  -H "X-API-Key: $BRAMBLE_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"Example name","domain":"string","phone":"…","address":"…","notes":[],"account_manager_id":7}'

#Update customer

POST/v1/app/psa/customers/:id
Address
https://<your-org>.brambleit.cloud/api/v1/app/psa/customers/:id
Requires
Signed-in session, X-API-Key, or a Bramble app access token (Authorization: Bearer).
Licence: PSA.

Path parameters

NameTypeDescription
idrequiredinteger

Request body JSON

NameTypeDescription
namestring
domainstring
phoneany
addressany
notesarray of any
account_manager_idinteger

Response 200

FieldTypeDescription
customerany
Example response
JSON
{
  "customer": null
}

Errors

StatusMessage
404Customer not found

Example request

Bash
curl -X POST 'https://<your-org>.brambleit.cloud/api/v1/app/psa/customers/42' \
  -H "X-API-Key: $BRAMBLE_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"Example name","domain":"string","phone":"…","address":"…","notes":[],"account_manager_id":7}'

#Delete customer

POST/v1/app/psa/customers/:id/delete
Address
https://<your-org>.brambleit.cloud/api/v1/app/psa/customers/:id/delete
Requires
Signed-in session, X-API-Key, or a Bramble app access token (Authorization: Bearer).
Licence: PSA.

Path parameters

NameTypeDescription
idrequiredinteger

Response 200

FieldTypeDescription
successboolean
Example response
JSON
{
  "success": true
}

Example request

Bash
curl -X POST 'https://<your-org>.brambleit.cloud/api/v1/app/psa/customers/42/delete' \
  -H "X-API-Key: $BRAMBLE_KEY"

#Contacts for a customer

GET/v1/app/psa/customers/:id/contacts
Address
https://<your-org>.brambleit.cloud/api/v1/app/psa/customers/:id/contacts
Requires
Signed-in session, X-API-Key, or a Bramble app access token (Authorization: Bearer).
Licence: PSA.

Path parameters

NameTypeDescription
idrequiredinteger

Response 200

FieldTypeDescription
contactsarray of object
contacts[].idinteger
contacts[].tenant_idinteger
contacts[].customer_idinteger, or null
contacts[].first_namestring
contacts[].last_namestring
contacts[].emailstring, or null
contacts[].phonestring, or null
contacts[].job_titlestring, or null
contacts[].notesstring, or null
contacts[].created_atstring (date-time), or null
contacts[].updated_atstring (date-time), or null
contacts[].mobilestring, or null
contacts[].contact_typestring, or null
contacts[].location_idinteger, or null
contacts[].is_importantboolean
Example response
JSON
{
  "contacts": [
    {
      "id": 42,
      "tenant_id": 1,
      "customer_id": 7,
      "first_name": "Alex",
      "last_name": "Morgan",
      "email": "alex@example.com",
      "phone": "string",
      "job_title": "Example job title",
      "notes": "string",
      "created_at": "2026-11-12T09:30:00.000Z",
      "updated_at": "2026-11-12T09:30:00.000Z",
      "mobile": "string",
      "contact_type": "string",
      "location_id": 7,
      "is_important": true
    }
  ]
}

Example request

Bash
curl -X GET 'https://<your-org>.brambleit.cloud/api/v1/app/psa/customers/42/contacts' \
  -H "X-API-Key: $BRAMBLE_KEY"

#Tickets for a customer

GET/v1/app/psa/customers/:id/tickets
Address
https://<your-org>.brambleit.cloud/api/v1/app/psa/customers/:id/tickets
Requires
Signed-in session, X-API-Key, or a Bramble app access token (Authorization: Bearer).
Licence: PSA.

Path parameters

NameTypeDescription
idrequiredinteger

Response 200

FieldTypeDescription
ticketsarray of object
tickets[].idinteger
tickets[].subjectstring
tickets[].statusstring: "open" | "pending" | "on-hold" | "closed"
tickets[].prioritystring: "low" | "medium" | "high" | "critical"
tickets[].updated_atstring (date-time), or null
Example response
JSON
{
  "tickets": [
    {
      "id": 42,
      "subject": "Example subject",
      "status": "open",
      "priority": "low",
      "updated_at": "2026-11-12T09:30:00.000Z"
    }
  ]
}

Example request

Bash
curl -X GET 'https://<your-org>.brambleit.cloud/api/v1/app/psa/customers/42/tickets' \
  -H "X-API-Key: $BRAMBLE_KEY"

#════════════════════════════════════════════════════════════════════════════════ CUSTOMER ↔ RMM DEVICES (RMM-license gated) ════════════════════════════════…

GET/v1/app/psa/customers/:id/devices

════════════════════════════════════════════════════════════════════════════════ CUSTOMER ↔ RMM DEVICES (RMM-license gated) ════════════════════════════════════════════════════════════════════════════════ Reuses bramble_rmm.sites.client_id (added by BRM-Schemas/2026-08-02_rmm_site_client_scoping.sql for the client-portal "your devices" feature — see v1-appPortal.js GET /devices for the same join) rather than a new per-device table: a customer is tagged by linking one or more RMM sites to it, and every device at a linked site counts as that customer's. Previously only settable from BRM-Admin's RMM site editor (v1-admin.js POST/PUT /rmm/sites) with no PSA-side UI at all.

Address
https://<your-org>.brambleit.cloud/api/v1/app/psa/customers/:id/devices
Requires
Signed-in session, X-API-Key, or a Bramble app access token (Authorization: Bearer).
Licence: PSA.
Licence: RMM.

Path parameters

NameTypeDescription
idrequiredinteger

Response 200

FieldTypeDescription
sitesarray of any
devicesarray of any
Example response
JSON
{
  "sites": [],
  "devices": []
}

Example request

Bash
curl -X GET 'https://<your-org>.brambleit.cloud/api/v1/app/psa/customers/42/devices' \
  -H "X-API-Key: $BRAMBLE_KEY"

#RMM sites (to link to customers)

GET/v1/app/psa/rmm-sites
Address
https://<your-org>.brambleit.cloud/api/v1/app/psa/rmm-sites
Requires
Signed-in session, X-API-Key, or a Bramble app access token (Authorization: Bearer).
Licence: PSA.
Licence: RMM.

Response 200

FieldTypeDescription
sitesarray of object
sites[].idinteger
sites[].site_namestring
sites[].client_idinteger, or null
Example response
JSON
{
  "sites": [
    {
      "id": 42,
      "site_name": "Example site name",
      "client_id": 7
    }
  ]
}

Example request

Bash
curl -X GET 'https://<your-org>.brambleit.cloud/api/v1/app/psa/rmm-sites' \
  -H "X-API-Key: $BRAMBLE_KEY"

#Link a customer to an RMM site

POST/v1/app/psa/customers/:id/link-site
Address
https://<your-org>.brambleit.cloud/api/v1/app/psa/customers/:id/link-site
Requires
Signed-in session, X-API-Key, or a Bramble app access token (Authorization: Bearer).
Licence: PSA.
Licence: RMM.

Path parameters

NameTypeDescription
idrequiredinteger

Request body JSON

NameTypeDescription
site_idrequiredintegerThe RMM site.

Response 200

FieldTypeDescription
successboolean
Example response
JSON
{
  "success": true
}

Errors

StatusMessage
400site_id required
404Customer not found
404Site not found

Example request

Bash
curl -X POST 'https://<your-org>.brambleit.cloud/api/v1/app/psa/customers/42/link-site' \
  -H "X-API-Key: $BRAMBLE_KEY" \
  -H "Content-Type: application/json" \
  -d '{"site_id":7}'

#A customer's agreement

GET/v1/app/psa/customers/:id/agreement
Address
https://<your-org>.brambleit.cloud/api/v1/app/psa/customers/:id/agreement
Requires
Signed-in session, X-API-Key, or a Bramble app access token (Authorization: Bearer).
Licence: PSA.

Path parameters

NameTypeDescription
idrequirednumber

Example request

Bash
curl -X GET 'https://<your-org>.brambleit.cloud/api/v1/app/psa/customers/12.5/agreement' \
  -H "X-API-Key: $BRAMBLE_KEY"

#Add an agreement line

POST/v1/app/psa/customers/:id/agreement
Address
https://<your-org>.brambleit.cloud/api/v1/app/psa/customers/:id/agreement
Requires
Signed-in session, X-API-Key, or a Bramble app access token (Authorization: Bearer).
Licence: PSA.

Path parameters

NameTypeDescription
idrequirednumber

Example request

Bash
curl -X POST 'https://<your-org>.brambleit.cloud/api/v1/app/psa/customers/12.5/agreement' \
  -H "X-API-Key: $BRAMBLE_KEY"

#Update an agreement line

PUT/v1/app/psa/customers/:id/agreement/:lineId
Address
https://<your-org>.brambleit.cloud/api/v1/app/psa/customers/:id/agreement/:lineId
Requires
Signed-in session, X-API-Key, or a Bramble app access token (Authorization: Bearer).
Licence: PSA.

Path parameters

NameTypeDescription
idrequirednumber
lineIdrequirednumber

Example request

Bash
curl -X PUT 'https://<your-org>.brambleit.cloud/api/v1/app/psa/customers/12.5/agreement/12.5' \
  -H "X-API-Key: $BRAMBLE_KEY"

#Remove an agreement line

DELETE/v1/app/psa/customers/:id/agreement/:lineId
Address
https://<your-org>.brambleit.cloud/api/v1/app/psa/customers/:id/agreement/:lineId
Requires
Signed-in session, X-API-Key, or a Bramble app access token (Authorization: Bearer).
Licence: PSA.

Path parameters

NameTypeDescription
idrequirednumber
lineIdrequirednumber

Example request

Bash
curl -X DELETE 'https://<your-org>.brambleit.cloud/api/v1/app/psa/customers/12.5/agreement/12.5' \
  -H "X-API-Key: $BRAMBLE_KEY"

#Link a customer to its Bramble organisation

PUT/v1/app/psa/customers/:id/bramble-tenant
Address
https://<your-org>.brambleit.cloud/api/v1/app/psa/customers/:id/bramble-tenant
Requires
Signed-in session, X-API-Key, or a Bramble app access token (Authorization: Bearer).
Licence: PSA.

Path parameters

NameTypeDescription
idrequirednumber

Request body JSON

NameTypeDescription
tenant_idintegerThe customer's Bramble organisation (for MSPs managing them as a partner).

Response 200

Example request

Bash
curl -X PUT 'https://<your-org>.brambleit.cloud/api/v1/app/psa/customers/12.5/bramble-tenant' \
  -H "X-API-Key: $BRAMBLE_KEY" \
  -H "Content-Type: application/json" \
  -d '{"tenant_id":1}'

#Unlink a customer from an RMM site

POST/v1/app/psa/customers/:id/unlink-site
Address
https://<your-org>.brambleit.cloud/api/v1/app/psa/customers/:id/unlink-site
Requires
Signed-in session, X-API-Key, or a Bramble app access token (Authorization: Bearer).
Licence: PSA.
Licence: RMM.

Path parameters

NameTypeDescription
idrequiredinteger

Request body JSON

NameTypeDescription
site_idrequiredinteger

Response 200

FieldTypeDescription
successboolean
Example response
JSON
{
  "success": true
}

Errors

StatusMessage
400site_id required
404Site not found or not linked to this customer

Example request

Bash
curl -X POST 'https://<your-org>.brambleit.cloud/api/v1/app/psa/customers/42/unlink-site' \
  -H "X-API-Key: $BRAMBLE_KEY" \
  -H "Content-Type: application/json" \
  -d '{"site_id":7}'