Skip to content

Create and sync customers

Open .md

Read first: Customers, for what a customer holds and the defaults it gives an order.

A customer is a company or person you sell to. Each customer has contacts (the people you email and call) and addresses (billing and shipping). Orders and quotes belong to a customer.

Syncing buyers from a store or a CRM? This is the safe order, with no duplicates:

  1. 1. Upsert by emailperform_upsert: true, the customer’s name, and a contact with the buyer’s email. See Sync without duplicates
  2. 2. Keep the idStore the answer’s data.id with the buyer in your system
  3. 3. Add the addressA shipping address on the customer, unless it already has it. See Manage addresses
The upsert matches on the contact's email or phone, so a retry finds the same customer instead of making a second one.

Send the name in the upsert: without it, a new customer has no name. Every other customer field is optional.

List customers a page at a time:

GET List customers /v1/api/store/{team_slug}/customer

Or filter them, for example the customers assigned to you, newest first:

POST Search customers with filters /v1/api/store/{team_slug}/customer/filter
{
"filters": [{ "key": "assigned_to_me", "operator": "eq", "value": true }],
"sort": [{ "key": "created_at", "direction": "desc" }]
}

See Filtering and sorting for the operators.

To open one customer, with its contacts, addresses, tags and assigned users:

GET Get a customer /v1/api/store/{team_slug}/customer/{hash_id}

The public API has no direct lookup by email or phone. Customer lists and filters don’t include contacts, and no filter matches an email. Choose one of these:

  1. Keep YoPrint’s id. When you create or upsert a customer, store the answer’s data.id next to the record in your own system. Later, read the customer by that id. This is the fastest and safest way.
  2. Upsert with only the contact. Send perform_upsert: true and a contact with the email, and no other customer fields. When a customer matches, YoPrint changes none of its fields and returns it with its contacts (it still sends customer.updated). When nothing matches, YoPrint creates a customer, without a name. Use this only when creating is what you want.
  3. Read customers one by one. List customers, then read each one to see its contacts. This works on any team, but it takes one request per customer.
  4. Export customers to CSV with the columns id and contact_email, then look the email up in the file. A customer with several contacts takes several rows. Deleted contacts are left out. See Export and import data.
{
"perform_upsert": true,
"contact": {
"first_name": "Alex",
"email": "alex@example.com",
"send_invoice": true,
"is_primary": true
}
}

An upsert never changes the matched contact itself. When an upsert creates a customer, is_primary is ignored and the new contact is not made primary. To make it primary, call Set the primary contact after creation. An upsert checks no customer permission, so any member’s key can update a matched customer.

POST Create a customer /v1/api/store/{team_slug}/customer
{
"customer": {
"name": "Northwind Apparel",
"tax_exempt": false,
"website": "https://example.com"
},
"contact": [
{
"first_name": "Alex",
"last_name": "Rivera",
"email": "alex@example.com",
"phone": "+1 201 555 0123",
"phone_country": "US",
"send_invoice": true,
"is_primary": true
}
],
"billing": [
{
"label": "Head office",
"address1": "100 Example Street",
"city": "Springfield",
"country_code": "US",
"postcode": "10001",
"is_primary": true
}
]
}
  • customer.name and customer.tax_exempt are required.
  • Each contact needs first_name, send_invoice (whether invoices go to them) and is_primary. A phone needs phone_country, and must be a valid number for that country: YoPrint checks it, so a made-up number such as +1 555 0100 is refused.
  • billing and shipping are lists of addresses. Each needs label, address1, country_code and is_primary.

The new customer is assigned to you, and customer.created fires.

If your system may already have sent a customer, upsert it instead. With "perform_upsert": true, YoPrint updates the customer whose contact has the same email or phone, or creates it:

POST Create or update a customer by contact /v1/api/store/{team_slug}/customer/upsert
{
"perform_upsert": true,
"name": "Northwind Apparel",
"tax_exempt": false,
"contact": {
"first_name": "Alex",
"email": "alex@example.com",
"send_invoice": true,
"is_primary": true
}
}

The upsert body is flat (name at the top, one contact object), unlike create. If no customer matches and a new one is created, contact.is_primary is ignored. Use Set the primary contact to make it primary. Read Retries and duplicates for what upsert matches before you rely on it.

PUT Update a customer /v1/api/store/{team_slug}/customer/{hash_id}

Send the fields to change at the top level, such as { "name": "Northwind Apparel Ltd" }. Contacts and addresses have their own operations.

GET List a customer's contacts /v1/api/store/{team_slug}/customer/{hash_id}/contact POST Add a contact to a customer /v1/api/store/{team_slug}/customer/{hash_id}/contact PUT Update a customer contact /v1/api/store/{team_slug}/customer/{hash_id}/contact/{id}

To make a contact the customer’s main one:

PATCH Set the primary contact /v1/api/store/{team_slug}/customer/{hash_id}/contact/{id}/primary

To add or update a contact by its email or phone, within one customer:

POST Create or update a customer contact by email or phone /v1/api/store/{team_slug}/customer/{hash_id}/contact/upsert

When you only have a contact’s id, and not its customer’s, read it directly:

GET Get a contact by id /v1/api/store/{team_slug}/contact/{id}

Two live contacts of one customer can’t share an email: YoPrint saves emails trimmed and in lower case, and refuses a second contact with the same email with 409 (customer_portal_duplicate_contact_email). Other customers may use the same email.

A contact can also give someone access to the Customer Portal. Changing that contact’s email moves their portal access, so the update may ask you to choose with portal_email_scope or to confirm with portal_reconnect_confirmed (a 409 tells you which). Deleting the contact removes their access to this customer. The update operation above explains both fields.

An address has a role, billing or shipping:

POST Add an address to a customer /v1/api/store/{team_slug}/customer/{hash_id}/address
{
"role": "shipping",
"label": "Warehouse",
"address1": "100 Example Street",
"city": "Springfield",
"country_code": "US",
"postcode": "10001",
"is_primary": true
}
PATCH Set the primary address /v1/api/store/{team_slug}/customer/{hash_id}/address/{id}/primary

Deleting moves a customer to the trash. A customer with an open quote or sales order can’t be deleted.

DELETE Delete a customer /v1/api/store/{team_slug}/customer/{hash_id} PATCH Restore a deleted customer /v1/api/store/{team_slug}/customer/{hash_id}/restore
  • Create nests, upsert doesn’t. Create takes customer plus lists of contact, billing and shipping. Upsert takes the customer’s fields at the top and one contact.
  • is_primary is ignored when upsert creates a customer. Call Set the primary contact afterwards to make it primary.
  • Upsert matches on email or phone. It can match, and overwrite, a different customer than you expect. Always send an email.
  • Upsert overwrites what you send. Every top-level field you send replaces the matched customer’s value. Send only the fields your system owns.
  • Made-up phone numbers are refused. Use a real-format number, such as +1 201 555 0123 with phone_country US.
  • Phones need a country. Send phone_country with every phone.
  • Customers synced from Shopify are read-only here. Change them in Shopify.
  • Send only the fields the reference lists. Don’t copy fields you read back, such as is_external, external_type, is_system or is_editable, into a create or an update. Creating, updating or upserting a customer or a contact ignores is_external and external_type.
  • customer_portal_link is always null. YoPrint no longer returns a portal sign-in link for a customer. To turn the portal off for one customer, update it with "customer_portal_enabled": false.
  • A narrower role sees fewer customers. Some roles see only customers assigned to them, and reading any other customer answers 403. See Roles and permissions.