Concepts

This page covers the building blocks of Ripllo: what each object is, how they relate to each other, and the lifecycle they go through. Read this before you go deep on any specific feature — the rest of the docs assume you know what a discount code is and how it differs from a referral attribution.

The data model

Workspace
  ├── Discount codes
  │     └── Redemptions
  ├── Referral program (one per workspace)
  │     ├── Referral links
  │     └── Attributions
  ├── Abandoned-cart config
  │     └── Reminders
  ├── Merchant pixels
  ├── Merchant feed config (Google Merchant Center XML)
  ├── Blog posts
  ├── Marketing campaigns
  ├── API keys
  └── Webhook endpoints

Everything is scoped to a workspace. Cross-workspace queries don't exist — if you operate two storefronts, you'll have two workspaces and treat them as fully separate.

Workspace

A workspace is the top-level tenant boundary. Each workspace has its own discount codes, referral program, pixels, API keys, blog posts, and team members. Workspaces are isolated. Data never crosses between them.

There are two ways a workspace gets created:

  1. Direct sign-up — you sign up at ripllo.com and Ripllo creates a workspace anchored to your Huudis user ID (usr_<huudisUserId>).
  2. Partner-provisioned — Storlaunch (or another partner) creates a workspace on your behalf when you enable the Ripllo module. The anchor is the partner's account ID (acc_<storlaunchAccountId>), never usr_*.

The two namespaces never cross — this matters when you're seeding data via the partner SDK because using the wrong prefix orphans the rows.

Discount code

A discount code is a string a customer enters at checkout to reduce their total. Examples: WELCOME10, BLACKFRIDAY, FREESHIP.

A discount code has:

  • A unique code (case-insensitive within a workspace)
  • A type: percent (e.g. 10% off) or fixed (e.g. IDR 25,000 off)
  • A value in the chosen unit
  • A currency
  • A scope: all (everything in the cart), products (only specific product IDs), or tag (only items matching a tag filter)
  • Optional minPurchaseAmount, maxUsesTotal, maxUsesPerCustomer, startsAt, expiresAt
  • An active flag
  • A public flag — if true, the code shows up in the applicable-codes endpoint your storefront can hit for a teaser

Identifier: disc_01H….

Discount redemption

A redemption is the record of one customer using one code on one order. Idempotent on externalRef (the order ID), so retried webhooks don't double-count.

A redemption stamps:

  • The discount code ID
  • The customer ID
  • The subtotal at the time of redemption
  • The currency
  • externalSource (e.g., 'storlaunch') and externalRef (the upstream order ID)

Identifier: red_01H….

Referral program

A referral program is a single per-workspace configuration. It defines:

  • Whether the program is enabled
  • The reward type (percent or fixed) for both the referrer and the referee
  • referrerValue — reward for the existing customer who shares the link
  • refereeValue — reward for the new customer who clicks it
  • currency
  • minPurchaseAmount — the smallest order that triggers a reward
  • rewardExpiryDays — how long an issued reward stays valid
  • attributionWindowDays — how long after a click the referrer still gets credit
  • Optional maxRewardsPerReferrer

There's exactly one referral program per workspace, fetched and updated via GET/PUT /referrals/program.

A referral link is a personal share URL minted for a single existing customer. Two customers in the same program get different links. The link is the join key between "who shared it" and "who used it".

A link has:

  • A code (the human-friendly slug, e.g. alice-7Q9)
  • A customerId (the referrer)
  • A click counter and signup counter
  • Optional expiry

Identifier: rl_01H….

Referral attribution

An attribution is the record of a referral chain: referrer X referred referee Y who placed order Z. Attributions move through a small lifecycle:

State Means
pending Referee signed up via the link but hasn't completed a qualifying purchase yet
qualified Referee's first paid order cleared — rewards are about to issue
rewarded Rewards have been minted (as disc_* codes) for both sides
voided Order refunded; rewards clawed back
expired Attribution window ran out before a qualifying purchase

