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:
- Direct sign-up — you sign up at ripllo.com and Ripllo creates a workspace anchored to your Huudis user ID (
usr_<huudisUserId>). - 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>), neverusr_*.
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) orfixed(e.g. IDR 25,000 off) - A
valuein the chosen unit - A
currency - A
scope:all(everything in the cart),products(only specific product IDs), ortag(only items matching a tag filter) - Optional
minPurchaseAmount,maxUsesTotal,maxUsesPerCustomer,startsAt,expiresAt - An
activeflag - A
publicflag — 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') andexternalRef(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(percentorfixed) for both the referrer and the referee referrerValue— reward for the existing customer who shares the linkrefereeValue— reward for the new customer who clicks itcurrencyminPurchaseAmount— the smallest order that triggers a rewardrewardExpiryDays— how long an issued reward stays validattributionWindowDays— 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.
Referral link
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:
enableddelayMinutes— how long after a cart goes idle before the first reminderdiscountCodeId(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
externalSourceandexternalRef(the upstream cart ID)- A
recoveredflag 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
titleandbody(markdown) - An optional
excerpt,coverImage,authorName,tags - A
status(draft/published/archived) - SEO
metaTitleandmetaDescription - A
publishedAttimestamp
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
EmailIntegrationrow) - A template (compiled to HTML at send time)
- A schedule (
sendAt) orsend-now - A status lifecycle:
draft→scheduled→sending→sent(orfailed/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:adminfor 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
externalReffor 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
- Portal tour — the dashboard, feature by feature.
- API reference — every endpoint.
- Authentication — how sign-in works.