unPLUGDevelopers

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#

OptionWhat you getFreshnessGood for
Reports APIDaily totals as JSONOn requestA dashboard tile, a weekly email to store managers
Daily file exportsRow-level CSV filesOnce a day, by 06:00 your timeLoading into any warehouse or BI tool
Snowflake Secure Data ShareThe same tables, live in your Snowflake accountRefreshed hourlyTeams 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.

FileKindOne row perKey columns
members.csv.gzSnapshotMembermember_id, external_id, status, email, phone, points_balance, lifetime_points, tier_id, enrolled_at, updated_at
points_activity.csv.gzDeltaActivity entryactivity_id, member_id, type, points, balance_after, order_id, reward_id, adjustment_reason, created_at
wallet_items.csv.gzDeltaWallet itemwallet_item_id, member_id, reward_id, source, offer_id, status, issued_at, expires_at, used_at, order_id
redemptions.csv.gzDeltaRedemptionredemption_id, member_id, order_id, reward_id, wallet_item_id, code, status, discount_cents, points_cost, created_at
orders.csv.gzDeltaOrderorder_id, external_order_id, member_id, location_id, channel, status, placed_at, subtotal_cents, discount_cents, total_cents, currency, points_earned
tiers.csv.gzSnapshotTiertier_id, name, min_lifetime_points, upgrade_bonus_points
communication_preferences.csv.gzDeltaMember whose preferences changedmember_id, email_marketing, sms_marketing, push_marketing, source, updated_at
challenge_progress.csv.gz Coming soonDeltaMember and challengemember_id, challenge_id, status, current, target, completed_at. Added when challenges ship.
manifest.jsonWritten lastOne per dayRow 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.

2026-11-03/manifest.json
{
  "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:

  1. Send support your account details. Your Snowflake account identifier (organization and account name) and its cloud and region.
  2. unPLUG shares the data with your account. Support tells you the name it appears under.
  3. Create a database from it. A user with the ACCOUNTADMIN role, or a role with the IMPORT SHARE privilege, accepts the share in Snowsight or with SQL, then grants access to the roles that need it.
Snowflake SQL
-- 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:read or 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 members snapshot, and from the Snowflake tables within a refresh. Rows you already loaded stay in your copy until you remove them. Listen for member.deleted and delete that member's rows from your systems.
  • Marketing consent. Use communication_preferences before 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.