Customers and loyalty
Manage customers, loyalty points and tiers in the app, the API and Glue.
Customers in Smooth POS carry their contact details, tags, marketing preferences, store credit balance and loyalty status. Staff see them at the register, and you can read and change them through the API or a Glue job. This guide covers the customer record, the loyalty program and the calls you'll use most.
Store credit has its own guide: Gift cards and store credit.
In the app
- Customers → Customers lists your customers. Open one to edit it, or add a new one.
- Admin → Loyalty Program holds your loyalty settings and tiers.
The customer record
| Field | What it holds |
|---|---|
email | Required. It has to be unique across your customers. |
first_name, middle_name, last_name, title, sex, birthdate | The customer's details. |
address | The address, including phone. A phone number has to be unique too. |
email_subscriber, sms_subscriber | Marketing preferences. |
tags | Tags, handy for grouping customers and filtering lists. |
metadata | Your own custom fields. |
market_id | The market the customer belongs to, if you use markets. |
credit_balance | Store credit available. Updating a customer doesn't change it; use a store credit adjustment (see Gift cards and store credit). |
loyalty_optin, loyalty_points, loyalty_tier, loyalty_tier_expiration | Loyalty status. Points change through sales and adjustments, not by updating the customer. |
Create and update customers
- Create a customer with
POST /customer.json. You get the saved customer back, with itsid. - Update a customer with
PUT /customer.json, including theid. - Get a customer and List customers read them back.
curl -X POST "https://api.smoothpos.net/customer.json" \
-H "X-Smoothpos-Auth: YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"email": "[email protected]", "first_name": "Jane", "last_name": "Citizen", "tags": ["vip"]}'Creating a customer fails with email address is required when there's no email, email already exists on another customer when the email is taken, and phone number already exists on another customer when the phone number is taken.
Update with the whole recordFetch the customer first, change what you need and send the whole record back. That way you won't blank out a field you didn't mean to touch.
Find customers
List customers returns 50 customers at a time (up to 250 with limit), oldest ID first. Filter with email, first_name, last_name, tagged, q and the loyalty filters, and follow the X-Next-Page header for the next page. See Filtering, sorting and search.
Load customers in bulk
Bulk create customers takes an array and answers with one result per customer, keyed by its position in your array:
{
"0": {"failed": false, "id": 2099268},
"1": {"failed": true, "error": "email already exists"}
}A customer is skipped, not updated, when its email or phone number already belongs to another customer, and when it has no email. Check every result and update the skipped ones with PUT /customer.json if you need to.
Bulk create also takes credit_balance and loyalty_points, so you can bring opening balances across when you move from another system.
Bulk deletes match on any tagBulk delete customers deletes everything that matches your filters, and
tagged=a,bmatches either tag. Run List customers with exactly the same filters first.
Loyalty
Program settings
Get loyalty program settings returns your program: whether it's enabled, whether customers must opt in (optin_required), what a point is worth (point_value), how tiers are worked out (tier_calculation), how long a tier lasts (duration) and the tiers themselves (program_tiers).
Update loyalty program settings saves every setting from the body you send, so start from GET /loyalty.json, change what you need and send the whole object back.
Opt customers in and out
- Opt a customer in:
GET /loyalty/{id}/allow.json - Opt a customer out:
GET /loyalty/{id}/deny.json - Extend a customer's tier:
GET /loyalty/{id}/extend/{months}.json
All three change data even though they're GET requests, so don't call them just to look something up. Each returns the updated customer.
Adjust points
Adjust a customer's loyalty points with POST /loyalty/adjust.json. A positive points adds points and a negative one removes them:
{"customer_id": 2099268, "points": -200, "reason": "Points expired"}The response shows the customer before and after, plus the adjustment that was applied. If you remove more points than the customer has, the balance stops at zero and adjustment.points shows what was actually taken off.
React to customer changes in Glue
These system hooks are the ones you'll use most here:
| Trigger | Runs when |
|---|---|
customer_create | a customer is created |
customer_update | a customer changes, including loyalty opt-ins, tier extensions and point adjustments |
loyalty_adjust | points are adjusted; it sends before, after and adjustment |
loyalty_program_update | the loyalty program settings change |
See React to changes for what each one sends.
Example: Send new customers to your email platform
Trigger: System Hook, customer_create.
-
API Request: Get Private Data for your email platform's key, Response variable
mail_res. -
Script: Read the customer
var customer = JSON.parse($.default); $.customer = customer; $.customer_id = customer.id; $.subscribed = customer.email_subscriber === true; var pd = JSON.parse($.mail_res.body); $.mail_key = pd[Object.keys(pd)[0]].trim(); $.contact_body = JSON.stringify({ email: customer.email, first_name: customer.first_name, last_name: customer.last_name }); -
If Condition: If the customer subscribed, Condition
$.subscribed === true. -
REST Request: Add the contact, nested under THEN, with your platform's URL, a header that uses
{{ mail_key }}, and Body{{ contact_body }}.
Keep secrets like mail_key in private data (see Save a private data value) rather than in the job.
Updated about 22 hours ago
