Customers
Manage customers, contacts, locations, and tags via the Zoop MCP tool layer.
This page covers every MCP tool for reading and writing customer data in Zoop.
A customer record holds core identity fields plus two child resources: contacts (the people you call or email) and locations (the service addresses you dispatch to). Tags are shared labels — one library per account — that you attach to customers to organize them.
All tools in this group require the read:customers or write:customers scope (a scope is a named permission you grant your API token — see Scopes). Contacts, locations, and tags share those two scopes; they do not have their own.
If you are new to the MCP layer, start at MCP overview to learn how to connect and authenticate.
Scopes
| Scope | Grants access to |
|---|---|
read:customers | customers.search, customers.get, contacts.list, contacts.get, locations.list, locations.get, tags.list, tags.get |
write:customers | customers.create, customers.update, customers.archive, contacts.create, contacts.update, contacts.archive, locations.create, locations.update, locations.archive, tags.create, tags.update, tags.delete |
write:customers does not imply read:customers. If your integration needs to both read and write, request both scopes.
Customers
customers.search
Search customers by name, phone, tag, or status. Returns a list of matching customers, each with an id you can pass to other tools. If you only have a name or phone number and need the customer's id, start here.
Free-text search string. Matches against name and phone fields.
Filter by status. One of active, inactive, or archived.
Filter by customer type. One of individual or company.
Filter to customers that have this tag assigned. Pass the tag id, not the tag name.
Pagination cursor. Copy the nextCursor value from a previous response to fetch the next page. Omit this on your first request.
Number of results per page. Integer between 1 and 100.
Example
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "customers.search",
"arguments": {
"q": "Nguyen",
"status": "active",
"limit": 20
}
}
}
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "{"rows":[{"id":"a1b2c3d4-...","display_name":"Hana Nguyen","customer_type":"individual","status":"active","primary_phone":"+15105550123","primary_email":"hana@example.com"}],"nextCursor":null,"hasMore":false}"
}
]
}
}
customers.get
Fetch one customer's full record by id, including their contacts and locations.
The customer's id. Get this from customers.search.
customers.create
Create a new customer. The customer_type field determines which other fields are required.
- For
individual:first_nameis required. - For
company:company_nameis required.
You cannot change customer_type after creation, so pick the right one up front.
individual or company.
Given name. Required when customer_type is individual.
Family name. Optional for individuals.
Business name. Required when customer_type is company.
Phone number in any common format (e.g. (510) 555-0199). Zoop converts it to E.164 format (e.g. +15105550199) and stores both the original and the converted value.
Email address.
Internal notes visible only to your team. Max 10,000 characters.
For company customers only. Creates an initial contact at the same time as the company record.
Given name of the contact.
Family name of the contact.
Contact's phone number.
Contact's email address.
Creates an initial service location at the same time as the customer record. See location fields below for the full field list.
Example
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "customers.create",
"arguments": {
"customer_type": "individual",
"first_name": "Marco",
"last_name": "Reyes",
"phone": "(510) 555-0199",
"email": "marco@example.com",
"location": {
"address_line1": "482 Oak Street",
"city": "Oakland",
"state": "CA",
"postal_code": "94607"
}
}
}
}
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"content": [
{
"type": "text",
"text": "{"id":"c9d8e7f6-...","customer_type":"individual","customer_number":"C-0042","display_name":"Marco Reyes","status":"active","primary_phone":"+15105550199","primary_email":"marco@example.com","created_at":"2026-06-13T18:00:00.000Z"}"
}
]
}
}
customers.update
Update fields on an existing customer. This is a partial update — only the fields you include in the request are changed; everything else stays as-is. You cannot change customer_type.
The customer to update.
Updated given name (individuals only).
Updated family name (individuals only).
Updated business name (companies only).
Updated phone number.
Updated email address.
Updated internal notes.
Mark or unmark the customer as VIP.
Flag the customer as do-not-contact.
Reason for the do-not-contact flag. Max 500 characters. Pass null to clear.
How the customer was acquired (e.g. referral, google). Max 64 characters.
customers.archive
Archive a customer. Archived customers are hidden from default list views, but their record and all related history (jobs, invoices, notes) is fully preserved. Zoop does not hard-delete customers — use this instead.
The customer to archive.
Contacts
A contact is a person associated with a customer — someone you can call or email. Every customer has at least one contact, and the first one added becomes the primary contact automatically.
Every contact belongs to one customer. All contact tools require the parent customer_id so Zoop knows which customer you are working with.
contacts.list
List all contacts for a customer. The primary contact is returned first, then contacts in creation order.
The parent customer.
contacts.get
Fetch one contact by id.
The contact's id.
The parent customer's id. Required — contacts are scoped to a customer.
contacts.create
Add a contact to a customer. first_name and last_name are required. Phone numbers are automatically converted to E.164 format.
If you set is_primary: true and a primary contact already exists, Zoop promotes your new contact and demotes the previous primary — no extra call needed.
The parent customer.
Given name.
Family name.
Phone number. Converted to E.164 format; the original input is also stored.
Email address.
Set to true to make this the primary contact. Defaults to false. The first contact on a customer is promoted automatically regardless of this field.
Whether the phone number can receive SMS. Defaults to true.
The contact's role. One of billing, service, decision_maker, or general.
Job title or role description (free text).
contacts.update
Update a contact's fields. This is a partial update — only the fields you include change; everything else stays as-is. You cannot move a contact from one customer to another.
The contact to update.
The parent customer's id.
All other fields from contacts.create are accepted as optional updates.
contacts.archive
Archive a contact. Archived contacts are hidden from default views but their history is preserved.
The contact to archive.
The parent customer's id.
Locations
A location is a service address tied to a customer — where you send a crew. Every customer can have multiple locations. Each location has a type (service, billing, mailing, or other), and the first location of each type becomes the primary for that type automatically.
Like contacts, locations require the parent customer_id on every call.
To promote a different location to primary, you must do it in two steps: first call locations.update on the current primary with is_primary: false, then call locations.update on the new one with is_primary: true. Trying to create a location with is_primary: true when a primary already exists for that type returns a conflict error.
locations.list
List all service locations for a customer. The primary location comes first, then in creation order.
The parent customer.
locations.get
Fetch one location by id.
The location's id.
The parent customer's id.
locations.create
Add a service location to a customer. address_line1, city, state, and postal_code are required.
The parent customer.
Street address line 1.
Street address line 2 (unit, suite, etc.).
City name.
State or province code.
ZIP or postal code.
ISO country code. Defaults to US.
One of service, billing, mailing, or other. Defaults to service.
A human-readable nickname for the location (e.g. Warehouse, Rental unit #3).
Set to true only when no primary exists yet for this location_type. Defaults to false. See the warning above about promoting an existing location.
Gate codes, alarm codes, or other access instructions for the crew.
Parking or vehicle instructions for the crew.
Any other notes about the location relevant to service.
Latitude in decimal degrees (−90 to 90). Must be provided together with longitude if either is sent.
Longitude in decimal degrees (−180 to 180). Must be provided together with latitude if either is sent.
The Google Places place_id from address autocomplete, if available.
locations.update
Update a location's fields. This is a partial update — only the fields you include change; everything else stays as-is. You cannot move a location from one customer to another.
The location to update.
The parent customer's id.
All other fields from locations.create are accepted as optional updates.
locations.archive
Archive a location. Archived locations are hidden from default views but their history is preserved.
The location to archive.
The parent customer's id.
Tags
Tags are shared labels for your whole account. Each tag is a name-and-color pair you attach to customers to organize them (e.g. VIP, Seasonal, HOA). Tags belong to the account, not to individual customers, so none of the tag tools require a customer_id.
tags.delete permanently removes the tag and all its customer assignments. This cannot be undone — there is no archive for tags. Double-check the id before calling this.
Attaching and detaching tags from customers is not yet available as an MCP tool. See MCP overview — limitations for what is out of scope in v1.
tags.list
List all customer tags for this account, ordered by name. Tags are shared across the whole account, not tied to individual customers.
No input parameters.
tags.get
Fetch one tag by id.
The tag's id.
tags.create
Create a customer tag. The name must be unique within the tenant.
tags.create requires a token that identifies a specific user. API keys that are scoped only to the account (with no associated user) cannot call this tool. Use a user-bound API key or an OAuth token instead. See API keys if you are unsure which type you have.
Display name for the tag. Max 64 characters. Must be unique within the tenant.
Hex color in #RRGGBB format (e.g. #3B82F6). The server supplies a default when omitted.
tags.update
Rename or recolor a tag. This is a partial update — omit any field you do not want to change. Renaming to a name that already exists in the account returns a conflict error.
The tag to update.
New name. Max 64 characters.
New hex color in #RRGGBB format.
tags.delete
Permanently delete a tag. This removes the tag and all customer assignments. It cannot be undone.
The tag to delete.
Error reference
When a tool call fails, Zoop returns a JSON-RPC error result (isError: true). The kind field tells you what went wrong.
| Kind | What it means | Common cause |
|---|---|---|
invalid_input | A field failed validation, or a required actor condition was not met | Missing required field, wrong type, tags.create called with a tenant-key token |
not_found | The referenced customer, contact, location, or tag does not exist in this tenant | Stale or wrong id, record already archived |
conflict | The request collides with existing state | Duplicate tag name, creating a second primary location of the same type |
insufficient_scope | The token does not hold the required scope | Missing read:customers or write:customers |
internal | Unexpected server or database error | A generic message is surfaced; details are never sent to the client |
For the full error shape and HTTP status codes, see Errors.