Security
Keep guests' accounts and data safe when you build on the unPLUG Loyalty API. This covers your side and what unPLUG does on its side. Read it before you go live, and again when someone new joins the team.
Available at launch
Transport#
- The API answers only over HTTPS with TLS 1.2 or later. Requests over plain HTTP or older TLS versions fail.
- Responses carry an HSTS header, so browsers and clients that honor it never fall back to HTTP.
- Keep certificate checks on in every client, including test scripts. Don't pin our certificate; certificates rotate.
- Webhook endpoints you register must use HTTPS too. See Webhooks.
Credentials#
| Credential | Where it may live | Never |
|---|---|---|
Secret key (uk_live_..., uk_test_...) | Your servers, loaded from a secrets manager or environment variable | In an app, a web page, a public repo, a log line or an email |
Member token (mt_...) | The signed-in guest's app or browser session, in memory or secure storage | Shared between guests, or logged |
Webhook signing secret (whsec_...) | Your servers | In an app or in source code |
- Keep test and live keys in separate configuration. A test key only works on the sandbox host and a live key only on production, but mixing them up still leaks a key to the wrong place.
- Strip the
Authorizationheader from request logs, error trackers and proxies. - Never email a secret key, to us or anyone. unPLUG support never asks for one.
Details on each credential are in Authentication.
Scopes and least privilege#
Each secret key has a set of scopes, and a call outside them fails with 403 missing_scope. Ask support for keys with only what each system needs:
| System | Scopes it needs |
|---|---|
| App backend that signs guests in and posts orders | program:read, members:read, members:write, member_tokens:create, checkout:write |
| Support tool for goodwill points | members:read, points:adjust |
| Webhook administration | webhooks:manage |
| Reporting job Coming soon | reports:read |
A full-access key has every scope. Use one only where a single service does everything, and never on a laptop.
Member tokens#
A member token lasts 15 minutes and can only act for one member. It can read that member's balance, wallet and activity, preview a checkout, create, read and cancel that member's redemptions, and register their devices. It can't create orders, adjust points, change the member's phone or read other members.
There is no refresh token. When a token expires (401 token_expired), the app asks your server for a new one, and your server checks your own session first. That keeps your login the only source of truth: if you sign a guest out or lock their account, they lose loyalty access within 15 minutes without any call to unPLUG. To cut access right away, for example after a reported account takeover, call POST /v1/members/{id}/revoke_tokens (scope members:write).
IP allowlists#
You can limit each secret key to a list of IP addresses or ranges. Requests from anywhere else are rejected, even with the right key. Email support with the key's prefix (the first characters, never the whole key) and the addresses. Use it for production keys used from fixed egress IPs.
Rotating keys#
Two keys can be active at once, so rotation needs no downtime:
- Ask support for a new key with the same scopes.
- Deploy it everywhere the old key is used.
- Check the old key is idle. Confirm your deploys and jobs all use the new one.
- Ask support to revoke the old key.
Rotate when someone with access leaves, after any suspected exposure, and on a schedule you set. Rotate webhook signing secrets yourself with POST /v1/webhook_endpoints/{id}/rotate_secret. Creating, rolling and revoking keys yourself in the developer dashboard is Coming soon.
If a key leaks#
- Email support right away. Send to support@unplugdining.com with a subject starting "Security:". Include the key's prefix, where it was exposed and since when. We revoke it within one hour on business days.
- Get and deploy a replacement as in the rotation steps above. Expect failures from anything still using the old key once it's revoked.
- Remove it from where it leaked. Deleting a commit doesn't remove it from history or forks, so treat it as public either way.
- Check what it did. Ask support for the request history of the key. Look in members' activity for
adjustentries you didn't make: every points adjustment records the key that made it.
Automatic revocation of unPLUG keys found in public GitHub repositories, through GitHub secret scanning, is Coming soon.
Warning A leaked secret key can enroll members, move points and post orders for your brand. Don't wait for the next business day to tell us.
Webhook verification#
Verify every webhook before acting on it: check the signature on the raw body, reject timestamps more than 5 minutes off, compare in constant time and dedupe on webhook-id. The steps and code are in Verify the signature.
Personal data#
unPLUG stores what the program needs: a member's name, email, phone, birthday, your external_id, marketing preferences, the metadata you send, devices and push tokens, and their orders and points history. It doesn't store payment card data; your payment processor handles cards.
Send only what you need:
- Member metadata is for ids and preferences, such as a favorite store. Don't put addresses, card details, government ids, health information or passwords in it.
- App event properties must not contain personal data. Send ids and product names, not emails, phone numbers or free text a guest typed.
- Order lines carry item names and ids. Don't put the guest's name or notes in an item name.
Account deletion#
Give guests a "Delete account" option in your app. Call DELETE /v1/members/me from the app, or DELETE /v1/members/{id} from your server. That meets the Apple App Store and Google Play rules for in-app account deletion.
Deletion finishes within 30 days, usually within minutes. Personal data is erased, points and rewards are forfeited, the member is left out of future data exports, and a member.deleted webhook fires. Delete your own copies of the guest's data when it arrives. If the same person signs up later, they start as a new member with a zero balance.
Data location#
unPLUG stores and processes program data in the United States. A Snowflake share (Coming soon) is created in the cloud region you choose; see Data sharing.
What unPLUG does on its side#
- Encryption. Data is encrypted in transit with TLS and encrypted at rest.
- Push credentials. Your Firebase service account and APNs key go into a secrets vault when you upload them. Nobody at unPLUG can read them back; they can only be replaced or deleted.
- Secret keys. Scopes and IP allowlists are checked on every call.
- Points audit. Every points adjustment records who made it: the API key, or the person in the unPLUG dashboard.
- Sandbox isolation. Sandbox data is separate from production and never reaches real guests.
If your security review has a questionnaire, email support and we'll answer it.
Report a vulnerability#
Email support@unplugdining.com with a subject starting "Security:". Include what you found, how to reproduce it, and the Request-Id of any requests involved. Test only against your own sandbox brand, and don't access data that isn't yours. We'll confirm we received it and keep you updated until it's fixed.