Developer docs
MCP server
Connect any AI assistant that supports MCP to your shop. It works as you, with the permissions you give its key.
Looking for the overview instead? See AI agents.
At a glance
| Endpoint | POST https://app.repair-receipts.com/api/mcp |
|---|---|
| Transport | Streamable HTTP, stateless, JSON responses |
| Auth | Authorization: Bearer rr_live_… |
| Plan | Established (pricing) |
| Rate limit | 120 requests per minute per key |
1. Create an API key
- In Repair Receipts, open Settings, then Integrations, then API and AI Agents.
- Name the key after what will use it, for example "Grok quoting bot".
- Pick its permissions and, if you like, an expiry of 30, 90, or 365 days.
- Copy the key. It is shown once. We store only a hash of it, so it can't be shown again.
A key acts as the person who created it, inside the shop it was created in. It can never see more than that person can. Revoke a key from the same screen and it stops working on the next request.
2. Permissions
| Permission | Grants |
|---|---|
read | Search and read customers, vehicles, invoices, estimates, appointments, parts and labor, VIN decoding, and shop pricing. Every key has it. |
write | Create customers, draft invoices, and appointments. |
send | Create links that are shared with a customer, such as invoice signature links. |
Tools outside a key's permissions are hidden from the assistant. It can't call what it can't see.
3. Connect your assistant
Claude, Cursor, and other MCP clients
Any client that supports remote HTTP MCP servers takes a config like this. Settings shows it filled in after you create a key.
{
"mcpServers": {
"repair-receipts": {
"type": "http",
"url": "https://app.repair-receipts.com/api/mcp",
"headers": {
"Authorization": "Bearer rr_live_YOUR_KEY"
}
}
}
}Groq
Groq's Responses API calls remote MCP servers directly. Add allowed_tools to narrow it further.
import os, openai
client = openai.OpenAI(
api_key=os.environ["GROQ_API_KEY"],
base_url="https://api.groq.com/openai/v1",
)
response = client.responses.create(
model="openai/gpt-oss-120b",
input="Draft an invoice for Ana Lopez's 2018 Honda CR-V: replace both front struts.",
tools=[{
"type": "mcp",
"server_label": "repair_receipts",
"server_url": "https://app.repair-receipts.com/api/mcp",
"headers": {"Authorization": f"Bearer {os.environ['REPAIR_RECEIPTS_API_KEY']}"},
"require_approval": "never",
}],
)
print(response.output_text)Grok (xAI)
Pass the key as authorization in xAI's remote MCP tool. The server accepts it with or without the Bearer prefix.
{
"type": "mcp",
"server_label": "repair_receipts",
"server_url": "https://app.repair-receipts.com/api/mcp",
"authorization": "rr_live_YOUR_KEY"
}Check it works
This lists the tools your key can use.
curl -s https://app.repair-receipts.com/api/mcp \
-H "Authorization: Bearer $REPAIR_RECEIPTS_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'4. Tools
| Tool | Permission | What it does |
|---|---|---|
search_customers | read | Find customers by name, company, phone number, or exact VIN. Returns their vehicles with ids. |
get_customer | read | Contact details, vehicles, and the 10 most recent invoices. |
search_parts_labor | read | Part list prices and book labor hours for a vehicle, by VIN or year, make, and model. |
decode_vin | read | Year, make, model, trim, and engine for a 17 character VIN. |
get_shop_pricing | read | Your labor rate, parts matrix, and default taxes. |
list_invoices | read | Invoices newest first. Filter by status, customer, vehicle, number, description, or dates. |
get_invoice | read | One invoice with line items, taxes, totals, and a link to open it. |
list_estimates | read | Estimates, most recently updated first. |
get_estimate | read | One estimate with line items and totals. |
list_appointments | read | Appointments in a time window of up to 62 days. |
create_customer | write | Create a customer. Returns the existing one if the phone number is already on file. |
create_invoice | write | Create a draft invoice priced with your shop's rules. See below. |
create_appointment | write | Put a job on the shop calendar. |
create_signature_link | send | The public link a customer opens to review and sign an invoice. |
Each tool publishes a JSON schema for its input, so your assistant knows the exact fields.
5. Creating invoices
A typical request, such as "2018 CR-V, two front struts", runs in three steps.
search_customersfinds the customer and the vehicle id.search_parts_laborreturns strut prices and book labor hours for that vehicle.create_invoicewrites the draft and returns a link to open it.
{
"customerId": "c0ffee00-0000-4000-8000-000000000001",
"vehicleId": "c0ffee00-0000-4000-8000-000000000002",
"description": "Replace both front struts",
"items": [
{
"type": "parts",
"description": "Front strut assembly",
"quantity": 2,
"unitCost": 120
},
{
"type": "labor",
"description": "R&R front struts",
"quantity": 2.4
}
]
}Pricing is worked out on our side, with your settings:
- A
unitPrice, when given, is used as is. - Parts without a price get your parts matrix markup on
unitCost. - Labor without a price uses your shop labor rate.
quantityis hours. - Your default taxes are added unless
applyDefaultTaxesis false.
Invoices are always created as drafts. Every invoice needs a vehicle with a VIN. PassvehicleId for a vehicle on file, or vehicle with vin, year,make, and model. A new customer can be passed as newCustomer. If one with the same phone number exists, that customer is used.
Each create_invoice call makes a new invoice. Don't retry a call that succeeded. The invoice history notes which key created it.
6. Errors
Auth problems come back as a JSON-RPC error with an HTTP status.
| Status | Meaning |
|---|---|
401 | Missing, unknown, revoked, or expired key. |
403 | The plan doesn't include API access, or the key's owner left the shop it was created in. |
429 | More than 120 requests a minute on one key. Wait and retry. |
503 | API access is temporarily unavailable. Retry shortly. |
Problems inside a tool, such as a customer that doesn't exist or a missing VIN, come back as a tool result withisError: true and a message the assistant can act on.
7. Keeping your shop safe
- Give each assistant its own key, with only the permissions it needs.
- Keep keys out of code you share. Use an environment variable.
- Customer names and notes are text the assistant reads. Review drafts before you send them.
- Revoke any key you think has leaked. Then create a new one.