Create a customer
- Permissions
customers:create,customers:read- Safe retries
Idempotency-Key- Also available as
fieldtask_create_customer
Creates one customer in the organization your credential is connected to.
Only name is required. You can also save an email address, a phone number, a display color and your own system's identifier for the customer.
This endpoint only creates. It never matches, updates or restores an existing customer, even one with the same name. If you send the same body twice without the same Idempotency-Key, you get two customers, or a 422 if the body includes an email address that's now in use. See Idempotency and safe retries.
This page is generated from contract 2026-11-03-review.2, a review export that hasn't been released.
Before you start
You need:
- API access for your organization. An owner or admin requests it in Settings → API connections. Until FieldTask enables it, every request returns
403 api_access_not_enabled. - A REST credential with the permissions below: an API token created in Settings → API connections, or an access token from an OAuth client-credentials connection. Tokens from an MCP sign-in don't work with the REST API.
- A check that the customer doesn't already exist. If you created it earlier with an
external_reference, look it up withGET /public/v1/customers?external_reference=…. Otherwise page throughGET /public/v1/customersand compare names and email addresses.
To add the customer's service address, create a location for it next with POST /public/v1/customers/{customer_id}/locations. A customer can't be given an address in this request.
Permissions
Every request needs all of these permissions:
| Permission | Dependency in the permission map |
|---|---|
customers:create | Depends on customers:read |
customers:read | No dependencies |
No field needs an additional permission.
Adding a permission to a connection doesn't happen automatically. An owner or admin edits it in Settings → API connections. API tokens keep the same token string when their permissions change. OAuth integrations must also request the new scope when they get an access token.
Request
Responses
- 201
- 400
- 401
- 403
- 404
- 405
- 409
- 410
- 413
- 415
- 422
- 429
- 503
Created
Response Headers
Responses must not be cached.
The operation key used for this create, including a server-generated key when omitted.
Server-generated request correlation ID.
Bad Request
Response Headers
Responses must not be cached.
Server-generated request correlation ID.
Unauthorized
Response Headers
Responses must not be cached.
Server-generated request correlation ID.
Forbidden
Response Headers
Responses must not be cached.
Server-generated request correlation ID.
Not Found
Response Headers
Responses must not be cached.
Server-generated request correlation ID.
Method Not Allowed
Response Headers
Responses must not be cached.
Server-generated request correlation ID.
Conflict
Response Headers
Responses must not be cached.
Seconds before retry; present on 429 and an in-progress operation.
Server-generated request correlation ID.
Gone
Response Headers
Responses must not be cached.
Server-generated request correlation ID.
Request Entity Too Large
Response Headers
Responses must not be cached.
Server-generated request correlation ID.
Unsupported Media Type
Response Headers
Responses must not be cached.
Server-generated request correlation ID.
Unprocessable Entity
Response Headers
Responses must not be cached.
Server-generated request correlation ID.
Too Many Requests
Response Headers
Responses must not be cached.
Seconds before retry; present on 429 and an in-progress operation.
Server-generated request correlation ID.
Service Unavailable
Response Headers
Responses must not be cached.
Server-generated request correlation ID.
Field guide
The request body is a single JSON object. Only name is required. Every optional field you leave out is saved as null.
| Field | Required | What to send |
|---|---|---|
name | Yes | The customer's name, at most 256 characters. Spaces at either end are removed; what remains can't be empty. Control characters, including tabs and line breaks, aren't allowed. Names don't have to be unique. |
email | No | A valid email address of at most 256 characters, or null. It must not already belong to another customer in your organization. See Email addresses. Defaults to null. |
phone_number | No | International format: +, the country code and the number, with no spaces or punctuation, such as +15555550100. The first digit after + can't be 0, and there can be 2–15 digits. Defaults to null. |
color | No | A display color as # followed by six hexadecimal digits, such as #336699. Defaults to null. |
external_reference | No | Your system's identifier for this customer. See External references. Omit it rather than sending null. |
Anything else in the body is rejected with 422 validation_failed. That includes fields that appear in the response, such as primary_address and is_archived, and organization_id. The organization always comes from your credential.
A new customer is never archived, and its primary_address is null. The first location you add to the customer can fill in primary_address; see Create a customer location.
Body and header rules
- Send
Content-Type: application/jsonwith an uncompressed body. AContent-Encodingheader is rejected with415. - The body can be at most 256 KiB and nest at most 10 levels deep.
- Duplicate property names,
NaNandInfinityare rejected with400 invalid_json. - The URL must have no query string.
Email addresses
Each customer email address can belong to only one customer in your organization.
- If another customer already has the address, the request is rejected with
422 validation_failed. The response doesn't say which customer has it, or that the email was the problem. - The check includes customers that were deleted in FieldTask. A deleted customer doesn't appear in lists but still holds its email address.
- The address is stored exactly as sent. It isn't trimmed or lowercased, and spaces at either end are rejected. Uniqueness is case-sensitive, so
Facilities@example.comandfacilities@example.comcount as different addresses. Normalize case in your own system if you want to avoid near-duplicates. - Customers without an email address never conflict with each other.
If you get a 422 and the rest of the body is valid, look for the existing customer with GET /public/v1/customers and compare email addresses. If you don't find it, it may have been deleted; create the customer without email, or ask an owner or admin to check in FieldTask.
External references
external_reference stores your own system's identifier for the customer, so you can find it again without keeping FieldTask IDs.
- It's 1–128 characters, can't be only whitespace and can't contain control characters.
- It's stored exactly as sent: case-sensitive and never trimmed.
- It's unique per organization and client application. A second customer with the same reference is rejected with
409 external_reference_conflict; the existing customer isn't changed. - It isn't returned in the customer body. Look a customer up with
GET /public/v1/customers?external_reference=…. That parameter can't be combined with any other.
An external reference is not an idempotency key. Use both: the reference identifies the record in your system, and the key makes one request safe to retry. See External references.
Idempotency and safe retries
Send an Idempotency-Key header with a new value, such as a UUID, for every new customer, and save it with your own record before sending. If you get no response, a timeout or a 5xx, send the same body with the same key again, with backoff.
| Situation | Result |
|---|---|
| New key | The customer is created. Response 201, Idempotency-Replayed: false. |
| Same key, same body, within 7 days | The original response is returned again. No second customer is created and it isn't counted against your daily create allowance. Response 201, Idempotency-Replayed: true. |
| Same key, different body | 409 idempotency_key_reused. Nothing is created. |
| Same key while the first request is still running | 409 operation_in_progress with Retry-After. Retry with the same key and body. |
| Same key more than 7 days later | 409 idempotency_window_expired. A key can never be reused for a different customer. |
| Same key, but the customer was deleted since | 410 resource_gone. Don't create it again automatically. |
A replay returns the response as it was when the customer was created, not the customer's current state. Read the customer with GET /public/v1/customers/{resource_id} for current values.
A retry with the same key never fails because of the customer's own email address: the key is checked first, so you get the original 201 back. If you lost a response and then sent the body again with a new key, a 422 can mean the first attempt succeeded.
Keys are 16–128 printable ASCII characters and are scoped to the organization, the connection and the kind of request. Without a key, the server generates one and returns it in the Idempotency-Key response header, which only helps if you receive the response. For the full rules, see Idempotency and recovery.
What happens after the customer is saved
A 201 response means the customer is saved in FieldTask. Nothing further is needed for it to exist, and later follow-up work never removes it. No external system is contacted during the request.
Any follow-up work is reported on the operation, not on the customer. Read the Operation-Location URL from the 201 response with the same credential (needs customers:read). See Get an operation for the status values.
In the review contract, customers created through the API aren't sent to a connected CRM. If your organization has external customer synchronization turned on, the operation reports a blocked target with configuration_required. Otherwise integration.status is not_applicable. The customer itself is created either way.
Operation results are kept for seven days. After that, GET /public/v1/operations/{id} returns 410 operation_result_expired. That doesn't mean the customer wasn't created.
Recovering from failures
| What happened | What to do |
|---|---|
Timeout, connection error or 5xx | Retry the same body with the same key, with exponential backoff. |
409 operation_in_progress or 429 | Wait for Retry-After seconds and retry with the same key. |
201 received | Store data.id and the Location and Operation-Location headers. Stop retrying. |
422 on a body that was accepted before | The email address may already be in use, possibly by the customer your first attempt created. See Email addresses. |
| Key older than 7 days, or the result expired | Don't create again yet. Look for the customer with GET /public/v1/customers?external_reference=… or your saved customer ID. |
Never switch to a new key just because a response was lost. A new key means a new customer.
Errors
Errors use application/problem+json. The top-level code is the stable machine-readable value; error adds a readable message, a suggested fix and a documentation link. For a missing permission, code is insufficient_scope and error.code is missing_permission. Validation errors don't say which field failed, and error responses never echo submitted values. See Errors.
| Status | code | Meaning | What to do |
|---|---|---|---|
| 400 | invalid_query | The URL has a query string. Create requests accept none. | Send the request to /public/v1/customers with no query parameters. |
| 400 | invalid_json | The body isn't one valid JSON value, repeats a property name, uses NaN/Infinity or nests deeper than 10 levels. | Send a single JSON object encoded as UTF-8. |
| 400 | invalid_operation_key | Idempotency-Key isn't 16–128 printable ASCII characters. | Use a UUID or another 16–128 character key without spaces at either end. |
| 401 | invalid_token | The bearer token is missing, malformed, expired, revoked or issued for a different resource (for example an MCP sign-in). | Send a current REST API token or REST OAuth access token as Authorization: Bearer …. |
| 403 | api_access_not_enabled | FieldTask hasn't enabled API access for this organization, or has disabled it. | An owner or admin requests access in Settings → API connections. |
| 403 | insufficient_scope | The connection lacks customers:create or customers:read. error.code is missing_permission. | Add the permission named in error.message to the connection, then retry with the same key. |
| 403 | operation_forbidden | The connection's access changed while the request was processed, or the result would include data the connection can no longer read. | Check the connection's permissions, then retry. Retry creates with the same key and body. |
| 404 | resource_not_found | The public API isn't available in this environment, or the URL is wrong. | Check the API origin and path. |
| 405 | method_not_allowed | Customer creation isn't enabled in this environment. The Allow header lists the methods that are. | Contact FieldTask if you expected customer creation to be available. |
| 409 | external_reference_conflict | Another customer created through this client application already uses this external_reference. Nothing was updated. | Find the existing customer with GET /public/v1/customers?external_reference=…. Use a new reference only for a genuinely new customer. |
| 409 | idempotency_key_reused | This key was already used with a different body. | Resend the original body with this key, or use a new key for a different customer. |
| 409 | operation_in_progress | A request with the same key is still being processed. | Wait for Retry-After seconds, then retry with the same key and body. |
| 409 | idempotency_window_expired | This key was used more than seven days ago. It can't be replayed or reused. This doesn't mean the original request failed. | Reconcile using your saved customer ID or external_reference before creating anything new. |
| 410 | resource_gone | You replayed a key whose customer has since been deleted in FieldTask. | Don't create the customer again automatically. Check with an owner or admin whether it was removed on purpose. |
| 413 | payload_too_large | The body is larger than 256 KiB. | Send a smaller body. |
| 415 | unsupported_media_type | Content-Type isn't application/json, or the body is compressed. | Send an uncompressed body with Content-Type: application/json. |
| 422 | validation_failed | A field is missing, unknown or invalid, or email already belongs to another customer in the organization, including a deleted one. | Check the request against the field guide. If only the email can be wrong, see Email addresses. The response doesn't name the field. |
| 429 | rate_limit_exceeded | Too many requests in the current minute, or too many concurrent requests, for the organization or connection. | Wait for Retry-After seconds. Retry creates with the same key. |
| 429 | daily_quota_exceeded | The organization or connection has used its daily create allowance. Allowances reset at 00:00 UTC. | Wait for Retry-After seconds, or check remaining allowance in Settings → API connections. |
| 503 | temporarily_unavailable | The service couldn't complete the request. The customer may or may not have been created. | Retry with the same key and body, with exponential backoff. |
Every response, including errors, has an X-Request-ID header. Include it, with the time and the status code, when you contact support. Never send tokens or secrets.
Limits
Customer creates count against the same per-minute, concurrency and daily create limits as other creates. Replaying an already-created customer with its original key doesn't count as another create. See Rate limits.
Response headers
A successful create returns 201 Created with these headers:
| Header | Always present | Value |
|---|---|---|
Cache-Control | Yes | Always no-store |
Idempotency-Key | Yes | string |
Idempotency-Replayed | Yes | true or false |
Location | Yes | uri-reference |
Operation-Location | Yes | uri-reference |
X-Request-ID | Yes | uuid |
Location is the customer's URL, /public/v1/customers/{id}. The server also returns the Idempotency-Key that was used, including one it generated.