The lifecycle is driven by the payment-success webhook (fulfillRewardOnPayment) and the refund webhook (voidAttributionOnRefund) from Plugipay or Storlaunch.

Abandoned-cart config

An abandoned-cart configuration is per-workspace settings for the recovery flow:

  • enabled
  • delayMinutes — how long after a cart goes idle before the first reminder
  • discountCodeId (optional) — a code attached to the reminder email
  • Sender / subject / body templates

Abandoned-cart reminder

A reminder is a single send event. It records:

  • The customer who abandoned
  • The cart snapshot (line items at send time)
  • The cart value
  • The discount code attached, if any
  • externalSource and externalRef (the upstream cart ID)
  • A recovered flag set later if the same customer completes checkout within the recovery window

Reminders honor the BuyerEmailPreference opt-out list — suppressed emails skip the send entirely.

Identifier: acr_01H….

Merchant pixels

Merchant pixels are tracking IDs the merchant configures so their storefront can fire analytics + ad-platform events. One row per workspace, holding:

  • Meta (Facebook) pixel ID + optional CAPI access token (server-side conversion API)
  • GA4 measurement ID
  • Google Ads conversion ID
  • TikTok pixel ID

The CAPI access token is never returned on the public storefront read endpoint (GET /pixels/public/:accountId) — only the public-facing IDs surface there.

Merchant feed config

A feed configuration holds settings for product feeds the storefront generates. Today: Google Merchant Center XML. The XML itself is generated on demand at GET /feeds/google/:accountId.xml and is shaped by:

  • enabled
  • The merchant's brand / country / language defaults
  • Currency

The product list itself is pulled from Storlaunch at feed-render time — Ripllo doesn't store the catalog.

Blog post

A blog post is the merchant's content-marketing record. Each post has:

  • A slug
  • A title and body (markdown)
  • An optional excerpt, coverImage, authorName, tags
  • A status (draft / published / archived)
  • SEO metaTitle and metaDescription
  • A publishedAt timestamp

Identifier: post_01H…. Posts are served on the storefront at GET /blog/public/:accountId (list) and GET /blog/public/:accountId/:slug (single).

Marketing campaign

A marketing campaign is a one-shot send to a list of contacts: email blast, SMS, etc. A campaign has:

  • A target audience (a contact list or audience segment)
  • A channel reference (an EmailIntegration row)
  • A template (compiled to HTML at send time)
  • A schedule (sendAt) or send-now
  • A status lifecycle: draftscheduledsendingsent (or failed / cancelled)

Identifier: mc_01H….

API key

An API key authenticates server-to-server calls. Keys have:

  • An identifier (AKIARPLO<random>)
  • A secret shown once at creation
  • A scope (* for full access, ripllo:platform:admin for partners)
  • A creation date
  • A last-used timestamp

Keys are per-workspace. They authenticate via HMAC signing of the request — see API → Authentication.

Identifiers (the prefix system)

Every Ripllo object has a typed prefix on its ID. Use this to read at a glance what kind of object you're holding:

Prefix Type
usr_ Workspace anchored on a Huudis user (direct sign-up)
acc_ Workspace anchored on a partner account (e.g. Storlaunch)
disc_ Discount code
red_ Discount redemption
rl_ Referral link
att_ Referral attribution
acr_ Abandoned-cart reminder
post_ Blog post
mc_ Marketing campaign
ak_ / sk_ API key (access ID / secret)
whep_ Webhook endpoint

The suffix is a ULID — sortable by creation time, globally unique.

Why this matters

The model isn't ornamental — it shapes how you build integrations:

  • Webhook handlers dispatch on event type, named after the object (discount.redeemed, referral.attributed, abandoned_cart.recovered).
  • Idempotency is keyed on externalRef for partner-provisioned writes, so you can safely retry a redemption call.
  • Audit log records actions on objects by ID, so you can trace who edited which discount.

Once you have this mental model, the rest of the docs are linear — each portal page, each API endpoint, each SDK method maps cleanly to one of these objects.

Next