Get startedIntroduction

Introduction

Build on Zoop with a 65-tool MCP API, secured by API keys or OAuth 2.1.

This page explains how the Zoop API works and how to make your first request.

Zoop's API is built on MCP (Model Context Protocol) — an open standard for calling structured tools over HTTP. You send a request to one endpoint, name the tool you want to run (for example customers.search), and get back structured data. This is the same tool layer the in-product Zoop AI agent uses, exposed as a stable API for your own integrations.

There is no OpenAPI/REST spec yet. All programmatic access goes through the MCP endpoint described here.

What you can build

A few examples of what the API makes possible:

  • AI agents and chatbots — connect Claude Desktop, LangGraph, n8n, or any MCP-capable agent framework to a contractor's Zoop account so it can look up customers, create jobs, draft invoices, and more.
  • Reporting dashboards — pull jobs, invoices, and quotes into your own data warehouse or BI tool.
  • Automation scripts — create jobs or notes in bulk, sync customers from an external CRM, or trigger follow-up tasks when a job is marked done.
  • Internal tools — build a custom dispatch interface or field-tech mobile view on top of the same data Zoop uses.

The API surface

Endpoint: POST /api/mcp

There is one endpoint. Every request is a POST to that path — you do not need a tenant ID in the URL. The tenant your request operates on is determined by your access token, not the path.

Requests use JSON-RPC 2.0 format: a JSON body with a method field naming the action and a params field carrying the arguments. You will see full examples in Making your first request below.

The server advertises 65 tools across 13 entities:

EntityTools include
Customerssearch, get, create, update, archive
Contactslist, get, create, update, archive
Locationslist, get, create, update, archive
Tagslist, get, create, update, delete
Noteslist, get, create, update, archive
Jobslist, get, create, update, cancel
Job serieslist, get, create, update, end
Invoiceslist, get, create, update, void
Quoteslist, get, create, update, archive
Catalog itemslist, get, create, update, archive
Catalog categorieslist, get, create, update, delete
Planslist, get, create, update, cancel
Tax rateslist, get, create, update, archive

Every entity follows the same five-verb shape: list or search, get one, create, update (partial patch), and a destructive verb (void, cancel, archive, or delete). The full catalog with scope requirements is in MCP tools.

Authentication

Every request needs an Authorization: Bearer <token> header. A bearer token is a secret string your code sends to prove it has permission to act on a Zoop account. Two token types are accepted:

Key prefixes

When you issue an API key you choose the actor type. The prefix on the key tells you which type you have:

PrefixActor typeHas a user identity
zoop_uk_User keyYes — writes are attributed to the issuing user
zoop_tk_Tenant keyNo — reads and un-attributed writes only

Use a user key when you need actions recorded against a specific person (for example, created_by on a new job). Use a tenant key for background scripts and read-only integrations.

Tools that require a real user identity are marked U in the tool catalog and can only be called with a user key or an OAuth token.

Scopes

Scopes are permissions attached to a token that control which tools it can call. They follow a read:<entity> / write:<entity> pattern — for example, read:customers or write:jobs. You choose scopes when you create an API key in Settings → API & MCP.

If your token is missing a required scope, you get a 403 insufficient_scope response that names the missing scope — so you know exactly which permission to add.

The full scope list is in Authentication — scopes.

Making your first request

The example below calls tools/list — a built-in method that returns all the tools your token can access. It is a safe, read-only call you can use to confirm your token works before writing any real integration code.

Replace zoop_uk_<secret> with your actual API key, and replace https://app.zoop.example with your Zoop app host.

curl -X POST https://app.zoop.example/api/mcp \
  -H "Authorization: Bearer zoop_uk_<secret>" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'

A successful response returns a JSON object containing a list of tool definitions. If you get a 401, your token is invalid or expired. If you get a 403, a required scope is missing — check the error message for which one.

To call a specific tool, change method to tools/call and add a params body. The example below searches for customers matching "Henderson":

curl -X POST https://app.zoop.example/api/mcp \
  -H "Authorization: Bearer zoop_uk_<secret>" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{
    "jsonrpc": "2.0",
    "id": 2,
    "method": "tools/call",
    "params": {
      "name": "customers.search",
      "arguments": { "q": "Henderson" }
    }
  }'

The Accept: application/json, text/event-stream header is required on every request. Without it, the endpoint will reject the call. Include it exactly as shown above.

Error responses

Auth failures (bad token, missing scope) return standard HTTP error codes (401, 403). All other tool failures return HTTP 200 with a JSON error object inside the response body — this is how JSON-RPC works, and it catches many developers off guard. Always check the response body, not just the HTTP status. The error message field is human-readable. Common cases:

SituationHTTP statusError kind
Missing or invalid token401
Token expired401
Insufficient scope403insufficient_scope
Input failed validation200 (RPC error)invalid_input
Record not found200 (RPC error)not_found
Conflicting state200 (RPC error)conflict
Rate limited429— (see Retry-After header)

See Errors and Rate limits for full details.

Next steps