API reference Integration API
Integration API
Tradesmen Tech exposes a small public API so other services can create clients and jobs in your company. It is what the Tradesmen Tech Zapier integration uses, and any service that can send an HTTP request can call it directly.
Need more than clients and jobs? The full Tradesmen Tech API reference documents every endpoint the app itself uses, authenticated with your regular login.
Base URL
https://api.tradesmentechnologies.com/prod
All requests use HTTPS. Request and response bodies are JSON. Date-times are ISO 8601 strings; UTC (Z) is recommended.
Authentication
The API is authenticated with a webhook code: a 32-character key that identifies your company and travels in the URL path. There are no login tokens, headers, or OAuth flows.
To create one, open the Tradesmen Tech app and go to Menu → Zapier and Webhooks Integration, tap +, give the source a name (for example "Zapier" or "Website form"), and copy the code shown under the new entry. Each code can be deleted at any time, which immediately stops anything using it, and each code can independently allow or block job creation.
Treat a webhook code like a password. Anyone who has it can create clients and jobs in your company.
Using Zapier
The Tradesmen Tech app on Zapier wraps this API so you never write JSON. In Zapier, add an action step, search for Tradesmen Tech, and choose Create Client or Create Job. When Zapier asks you to connect an account, paste a webhook code. Every field in both actions is optional and maps one-to-one onto the fields documented below.
Verify a webhook code
GET /webhooks/incoming/{code}
Confirms a code is valid and returns the settings an integration needs to label a connection. Never returns the code or any secret. Zapier calls this when you connect an account.
Response 200 OK
{
"companyName": "Acme Plumbing",
"source": "Zapier",
"allowJobCreation": true,
"notifyCompanyOnNewCustomer": false
}
403 for an unknown code.
Create a client and, optionally, a job
POST /webhooks/incoming/{code}
Creates a client in your company. Include a job object to also create a job for that client. Every field is optional: an empty body {} creates a blank client, and "job": {} creates a job with default values.
Duplicate prevention
If a client with the same email already exists in your company, that client is reused instead of creating a duplicate. When no email is sent but a phoneNumber is, the same check runs on the normalized phone number. When neither is sent, a new client is always created.
An optional idempotencyKey makes retries safe: when the matched client carries the same key, the request returns the existing client and creates nothing.
Example request
POST /prod/webhooks/incoming/ABCDEFghijklmnopQRSTUVwxyz012345
Content-Type: application/json
{
"firstName": "Jane",
"lastName": "Smith",
"email": "jane@example.com",
"phoneNumber": "5125551234",
"address": {
"streetAddress": "123 Main St",
"city": "Austin",
"state": "TX",
"zipCode": "78701"
},
"source": "Website form",
"idempotencyKey": "form-submission-9f1c",
"job": {
"jobType": "PLUMBING",
"status": "NEW",
"description": "Leaking kitchen faucet",
"startDateTime": "2026-10-01T15:00:00Z",
"endDateTime": "2026-10-01T16:00:00Z",
"address": {
"streetAddress": "123 Main St",
"city": "Austin",
"state": "TX",
"zipCode": "78701"
}
}
}
Responses
201 Created when a new client was created; 200 OK when an existing client was reused. jobId and displayId (the job number shown in the app) are present only when a job object was sent.
{
"message": "Customer created successfully",
"customerId": "6f1c2b1e-3d2a-4c8e-9a7b-0e5d4c3b2a10",
"customerIsNew": true,
"jobId": "0a9b8c7d-6e5f-4a3b-2c1d-0e9f8a7b6c5d",
"displayId": 42
}
An idempotent replay answers 200 OK with "message": "Duplicate request detected" and no jobId.
Field reference
Field names follow the app's own create-client and create-job endpoints. The API uses the word customer in field and response names; the app calls the same record a client.
Client fields (top level, all optional)
| Field | Type | Notes |
|---|---|---|
firstName | string | |
middleName | string | |
lastName | string | |
email | string | Used for duplicate matching. |
phoneNumber | string | A 10-digit US number in any format; stored as E.164 (+1…). Used for duplicate matching when no email is sent. Invalid numbers are rejected with 400. |
address | object | streetAddress, city, state, zipCode — each optional. |
description | string | Free-text notes about the client. |
additionalEmails | string[] | |
additionalPhoneNumbers | string[] | Each a valid 10-digit US number. |
additionalAddresses | object[] | Same shape as address. |
parentCategoryId | string | Id of a client category in your company. |
customFields | object | Maps custom field ids to values. |
smsOptedOut | boolean | false = opted in to text messages. Only stored for a brand-new client. |
source | string | Where the client came from; shown in the app. |
idempotencyKey | string | Any unique id from your side, e.g. a form submission id. |
Job fields (inside job, all optional)
| Field | Type | Notes |
|---|---|---|
jobType | string | Defaults to OTHER. One of: APPLIANCE_REPAIR, AUTO_REPAIR, CARPENTRY, CARPET_CLEANING, CONCRETE, DRYWALL, ELECTRICAL, ESTHETICIAN, FENCING, FLOORING, GARAGE_DOOR, GENERAL_CONTRACTING, GLASS_AND_GLAZING, GUTTERS, HANDYMAN, HVAC, INSULATION, JUNK_REMOVAL, LANDSCAPING, LOCKSMITH, MASONRY, MOVING, PAINTING, PEST_CONTROL, PET_GROOMING, PLASTERING, PLUMBING, POOL_AND_SPA, POWER_WASHING, ROOFING, SEPTIC, SIDING, SOLAR, TREE_SERVICE, WELDING, WINDOW_AND_DOOR, WINDOW_CLEANING, OTHER. |
status | string | Defaults to NEW. One of NEW, ACCEPTED, SCHEDULED, IN_PROGRESS, COMPLETED, PAID, CANCELLED, or a status of the pipeline named by pipelineId. |
description | string | Defaults to the webhook's source name. |
startDateTime | string | ISO 8601. |
endDateTime | string | ISO 8601. |
employeeIds | string[] | Employees to assign. Assigned employees are texted when the company has that notification turned on. |
salesEmployeeId | string | |
pipelineId | string | A custom pipeline in your company; 400 if it does not exist. |
color | string | Calendar color, e.g. #FF0000. |
customFields | object | Maps job custom field ids to values. |
address | object | When present, all four of streetAddress, city, state, zipCode are required. An address of empty strings is treated as absent. |
destinationAddress | object | Same rules as address; for moves and deliveries. |
A job created this way behaves exactly like one created in the app: it receives a sequential job number, syncs to connected Google Calendars, and follows the company's assignment and inventory rules.
Errors and limits
Errors return a JSON body with a human-readable message.
| Status | Meaning |
|---|---|
400 | A field failed validation: invalid phone number, address not an object, unknown jobType/status/pipelineId, incomplete job address, or a body that is not a JSON object. |
403 | Unknown or deleted webhook code, or the code does not allow job creation and a job object was sent. |
429 | Rate limit exceeded. The endpoint allows 10 requests per second with bursts of 20. Retry after a short delay. |
500 | Unexpected server error. Safe to retry with the same idempotencyKey. |
The job is validated before anything is written, so a rejected request never leaves a partially created client behind.
Questions
Email support@tradesmentechnologies.com. We typically respond within one business day.