Customers API
Use this when your integration knows who your customers are and what they ask for: a CRM that holds your accounts, or a support tool where requests arrive. By the end you’ll know which key to make, how to create and update customers by your own IDs, and how to add a customer’s request to a ticket so it counts on the board.
How customers fit with tickets
Section titled “How customers fit with tickets”A customer is a company your organization works for: its name, the email domains its people write from, and optional details such as revenue, size, tier and status. A customer request says that a customer asked for a ticket. It belongs to one ticket and one customer, and can be marked important and carry a quote of what they said.
A ticket can have requests from several customers, and several requests from the same one. The board counts each customer once per ticket, so people can filter and sort by how many customers asked and how much revenue they bring. What people see in the app is on Customers.
Customers are off until an organization admin turns them on, and the organization’s plan has to include them (see
Customers settings and privacy). While they’re off, every call on this page answers
409 customers_disabled, except reading the statuses and tiers (GET /customer-statuses and GET /customer-tiers),
which still answer. So check that Customers is on with a call such as GET /customers, not with those two.
Make a key
Section titled “Make a key”In the app, an owner or admin makes the key in Settings › Organization › Security and picks its Customers access (see API keys):
| You want to | Customers | Access | Scopes |
|---|---|---|---|
| Read customers and their requests | Read | any, or Customers only | customers:read |
| Create and update customers from your CRM | Read & write | Customers only | customers:read, customers:write |
| Also add a customer’s request to a ticket | Read & write | Board — read only or higher | customers:read, customers:write, tickets:read |
A request is part of a ticket, so changing a ticket’s requests also needs tickets:read on the ticket’s project, and
the project must be one the key can read. A key never sees restricted projects, so it can’t add a request to their
tickets, and the counts it reads leave their tickets out. See Scopes for the
rest of what each scope allows.
Create and update customers by your own IDs
Section titled “Create and update customers by your own IDs”Keep a customer in step with your system by addressing it with your own ID, so you never have to store By Dawn’s.
PUT /customers/external/{namespace}/{externalId} creates
the customer the first time and updates it after that:
PUT /customers/external/hubspot/18842{ "name": "Acme Lending", "domains": ["acme-lending.com"], "revenue": 120000 }The customer comes back with your ID recorded on it:
{ "ok": true, "data": { "id": "customer-3f1c…", "name": "Acme Lending", "domains": ["acme-lending.com"], "externalIds": [{ "source": "api", "tenant": "hubspot", "externalId": "18842" }], "statusId": "customerstatus-6a2d…", "tierId": null, "revenue": 120000, "size": null, "ownerId": null, "logoUrl": null, "openRequests": 0, "shippedRequests": 0, "createdAt": "2026-10-17T09:12:44Z", "updatedAt": "2026-10-17T09:12:44Z" }}- The namespace is your name for the system the ID comes from, such as
hubspot: lower-case letters, digits,.,_and-. IDs in different namespaces never collide, so two integrations can’t overwrite each other’s mapping. - The first call needs a
name, because it creates the customer. Later calls send only the fields that changed. - Two first calls at once can answer
409 conflictto one of them. Retry it, and it updates the customer the other one created.
To create a customer you don’t know by an ID of your own, use
POST /customers. To change one by By Dawn’s ID, use
PATCH /customers/{customerId}. In both, a field you leave out keeps
its value and null clears an optional one, and domains replaces the whole set.
Names and domains
Section titled “Names and domains”A customer’s name is unique in your organization, ignoring case, so a second “acme lending” is
409 customer_name_taken. Look the customer up and update it instead.
By Dawn matches incoming requests to customers by email domain, so a domain belongs to one customer only:
- By Dawn tidies a domain before storing it. It’s lower-cased, and a trailing dot and a leading
www.are removed. - A domain another customer has is
409 customer_domain_taken, and the message names that customer. - A domain that can’t belong to a customer is
422 customer_domain_excluded. That’s a personal mail provider such asgmail.com, a domain your admins excluded, or one of your organization’s own domains.
Status and tier
Section titled “Status and tier”statusId and tierId are IDs from your organization’s own lists, which admins edit in the app. Read them with
GET /customer-statuses and
GET /customer-tiers, and map them by name once when your
integration starts. A new customer without a statusId takes the first active status. A status that isn’t active,
such as Churned, marks a customer you no longer serve. A new organization has no tiers.
Revenue
Section titled “Revenue”revenue is a whole number in the unit your organization chose, such as US dollars per year. An admin can limit
revenue to admins. Then a key never receives revenue: it’s left out of every customer, not null. Sending it, or
sorting the list by it, is 403 forbidden. Check for the field rather than assuming it’s there.
When an organization fills revenue, size or tier from Intercom, the customer lists those fields in syncedFields, and
changing one is 422 validation_error, because the sync would overwrite it.
Add a customer’s request to a ticket
Section titled “Add a customer’s request to a ticket”When a customer asks for something, record it on the ticket with
POST /tickets/{ticketId}/customer-requests:
{ "customerId": "customer-3f1c…", "important": true, "quote": "We need bulk export before our audit in November.", "requesterName": "Dana Okafor", "sourceUrl": "https://app.hubspot.com/contacts/1234/ticket/55120", "sourceKey": "hubspot-ticket-55120"}The request comes back with "source": "api", which the app shows as where it came from.
- Send a
sourceKeyto make the call safe to retry. If the ticket already has a request from this customer with the same key, you get that request back instead of a second one. Use your own ID for the conversation or the support ticket. quoteis plain text, up to 4,000 characters. By Dawn never renders it as HTML.requesterNameandrequesterRefsay who asked: a name, and your system’s reference for them. Keep them to what people need to see, because they’re personal data, and an admin can clear them (see Customers settings and privacy).
Change a request with PATCH /customer-requests/{requestId},
for example to mark it important or move it to another customer. Remove it with
DELETE /customer-requests/{requestId}. The ticket and the
customer stay.
Read a customer’s requests
Section titled “Read a customer’s requests”GET /customer-requests lists one customer’s requests or one
ticket’s. Name exactly one of customerId and ticketId:
?customerId=…lists the customer’s requests newest first, each with itsticket. Addstate=open,shippedorcanceledto see one group. Shipped means the ticket reached a completed column. Canceled means it was archived, or closed as a duplicate or won’t fix, without being completed.?ticketId=…lists the ticket’s requests oldest first, each with itscustomer.
GET /customers lists customers by name. q finds one by the start of
a word in its name or of a domain, and each customer carries openRequests and shippedRequests: its requests on
open tickets, and on tickets completed in the last 90 days.
Merged customers
Section titled “Merged customers”An organization admin can merge two customers in the app. The one merged away keeps its ID, and reading it answers
the customer it was merged into, so the id you get back can differ from the one you asked for. The same goes for your
own IDs: the external ID moves to the customer it was merged into. When the IDs differ, store the new one.
A key can’t merge customers itself. Merging is one of the things that stay with people in the app, and What a key can’t do lists the others.
Do and don’t
Section titled “Do and don’t”- Do upsert by your own ID, so a retried sync never makes a second customer.
- Do send a
sourceKeywith every request you add, for the same reason. - Don’t add a customer for every email domain you see. Add the companies you work for, and let By Dawn match their people’s emails by domain.
- Don’t branch on an error’s message. Branch on its slug (see Responses and errors).
Where to go next
Section titled “Where to go next”- Customers: what people see in the app, and where requests come from.
- Customers settings and privacy: the admin’s settings, and how requester data is cleared.
- The API reference lists every customer route under Customers.