Data sharing
Get your loyalty data out of unPLUG and into your own reporting, warehouse or CRM. Pick the option that matches how fresh the data needs to be and where you want it.
Coming soon
Coming soon Everything on this page is designed and planned but not released yet. The shapes here are what we plan to ship. The changelog will say when each option goes live.
Three ways to get the data#
| Option | What you get | Freshness | Good for |
|---|---|---|---|
| Reports API | Daily totals as JSON | On request | A dashboard tile, a weekly email to store managers |
| Daily file exports | Row-level CSV files | Once a day, by 06:00 your time | Loading into any warehouse or BI tool |
| Snowflake Secure Data Share | The same tables, live in your Snowflake account | Refreshed hourly | Teams already on Snowflake |
For changes as they happen (a single points change, a new member), use webhooks, which are available at launch. Bulk data stays in files and shares.
Reports API#
Two read-only endpoints in the Management API return totals by local day. You need a secret key with the reports:read scope.
GET /v1/reports/program_summary: members (total, new, active), points (issued, redeemed, adjusted, outstanding), rewards (issued, redeemed, discount), and orders and sales from members compared with non-members. Filter by location.GET /v1/reports/rewards: issued, redeemed and discount for each reward.
Dates are local dates in the location's time zone, or the brand's default time zone when you don't filter by location. Full fields and examples are on Reports.
Daily file exports#
Every day unPLUG writes a set of gzipped CSV files with the previous day's data. You choose where they go:
- SFTP hosted by unPLUG. You connect and download. Sign-in is by SSH key only; passwords aren't accepted. IP allowlisting is available.
- Your own Amazon S3 bucket. You give unPLUG permission to write to one bucket prefix.
- Your own Google Cloud Storage bucket. Same, with a GCS bucket.
Files#
Each day's export is a folder named for the local date it covers, for example 2026-11-03/. members is a full snapshot every day. The other tables hold the rows created or changed that day (deltas), except tiers, which is small enough to send whole.
| File | Kind | One row per | Key columns |
|---|---|---|---|
members.csv.gz | Snapshot | Member | member_id, external_id, status, email, phone, points_balance, lifetime_points, tier_id, enrolled_at, updated_at |
points_activity.csv.gz | Delta | Activity entry | activity_id, member_id, type, points, balance_after, order_id, reward_id, adjustment_reason, created_at |
wallet_items.csv.gz | Delta | Wallet item | wallet_item_id, member_id, reward_id, source, offer_id, status, issued_at, expires_at, used_at, order_id |
redemptions.csv.gz | Delta | Redemption | redemption_id, member_id, order_id, reward_id, wallet_item_id, code, status, discount_cents, points_cost, created_at |
orders.csv.gz | Delta | Order | order_id, external_order_id, member_id, location_id, channel, status, placed_at, subtotal_cents, discount_cents, total_cents, currency, points_earned |
tiers.csv.gz | Snapshot | Tier | tier_id, name, min_lifetime_points, upgrade_bonus_points |
communication_preferences.csv.gz | Delta | Member whose preferences changed | member_id, email_marketing, sms_marketing, push_marketing, source, updated_at |
challenge_progress.csv.gz Coming soon | Delta | Member and challenge | member_id, challenge_id, status, current, target, completed_at. Added when challenges ship. |
manifest.json | Written last | One per day | Row count and SHA-256 checksum for every file |
Column values follow the API: ids are UUIDs, times are UTC in RFC 3339, money is integer cents. A delta row is the full current row, so load deltas with an upsert on the id column.
The manifest#
manifest.json is written after every other file in the folder. Don't start loading until it exists, then check each file's row count and checksum against it.
{
"brand_id": "e5a1c7d9-2f4b-4c8e-a3d6-8b0f1e9c2a57",
"export_date": "2026-11-03",
"time_zone": "America/Chicago",
"generated_at": "2026-11-04T10:41:17Z",
"files": [
{ "name": "members.csv.gz", "kind": "snapshot", "rows": 18342, "sha256": "9f2c4e7a1b3d5f8e0a2c4b6d8f1e3a5c7b9d0f2e4a6c8b1d3f5e7a9c0b2d4f6e" },
{ "name": "points_activity.csv.gz", "kind": "delta", "rows": 2207, "sha256": "4b8e1d3f6a9c2e5b7d0f3a6c8e1b4d7f9a2c5e8b0d3f6a9c1e4b7d0a3c6f9e2b" },
{ "name": "wallet_items.csv.gz", "kind": "delta", "rows": 391, "sha256": "e1a4c7f0b3d6e9a2c5f8b1d4e7a0c3f6b9d2e5a8c1f4b7d0e3a6c9f2b5d8e1a4" },
{ "name": "redemptions.csv.gz", "kind": "delta", "rows": 268, "sha256": "7c0f3b6e9a2d5c8f1b4e7a0d3c6f9b2e5a8d1c4f7b0e3a6d9c2f5b8e1a4d7c0f" },
{ "name": "orders.csv.gz", "kind": "delta", "rows": 1934, "sha256": "2d5a8c1f4b7e0a3d6c9f2b5e8a1d4c7f0b3e6a9d2c5f8b1e4a7d0c3f6b9e2a5d" },
{ "name": "tiers.csv.gz", "kind": "snapshot", "rows": 2, "sha256": "b6e9c2f5a8d1b4e7c0f3a6d9b2e5c8f1a4d7b0e3c6f9a2d5b8e1c4f7a0d3b6e9" },
{ "name": "communication_preferences.csv.gz", "kind": "delta", "rows": 57, "sha256": "5f8b1e4a7d0c3f6b9e2a5d8c1f4b7e0a3d6c9f2b5e8a1d4c7f0b3e6a9d2c5f8b" }
]
}Timing#
Each day's files are ready by 06:00 in your brand's default time zone. A day runs midnight to midnight in that time zone. If a day's export is late, the folder won't have a manifest yet; check again later rather than loading partial files.
Schema rules#
- New columns are only ever appended at the end.
- Columns are never removed or retyped. A retired column stays, blank.
- Parse by header name.
- Changes are announced in the changelog 30 days ahead.
Read the header row, map columns by name, and ignore columns you don't know, so a new column never breaks your load.
Snowflake Secure Data Share#
A Secure Data Share puts the same tables as the file export in your Snowflake account as a read-only database. Nothing is copied into your storage, and queries run on your own warehouse.
- Region. You choose the AWS or Azure region the share lives in, so it can sit next to your Snowflake account.
- Refresh. Tables are refreshed hourly.
- Tables. The same tables and columns as the file export, under the same schema rules. Every table is a full table, not daily deltas.
To accept the share:
- Send support your account details. Your Snowflake account identifier (organization and account name) and its cloud and region.
- unPLUG shares the data with your account. Support tells you the name it appears under.
- Create a database from it. A user with the
ACCOUNTADMINrole, or a role with theIMPORT SHAREprivilege, accepts the share in Snowsight or with SQL, then grants access to the roles that need it.
-- Use the share name support sends you.
CREATE DATABASE unplug_loyalty FROM SHARE UNPLUG.YOUR_BRAND_LOYALTY;
GRANT IMPORTED PRIVILEGES ON DATABASE unplug_loyalty TO ROLE analyst;
SELECT tier_id, COUNT(*) AS members
FROM unplug_loyalty.loyalty.members
WHERE status = 'active'
GROUP BY tier_id;BigQuery Analytics Hub may come later. Ask support if you need it.
Request data sharing#
All three options are set up by support. Email support@unplugdining.com with:
- Your brand name and which option you want.
- For the Reports API: whether you need a new key with
reports:reador want the scope added to an existing key. - For SFTP: your SSH public key (never the private key) and, if you want an allowlist, the IP addresses or ranges you'll connect from.
- For S3 or GCS: the bucket name, prefix and region. Support replies with the identity to grant write access to.
- For Snowflake: your account identifier, cloud and region.
- A technical contact who gets an email if an export fails.
Data handling#
Exports and shares contain personal data: names, email addresses, phone numbers and birthdays in members. Treat them like your own customer records.
- Access. Give access to the people and systems that need it. Store files encrypted and don't email them.
- Deleted members. When a member is deleted, they're removed from the next
memberssnapshot, and from the Snowflake tables within a refresh. Rows you already loaded stay in your copy until you remove them. Listen formember.deletedand delete that member's rows from your systems. - Marketing consent. Use
communication_preferencesbefore you send marketing. An unsubscribe can come from an email link, the app or the unPLUG dashboard. - Retention. Keep exported data only as long as you need it. Support confirms how long files stay on the unPLUG SFTP server when it sets up your export; download each day's files promptly.
See Security for how unPLUG handles personal data on its side.