Customers
Siren's customer records in the REST API: the customer object and the routes to list, merge, and split customers and to link them to collaborators for lifetime commissions.
WordPress plugin and Siren Cloud
Last updated: October 26, 2026
Siren keeps one record for each shopper who buys, signs in or registers after a referral, or is linked to a collaborator. Each way a store knows the shopper is an identity, such as a store account or a guest checkout, and a merged customer holds the identities of every customer merged into it. Customers explains the screen these routes serve, and Lifetime Commissions explains links.
Paths are relative to the REST base, /wp-json/siren/v1 on WordPress, and Authentication explains how to sign requests. The routes need staff access, an administrator or Platform Manager. Linking and unlinking need Siren Plus or Pro. On WordPress, other plans answer 403 with the code rest_forbidden and “Your plan does not include this feature.” in WordPress’s error shape. On Siren Cloud, the refusal answers 403 with error.code plan_required.
403 when a merge or split touches a store they can’t reach. Customers at different Properties can’t be merged, and the merge answers 400, until an Admin confirms the stores are one business with PUT /customers/matching/cross-store and {"confirmed": true}, which also lets Siren suggest matches across them. GET /customers/matching/cross-store answers { "confirmed" }.
The customer object
| Field | Type | Description |
|---|---|---|
id | integer | The customer |
label | string | ”Customer #” and the ID |
name | string or null | The newest name a store reported |
mergedIntoId | integer or null | The customer this one was merged into |
lastSeenAt | datetime or null | When Siren last saw the customer |
identities | array | Each way a store knows them: id, propertyId, integration (such as wordpress, wc, or edd), platformId (the store’s ID, null for a guest), name, hasEmail, guest, deleted, and lastSeenAt |
collaboratorIds | array | The collaborators linked to the customer for lifetime commissions |
opportunityCount | integer | How many visits belong to the customer |
openSuggestions | integer | How many merge suggestions wait for this customer |
Siren never returns an email address. It keeps only a keyed hash, and hasEmail says whether an identity has one.
List customers
GET /customers
| Parameter | Description |
|---|---|
search | A customer ID with or without #, a store’s ID for the customer, or an exact email |
integration | One integration, such as wc |
propertyId | One store. Leave it out for every store |
linked | 1 for linked customers, 0 for customers no one is linked to |
collaboratorId | Customers linked to one collaborator |
matches | 1 for customers with an open merge suggestion |
page, perPage | Paging. perPage is 1 to 100, default 25 |
Answers { "customers": [...], "total" }, most recently seen first. Merged customers are left out.
Get a customer
GET /customers/:id
Answers { "customer": {...}, "suggestions": [...], "sales": [...], "crossStoreConfirmed" }. sales lists up to 50 transactions credited from the customer’s visits, each with id, date, and status. A merged customer answers with its own record, and its mergedIntoId names the customer to read instead. An unknown ID answers 404. Each suggestion has id, signal, strength, and the other customer. crossStoreConfirmed says whether customers can be matched and merged across stores, and it’s false on WordPress, where every customer is at one store.
Merge suggestions
GET /customers/suggestions lists open suggestions, optionally for one customerId, as { "data": [...] }, strongest first, at most 100. Each has id, signal, strength, and the two customers. signal is same_email_same_store for the same email at one store, or same_email for the same email at two stores once cross-store matching is confirmed.
POST /customers/suggestions/:id/dismiss dismisses that suggestion for good, or answers 404 for an unknown one, and answers id and state.
Merge customers
POST /customers/merge
Send survivorId, the customer to keep, and customerIds, the customers to merge into it. A merge covers at most 20 customers, the survivor included. Identities, visits, and sales move to the survivor. Answers 200 with customer and mergedIds. Send "preview": true to get only the questions the merge would ask, as conflicts.
When the customers are linked to more than one collaborator, the merge asks which stay linked. Without an answer it answers 409 with conflicts, and the error’s code is merge_conflict. Each conflict has key, options, and multiple. Answer it with collaboratorIds, a list of at least one of the offered collaborators. An answer that names a collaborator not offered repeats the 409. A missing survivorId or customerIds, an empty collaboratorIds, or a merge Siren refuses, such as one with a customer already merged, answers 400. An unknown customer answers 404.
Split an identity off
POST /customers/:id/identities/:identityId/split
Makes that identity a customer of its own, with the visits and sales that came through it and no collaborator linked. Answers 200 with customer, the original, and split, the new one. Splitting a customer’s only identity answers 400, and an identity that isn’t part of the customer answers 404.
Link a customer to a collaborator
POST /customers/:id/collaborators with {"collaboratorId": 12} links the customer, so the collaborator earns from their later purchases in programs that track Opportunity Bound To Collaborator. Answers 200 with customer and changed, which is false when the link already existed. A missing collaboratorId or an unknown collaborator answers 400, and so does a customer that was merged, naming the customer to link instead.
DELETE /customers/:id/collaborators/:collaboratorId unlinks them. Rewards already earned stay. It answers 200 with customer and changed, which is false when there was no link, and an unknown customer answers 404.
Linked customers on other records
- A collaborator’s
linkedCustomerCountfield, requested with?fields=linkedCustomerCount, counts the customers linked to them. GET /opportunities?collaboratorId=lists the visits linked to a collaborator.PUT /opportunities/:idtakescustomerCollaborators, a list of collaborator IDs that replaces the links on that visit’s customer, andcascadeRejectOnUnbind, a list of collaborator IDs. It works only withcustomerCollaboratorsin the same request. When that list drops a collaborator named incascadeRejectOnUnbind, Siren also rejects that collaborator’s unpaid rewards (draftandapproved) from that visit. SendingcustomerCollaboratorsneeds Plus or Pro.
Data requests
WordPress’s Export Personal Data and Erase Personal Data tools cover Siren’s records, as Answer a Customer’s Data Request describes. On Siren Cloud, POST /customer-data/export and POST /customer-data/erase answer a shopper’s data request, as Answer a Customer’s Data Request describes. Send email (up to 254 characters), references (a list of {type, id}, such as stripe_customer@property:5), or opportunityIds, at most 50 identifiers in all. Export answers { "items": [...] }, each with groupId, groupLabel, itemId, and fields. Erase answers found, removed, retained, messages, unlinkedCollaborators (a count), and complete. A bad body answers 400, and a request that can’t run answers 503. Admins can call them, and so can a connected WordPress site for its own WordPress users. An Admin’s call with no active plan answers 403 with plan_required.