Create a custom field
const url = 'https://api.usesonora.com/v1/customer-fields';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"label":"example","type":"string","format":"currency","options":["example"],"multiple":true}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://api.usesonora.com/v1/customer-fields \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "label": "example", "type": "string", "format": "currency", "options": [ "example" ], "multiple": true }'Add a custom field to every customer, as Add column on the customers page does. Its key is made from the label — Renewal risk becomes renewal_risk, or renewal_risk_2 if an earlier field still owns that key — and the answer says which. Every customer starts without a value. A label another field already shows is 409 customer_field_exists. Send an Idempotency-Key to make a retry safe.
Requires the custom-fields:manage scope. API keys only.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Header Parameters
Section titled “Header Parameters”1–255 printable characters. A retry with the same key and request answers with the first call’s result instead of acting twice.
Request Bodyrequired
Section titled “Request Bodyrequired”A custom field to add to customers. Its key is made from the label.
object
How Sonora shows the field. No other field may show the same label, ignoring case; runs of spaces are kept as one.
date holds YYYY-MM-DD; select one of options; user people in your workspace.
user only: true lets the field hold several people. Left out, it holds one.
Responses
Section titled “Responses”The field, created.
A custom field on customers.
object
The key in a customer’s customFields.
date is YYYY-MM-DD; datetime an ISO 8601 instant; select one of options (or several, with multiple); user a list of people.
How the value is meant: currency, percentage, email, url, phone, … Null when it’s plain.
Whether the value is a list: a multi-select, or a user field holding several people.
Example
{ "type": "string"}Headers
Section titled “Headers”true when this answers a retry with an earlier call’s Idempotency-Key: the first call’s body, replayed.
invalid_json: The request body is not valid JSON.
invalid_request: A parameter or body field is missing, malformed or unknown; details.issues names each.
The one error shape every endpoint answers with.
object
object
Stable snake_case code to branch on; see the error table.
For humans; may change.
object
Quote it when asking for help.
Examplegenerated
{ "error": { "code": "example", "message": "example", "details": { "additionalProperty": "example" }, "requestId": "example" }}unauthorized: The Authorization header is missing, or the key is invalid, revoked or expired.
The one error shape every endpoint answers with.
object
object
Stable snake_case code to branch on; see the error table.
For humans; may change.
object
Quote it when asking for help.
Examplegenerated
{ "error": { "code": "example", "message": "example", "details": { "additionalProperty": "example" }, "requestId": "example" }}insufficient_scope: The key or token lacks the scope this endpoint needs, and details.required names it; or an OAuth access token called an endpoint only an API key can.
The one error shape every endpoint answers with.
object
object
Stable snake_case code to branch on; see the error table.
For humans; may change.
object
Quote it when asking for help.
Examplegenerated
{ "error": { "code": "example", "message": "example", "details": { "additionalProperty": "example" }, "requestId": "example" }}customer_field_exists: A custom field already has that label; details.key names it when it’s one the API shows.
idempotency_key_in_use: A request with this Idempotency-Key is still being processed. Retry once it has finished.
The one error shape every endpoint answers with.
object
object
Stable snake_case code to branch on; see the error table.
For humans; may change.
object
Quote it when asking for help.
Examplegenerated
{ "error": { "code": "example", "message": "example", "details": { "additionalProperty": "example" }, "requestId": "example" }}payload_too_large: The request body is too large; details.maxBytes gives the limit.
The one error shape every endpoint answers with.
object
object
Stable snake_case code to branch on; see the error table.
For humans; may change.
object
Quote it when asking for help.
Examplegenerated
{ "error": { "code": "example", "message": "example", "details": { "additionalProperty": "example" }, "requestId": "example" }}idempotency_key_mismatch: The Idempotency-Key was used before with a different request.
invalid_fields: A field’s value can’t be saved, so nothing was; details.issues names each field and why.
The one error shape every endpoint answers with.
object
object
Stable snake_case code to branch on; see the error table.
For humans; may change.
object
Quote it when asking for help.
Examplegenerated
{ "error": { "code": "example", "message": "example", "details": { "additionalProperty": "example" }, "requestId": "example" }}rate_limited: Too many requests for this key; retry after Retry-After seconds.
The one error shape every endpoint answers with.
object
object
Stable snake_case code to branch on; see the error table.
For humans; may change.
object
Quote it when asking for help.
Examplegenerated
{ "error": { "code": "example", "message": "example", "details": { "additionalProperty": "example" }, "requestId": "example" }}internal_error: Something went wrong on Sonora’s side. Retry, and quote requestId if it persists.
The one error shape every endpoint answers with.
object
object
Stable snake_case code to branch on; see the error table.
For humans; may change.
object
Quote it when asking for help.
Examplegenerated
{ "error": { "code": "example", "message": "example", "details": { "additionalProperty": "example" }, "requestId": "example" }}Try it
Try it runs the reference's read endpoints, and this one changes data, so it needs an API key with the custom-fields:manage scope. Create a key in Sonora under Settings → API and call it from your own code.