Developer API & Webhooks
Create a secret API key in Settings → Developer Reference → API Keys, choose exactly what it may read or change, and connect Joby to Zapier or your own software. Also covers the webhook trigger and webhook action inside Automations.
You'll need Owner or Admin access for this.
Video walkthrough coming soon
Want this one filmed next? Request it
Admins only
Only users with the Admin role can open Settings›Admin›Developer Reference and create or revoke API keys. A developer can build the integration, but an admin has to create the key and hand it over.
What it is
The Joby API lets other software read and update the records in your Joby account — leads, clients, appointments, tasks, estimates, and invoices — without anybody typing them in twice.
To use it you create a secret key on the API Keys tab of Settings›Admin›Developer Reference. Each key is tied to your organization, and you tick exactly which records it may read, create, or update. A key can be revoked at any time, which stops the connected tool immediately.
The same screen also shows a Recent requests list so you can see what an outside tool has actually been doing.
No code? Use Zapier instead
If you only want Joby to talk to another business app, go to Settings›Integrations›Zapier and press Connect Zapier. Joby builds the key for you. See Connect Zapier without writing code below.
When to use it
- Push leads into Joby from your website form, a landing page, or another lead provider.
- Copy jobs, estimates, or invoices into your bookkeeping or reporting spreadsheet.
- Feed a dashboard, an internal tool, or a custom assistant with live Joby data.
- Keep a second system (dispatch board, warehouse tool, customer portal) in step with Joby.
If you instead want Joby to react to something happening inside Joby — send a text, create a task, notify a manager, or post data to an outside address — build that in Automations rather than in code. See Webhooks inside Automations.
Before you start
- You are signed in with the Admin role. Without it the Settings pages are hidden and you are sent back to the Dashboard.
- You can see the API Keys tab on Settings›Admin›Developer Reference. If that tab is missing, developer access is switched off for your account — contact Joby support to turn it back on.
- Your subscription is active. A locked or unpaid workspace has its API access blocked along with everything else.
- You have somewhere safe to store the key — a password manager, not a spreadsheet or a chat message.
- You know which records the outside tool actually needs, so you can grant the smallest set of permissions.
Step-by-step
Create a secret key
- Go to Settings›Admin›Developer Reference.
- Open the API Keys tab.
- In the Create a new secret key card, type a Name you will recognise later — for example
Website formorBookkeeping export. The name is limited to 80 characters. - Set Requests/min. This caps how many requests that key may make each minute. The default is
60, and you can set anything from1to300. - Optionally set an Expires date. After that date the key stops working on its own. Leave it blank for a key that never expires.
- Under Permissions, tick the boxes for what this key may do. Rows are the record types and columns are Read, Create, and Update.
- Press Generate secret key. The button stays greyed out until you have entered a name and ticked at least one permission.
- A Copy this key now box appears with the full key. Press the copy button and paste it into your password manager straight away.
The full key is shown one time only
After you leave that screen, the Secret keys list only shows the first few characters of the key. Joby cannot recover the rest. If you lose it, create a new key and revoke the old one.
Make your first request
- Press Copy base URL at the top right of the API Keys tab. That is the web address every request goes to.
- In the Quick start card, press Copy cURL. If you just created a key, the sample already has your key filled in.
- Paste it into your terminal, or hand it to whoever is building the integration.
curl "https://api.joby.io/v1/leads?limit=10" \
-H "Authorization: Bearer YOUR_JOBY_API_KEY" \
-H "Accept: application/json"Your key can be sent either way — as Authorization: Bearer <key> or as an X-Joby-API-Key: <key> header. Use one or the other, not both. Always send requests over https.
How to check it worked
- Run the sample request. A working key returns
200and a body shaped like{ "data": [ … ], "limit": 10, "offset": 0, "request_id": "…" }. - Go back to Settings›Admin›Developer Reference›API Keys and refresh the page.
- The Last request tile at the top should now say something like Just now, and Stored requests should have gone up.
- In the Secret keys list, the Last used column for that key should show a recent time instead of Never.
- Scroll to Recent requests. You should see a row with the time, the request, a green status code, and a request ID you can quote to support if something looks wrong.
Handy check for developers
Calling /schema instead of /leads returns a list of every record type the API supports, which permission each one needs, which fields can be sent, and which filters are accepted. It is the fastest way to confirm a key is valid and see what it is allowed to touch.
Common mistakes
Losing the key
Closing the page before copying
The full key is displayed once. Copy it into a password manager before you navigate away. Otherwise you have to create a replacement and revoke the old one.
Too much access
Ticking every permission box
A reporting tool that only reads leads needs Leads›Read and nothing else. Extra ticks only add risk if the key ever leaks.
Wrong permission
A 403 that looks like a broken key
A key with only Read ticked gets refused when it tries to create a record. The reply names the exact permission it wanted, so check that before assuming the key is bad.
Too many requests
Hitting the per-minute cap
If a tool is refused with a 429, either slow it down or raise Requests/min on a new key. The cap on an existing key cannot be edited after it is created.
Shared keys
One key for everything
Give every tool its own key. When one has to be revoked, the others keep running and you know exactly what broke.
Keys in the browser
Pasting a key into a web page
Anything in a public web page can be read by anyone visiting it. Keys belong on a server or inside the connected tool's own settings.
More detail (9)
What a key is allowed to do
The Permissions grid in the Create a new secret key card has one row per record type and three columns.
| Row | Read | Create | Update |
|---|---|---|---|
| Leads | Yes | Yes | Yes |
| Clients | Yes | Yes | Yes |
| Appointments | Yes | Yes | Yes |
| Tasks | Yes | Yes | Yes |
| Estimates | Yes | — | — |
| Invoices | Yes | — | — |
| Activity & timeline | Yes | — | — |
| Reference data | Yes | — | — |
Estimates and Invoices show a dash in the Create and Update columns because the API can only read them. If the words in the first column look different in your account — for example Jobs instead of Leads — that is because your organization renamed them in its own settings.
Reading your lead statuses is included with Leads›Read, so a reporting tool does not need a separate tick for it.
Choosing permissions well
- Start with Read only, confirm the tool works, then add Create or Update if it truly needs them.
- A website form that files new enquiries needs Leads›Create — not Update, not Clients.
- An export or dashboard almost never needs anything but Read.
- The ticks you choose are shown as small labels next to the key in the Secret keys list, so you can audit them later.
Records, filters, and page sizes
Every address starts with the base URL you copied, then the record type. A list request returns many records; adding an ID after the record type returns one.
GET /leads GET /leads/{id}
POST /leads PATCH /leads/{id}
GET /clients POST /clients PATCH /clients/{id}
GET /appointments POST /appointments PATCH /appointments/{id}
GET /tasks POST /tasks PATCH /tasks/{id}
GET /estimates (read only) GET /estimates/{id}/items
GET /invoices (read only) GET /invoices/{id}/items
GET /payments (read only)
GET /lead_statuses (read only, uses the Leads Read permission)
GET /job_types GET /service_areas GET /agents GET /estimate_templates
GET /custom_fields?target=lead|client (Reference data permission)
GET /reference everything above in one call
GET /search?q= find a customer by name, phone, email or lead number
GET /leads/{id}/timeline messages, calls, documents, tasks and payments on one lead
GET /schedule?date= jobs and appointments on a day (in your timezone)
GET /schema what this key is allowed to do
GET /openapi.json the OpenAPI 3.1 description of all of the above
POST /mcp the same operations as AI-assistant tools (see below)Paging and filters
limit— how many records to return. Default50, maximum1000.offset— how many to skip, for paging through a long list. Maximum10000.cursor— every list reply carriesnext_cursor; send it back ascursorto get the next page. Unlikeoffsetit has no ceiling, so use it to walk a whole account.created_sinceandupdated_since— only records added or changed on or after a date and time.q— a simple name search (first name for leads, clients, and appointments; title for tasks).order_by— sort by one of the returned fields. Results always come back newest first.- Exact matches per record type. For leads those are
id,lead_number,status,phone,email, andclient_id. Call/schemato see the list for every other record type.
What comes back
{
"data": [
{
"id": "…",
"lead_number": "…",
"first_name": "Dana",
"last_name": "Reyes",
"phone": "+15551234567",
"email": "dana@example.com",
"status": "New",
"primary_field_worker_id": "…",
"primary_field_worker_name": "Alex Kim",
"field_workers": [
{ "id": "…", "name": "Alex Kim", "is_primary": true, "assigned_at": "2026-02-26T14:05:00.000Z" }
],
"created_at": "2026-02-25T18:30:12.123Z"
}
],
"limit": 50,
"offset": 0,
"request_id": "…"
}Leads also carry their current Field Workers: primary_field_worker_id, primary_field_worker_name, and field_workers (everyone assigned right now, primary first). A removed Field Worker simply drops out of the list, so read these fields for the current team rather than rebuilding it from the timeline. Changing a lead's Field Workers does not change the lead's updated_at, so a sync that must catch assignment changes should re-read the leads it tracks.
A single record request returns data as one object instead of a list. Every reply also carries the same value in an X-Request-ID header, and that value appears in the Recent requests table — quote it if you need help tracing a specific call.
When you create or update a lead or client, only the fields Joby recognises are accepted. Sending anything else — or a protected field such as the record's own ID — is refused with a message listing the fields it rejected. Call /schema to see the exact field list.
Creating a lead with a phone number or email links it to the client Joby already has for that contact (matched by phone first, then email) and only creates a new client when nobody matches. Updating custom_fields changes just the keys you send — send a key as null to clear it. A key can add new custom fields on the fly, up to 150 per record type; past that, create the field in Settings first.
Connect an AI assistant
The same key works as a Model Context Protocol server at https://api.joby.io/v1/mcp, so Claude Code, Claude Desktop and any MCP-capable assistant can search your customers, read a job's timeline and check the schedule — limited to exactly the permissions you ticked. The assistant layer is read-only: it cannot create, change, send or delete anything, even on a key that has Create or Update ticked (those still apply to the API itself). Each tool call shows up in Recent requests like any other request.
claude mcp add --transport http joby https://api.joby.io/v1/mcp \
--header "Authorization: Bearer YOUR_JOBY_API_KEY"A key with Reference data and Activity & timeline ticked, plus Read on the records you care about, gives an assistant everything it needs to answer questions. Company owners and admins on Pro and Enterprise can also connect Claude with no key at all, through "Sign in with Joby": see Connect Claude to Joby CRM.
What the error numbers mean
- 401 — the key is missing, wrong, revoked, or past its expiry date.
- 403 — the key is real but not allowed. The reply says which permission was needed, or that developer access is switched off for the organization, or that the workspace is locked over billing.
- 400 — the request body had unknown or protected fields, an invalid value, or pointed at a record that is not in your organization.
- 404 — no such record, or a record type the API does not support.
- 405 — you tried to create or change something the API only lets you read, such as an estimate or invoice.
- 429 — this key went over its per-minute cap. The reply repeats the cap so your code can wait and try again.
- 500 — something went wrong on Joby's side. Safe to retry after a short pause.
{ "error": "Missing scope", "required_scope": "leads:create" }
{ "error": "Rate limit exceeded", "limit_per_minute": 60 }Do not retry blindly
Retrying a 400, 401, 403, or 405 will fail every time — those need a change to the request or to the key's permissions. Only 429 and 500 are worth retrying, and then with a growing pause between attempts and a cap of a few tries.
Managing and revoking keys
The Secret keys card lists every key ever created for the organization. Each row shows:
- The Name you gave it, plus an active or revoked label.
- The first few characters of the key, so you can tell two keys apart.
- Small labels for each permission you ticked.
- Rate limit — the per-minute cap for that key.
- Last used — how long ago it made a request, or Never.
- Find the key in the Secret keys list.
- Press Revoke on the right of the row.
- Confirm in the pop-up. It warns that any integration using that key will stop working.
Replacing a key safely
- There is no edit button — a key's name, permissions, cap, and expiry are fixed once created.
- To change any of them, create a second key with the settings you want.
- Paste the new key into the connected tool and confirm it works.
- Only then revoke the old key. Check Last used first to be sure nothing else is still using it.
- Revoke immediately, without waiting, if a key was shared by mistake or a team member with access has left.
Watching what the API is doing
The top of the API Keys tab has three counters and the bottom has a request table. This is where you look first when an integration "stopped working".
Active keys
How many keys are still usable. Revoked keys are not counted.
Stored requests
How many recent requests Joby is holding. Only the latest 50 per key are kept.
Last request
How long ago anything last used the API. A stale value here means nothing is calling in.
Recent requests
Time, what was asked for, the status code, and a request ID for each recent call.
If an integration stops working
- Open Settings›Admin›Developer Reference›API Keys.
- Check the key is still marked active and has not passed its expiry date.
- Look at Last used. If it says Never or a very old time, the outside tool is not reaching Joby at all — check the address and the key stored in that tool.
- Scroll to Recent requests and read the status codes. Red codes tell you which failure it is; match them against the error list.
- If every request is refused with a permission error, create a replacement key with the right boxes ticked.
- If nothing appears at all and billing is behind, clear the billing issue first — a locked workspace blocks the API too.
The history is short on purpose
Joby only keeps the latest 50 requests per key, and only for requests that used a valid key. It is a quick health check, not a permanent log — keep your own records on the receiving side if you need history.
Connect Zapier without writing code
Zapier is the no-code route. Joby creates and stores the key for you, with a sensible set of read permissions plus the ability to file new leads and clients.
- Go to Settings›Integrations.
- Open the Zapier card.
- Press Connect Zapier.
- Copy the connection key shown. Like any key, it is displayed once only.
- Open Zapier, start a Zap, and search for Joby.
- When Zapier asks to connect, paste the key.
- Pick a trigger such as New Lead, then pick an action.
Once connected, the same page shows the first characters of the key and gives you two buttons: Generate new key (the old key stops working straight away, so paste the new one into Zapier) and Disconnect (revokes the key and stops every Zap that used it).
Webhooks inside Automations
Joby's webhooks live in Automations, not on the Developer Reference page. There is one for data coming in and one for data going out.
Letting another system send data into Joby
- Go to Automations and press New Automation.
- For the trigger, choose Webhook Received — described in the palette as "Another system posts data to Joby".
- Save the automation. Until you save, the address is not created yet.
- In the properties panel on the right, find Webhook Configuration and click the Webhook URL box to copy it.
- Paste that address into the outside system — your website form builder, Zapier, or whatever is sending the data.
- Optionally fill in Secret Key. If you set one, the sending system must include the same value in an
x-webhook-secretheader or Joby will ignore the request. - Send one real message from the outside system.
- Press Refresh in the Last Received Webhook box. The message you just sent should appear, with the time it arrived.
- Now add your actions — for example Create Lead — and use the received fields to fill them in.
Let Joby AI do the field matching
Once a sample has arrived, a Create Lead action shows a Joby AI field mapping box with a Fill with AI button. It matches the incoming fields to first name, phone, address, and the rest, and you can correct anything by hand afterwards.
Sending data from Joby to another system
- In the automation builder, add the action Call a Webhook — "Send the data to an external URL".
- Paste the destination address into URL.
- Choose the Method the receiving system expects: GET, POST, or PUT.
- Fill in Body (JSON) with the information to send. Use the variable picker underneath, or type tokens directly, for example
{{Lead.phone}}or{{Estimate.customer_name}}. - Save and turn the automation on, then trigger it once and confirm the data arrived on the other side.
A full list of the tokens you can use — and a copy button for each — is on the Reference tab of Settings›Admin›Developer Reference.
Keeping keys safe
- Store keys in a password manager or your software's own secure settings — never in a spreadsheet, email, or chat message.
- Never paste a key into a public web page; anything a browser can see, a visitor can copy.
- Give each tool its own key so you can revoke one without breaking the others.
- Set an Expires date for anything temporary, such as a one-off migration or a contractor's project.
- Review the Secret keys list every few months and revoke anything whose Last used says Never or a very old date.
- Revoke straight away when a team member with access leaves or a key may have been seen by someone else.
- Keep Requests/min as low as the tool can live with; it limits the damage a runaway or stolen key can do.