Build for Baseet
Baseet is an Arabic-first commerce platform for MENA. This is where you learn to build on it — starting with storefront themes, and soon apps and the API.
What you can build today
- Themes — complete storefront designs, expressed as data, not code, rendered by one trusted engine. Available
- Apps & the public API — extend a store's functionality and data. Coming
A theme you publish can be installed by any Baseet merchant. You keep the majority of every sale (70/30 in your favor).
Quickstart
Scaffold, design, preview, and submit a theme — the whole loop — in about ten minutes.
1 · Get your key
The Baseet team issues you a scoped developer key (bth_live_…). It's the only credential you need, and it only authorizes submitting your own themes. Sign in at developers.baseet.dev and keep it somewhere safe — treat it like a password.
2 · Scaffold a theme
From a Baseet workspace checkout:
# creates the two DATA files + auto-registers the theme
npm run theme -- init my-theme --name-en "My Theme" --name-ar "ثيمي" --industry fashion
That's it — no React, no build config. You now have a manifest and a preset to edit.
3 · Make it yours
Edit the two generated files — the preset (design tokens + starter content) and the manifest (which sections, in what order). Point a demo store's theme_id at your id to see it live, then validate:
npm run theme -- validate my-theme
4 · Submit for review
export BASEET_THEME_KEY=bth_live_… npm run theme -- submit my-theme --changelog "First release"
Your version lands as Pending and appears on your dashboard. The Baseet team reviews it, then publishes it or returns notes. Once published, it renders live for merchants with no deploy.
Core concepts
A few ideas explain every decision on the platform. Learn these and the rest follows.
Data, not code
A Baseet theme ships no executable code. It's a manifest (structure) plus a preset of design tokens (look). One trusted renderer turns that data into a storefront. This is the platform's core safety property: the least-privileged thing you can build is a theme, so themes are safe to install, review, and run at scale — and a theme can go live without a code deploy.
Two planes
| Plane | What |
|---|---|
| baseet.cc | The product — merchants, storefronts, the company. Ships fast. |
| baseet.dev | The platform — you, the docs, the APIs, the tools. Moves on stable, versioned contracts. |
They're deliberately separate: a product change can never break a contract you built against.
Stable contracts
Everything you depend on — the theme manifest schema, the CLI, and (soon) the API and webhooks — is a versioned contract. Changes are additive by default; anything removed is deprecated on a published schedule with a migration guide. See Versioning & stability.
Least-privilege credentials
Your key is scoped to exactly one capability and nothing else. It can't reach billing, other developers' themes, or any other data. A leaked key's worst case is "a theme that gets rejected in review." See Security.
Theme anatomy
A theme is exactly two files of data, plus the one engine that renders them.
The manifest — structure
Declares the theme's identity and its ordered list of sections (hero, categories, featured products, testimonials, …), each with a layout variant and animation. The manifest defines availability + order; every section still gates on the merchant's own store config at render time.
export const MyThemeManifest = {
id: 'my-theme',
name: { en: 'My Theme', ar: 'ثيمي' },
version: '1.0.0',
industry: 'fashion',
directions: ['rtl', 'ltr'],
sections: [
{ schemaId: 'hero', layoutVariant: 'split', animation: 'fadeUp' },
{ schemaId: 'categories', animation: 'fadeUp' },
{ schemaId: 'featured', animation: 'staggerCards' },
// …reorder / remove / re-variant freely
],
};
The preset — look + starter content
Design tokens (colors, radii, fonts) plus demo hero/benefits content. The theme's entire visual language lives in tokenOverrides.
export const MY_THEME_PRESET = {
id: 'my-theme', themeId: 'my-theme',
accentColor: '#1C1917',
tokenOverrides: {
'--color-background': '#FAFAF9',
'--color-accent': '#1C1917',
'--radius-card': '14px',
'--font-display': "'Fraunces', serif",
'--font-body': "'Manrope', 'IBM Plex Sans Arabic', sans-serif",
},
homeContent: { /* demo hero, benefits, … */ },
};
The engine — one renderer for every theme
The storefront engine reads your manifest + tokens and dispatches each section to the shared component registry. You never write render code — which is why a new theme is a manifest + a preset, and nothing else.
Sections & tokens
The building blocks you compose, and the token vocabulary that colors them.
Sections
Each manifest entry references a schemaId. The engine renders it from the merchant's store data. Common sections:
| schemaId | Renders |
|---|---|
| hero | Hero banner / slider (variants: split, static, full) |
| categories | Category tiles (grid / pills / circles / scroll) |
| featured · new_arrivals · products · most_loved · sale | Product grids |
| benefits | Trust/benefit strip |
| banners · promo | Promotional banners |
| testimonials · brands · instagram | Social proof |
| bundles · bundle_offers · shop_the_look · before_after · hero_product | Merchandising |
Design tokens
Sections read CSS variables, never raw colors — so your preset's tokens re-skin every section at once. Token names are roles, not adjectives (--color-accent, not --color-blue). Core roles:
- Color — --color-background, --color-surface, --color-on-surface, --color-accent, --color-on-accent, --color-muted, status roles.
- Radius — --radius-card, --radius-button, --radius-input.
- Type — --font-display, --font-body, and always an Arabic-capable stack.
The design bar
Every theme must clear this standard before it publishes. It's what keeps the marketplace worth browsing.
Engineering rules (must)
- Never hardcode a color, radius, or shadow in a section — read a token.
- A theme is data, never React. If you want to write JSX, you've found a missing section, not a theme.
- Every theme ships every token the schema requires.
- Token names are roles, not adjectives.
Design rules (the taste bar)
- A distinct design language across all surfaces — home, product, checkout, profile, empty/error states — not "the home page styled."
- One icon family, one stroke weight, one fill style.
- Mobile and desktop are equal first-class targets; touch targets ≥ 44px.
- WCAG AA contrast (4.5:1 body); focus rings always visible; color never the only signal.
The anti-AI checklist — block at 3+ hits
Score your theme against these; three or more and it won't pass review:
- Indigo/purple gradient as the primary accent.
- 3D blobs or floating geometric shapes in the hero.
- Sparkle / wand / star icons in a storefront section.
- "Get Started Free →" or "Modern. Fast. Beautiful." copy.
- Cards rotated "for energy."
- Every card using the same hover:-translate-y-1 hover:shadow-2xl.
- Tailwind default slate greys as the only surface tone.
- Aurora / mesh-gradient backgrounds without purpose.
- Glassmorphism as the default surface.
- Stock Unsplash placeholder photography.
RTL & Arabic
Baseet is Arabic-first. RTL is a first-class design target, not a mirror of the LTR version.
- Design in EN (LTR) and AR (RTL) simultaneously — flipping later reliably breaks layouts.
- Ship --font-arabic separately — a Latin font's fallback silently covers Arabic with the wrong glyphs. Lead Arabic stacks with the Arabic font.
- Arabic body copy usually needs +0.1–0.2 line-height vs. Latin.
- Directional icons (chevrons, arrows) flip automatically; brand and object icons must not.
- Numerals, prices, phone numbers, SKUs, and codes stay LTR inside RTL text.
- Use logical CSS (padding-inline-start, not padding-left). Note: logical props resolve per-element direction — inside a dir="ltr" island (a price, a phone input) they don't flip with the page.
Testing & preview
Prove the theme works before you submit — the review is faster when you've already checked.
Validate
npm run theme -- validate my-theme
Checks bilingual names, RTL support, that every section resolves in the schema, known field types, and that your preset and manifest are wired consistently.
Preview on a demo store
Point a demo store's theme_id at your theme id and open it. Check, in this order: home, product listing, product detail (with several sections on), cart, checkout, thank-you, profile, and the empty / error / loading states — each in EN + AR, mobile + desktop.
The pre-submit checklist
- Header/footer identical on every page.
- Same button, input, and modal style everywhere.
- Long product page has rhythm (alternating section weights).
- Empty states are designed, not blank.
- Anti-AI checklist ≤ 2 hits.
Submit & review
How a theme goes from your machine to the review queue, and what reviewers look for.
Submitting
export BASEET_THEME_KEY=bth_live_… npm run theme -- submit my-theme --changelog "what changed"
The CLI validates locally first, then submits the manifest + tokens to Baseet over an authenticated, scoped-key endpoint. The version lands as Pending and shows on your dashboard. Each release is an immutable version — to iterate, bump the semver and resubmit.
What review checks
- Design quality — the design bar (distinct language, anti-AI ≤ 2).
- RTL / Arabic correctness — native-feeling in both directions.
- Accessibility — contrast, focus, touch targets.
Outcomes
A reviewer approves (→ ready to publish), requests changes (with specific notes on your dashboard — fix and resubmit a new version), or rejects. You see every decision and note in the Theme detail view.
Publishing
What happens when your theme goes live — and the promise that comes with it.
Once a reviewer publishes an approved version, it enters the Baseet theme library and any merchant can install it. Because a theme is data, publishing takes effect with no deploy — the storefront engine picks it up from the registry.
Lifecycle states
| State | Meaning |
|---|---|
| Draft | Created, not yet submitted. |
| In review | A version is pending a decision. |
| Published | Live in the library, installable. |
| Suspended | Temporarily removed (contact the team). |
| Retired | Withdrawn from new installs. |
Your dashboard shows install/usage analytics per theme so you can see your reach.
Versioning a theme
Ship improvements without breaking merchants already using your theme.
- Every submission carries a semver (x.y.z) and is immutable once submitted.
- Patch (1.0.1) — safe, additive fixes.
- Minor (1.1.0) — new sections/options, backwards-compatible.
- Major (2.0.0) — a redesign that changes the look meaningfully; treat it as a distinct offering so merchants opt in deliberately.
The manifest also declares the schema version it targets. Baseet keeps published themes rendering across schema changes; when a required capability changes, you'll get a deprecation window and a migration note — see Versioning & stability.
CLI reference
The theme developer kit. One tool: scaffold, validate, list, submit.
init <id>
Scaffolds the manifest + preset for a new engine theme and auto-registers it.
npm run theme -- init <id> [--name-en X] [--name-ar X] [--industry fashion] [--accent #hex]
validate [<id>]
Runs the acceptance gate: bilingual names, RTL, sections resolve, field types, preset/manifest consistency. Add --all to validate every theme.
npm run theme -- validate <id>
list
Lists every registered theme and whether it's engine-enabled.
npm run theme -- list
submit <id>
Validates locally, then submits the theme for review. Requires your key.
export BASEET_THEME_KEY=bth_live_… npm run theme -- submit <id> [--changelog "…"]
| Env var | Purpose |
|---|---|
| BASEET_THEME_KEY | Your scoped developer key (bth_live_…). Never stored or committed. |
| BASEET_THEME_SUBMIT_URL | Optional override of the submit host. |
Tutorial — sync a catalog to an ERP
A complete walkthrough: read a store's catalog, keep it in sync, and react to changes. ~15 minutes. All code is Node 18+ (built-in fetch) or the SDK.
1 · Get a key with the right scopes
The merchant creates a key in Baseet dashboard → Settings → API Keys. For a two-way ERP sync, grant read_products + write_products (add read_store to read the currency). Store it as BASEET_KEY.
2 · Read the whole catalog
Lists are cursor-paginated — loop until next_cursor is null:
const BASE = "https://api.baseet.dev/2026-07";
const H = { Authorization: `Bearer ${process.env.BASEET_KEY}`, "Baseet-Version": "2026-07" };
async function* allProducts() {
let cursor = null;
do {
const qs = new URLSearchParams({ limit: "100" });
if (cursor) qs.set("cursor", cursor);
const res = await fetch(`${BASE}/products?${qs}`, { headers: H });
if (!res.ok) throw new Error(`${res.status} ${(await res.json()).error?.message}`);
const page = await res.json();
for (const p of page.data) yield p; // p.price.amount is MINOR units
cursor = page.next_cursor;
} while (cursor);
}
for await (const p of allProducts()) upsertIntoErp(p);
3 · Map the fields
- Money: price.amount is an integer in minor units — 45000 ÷ 100 = 45.00 price.currency.
- Names: title.en / title.ar — pick per your ERP's locale.
- Identity: store Baseet's id against your ERP row so later updates target the right product.
4 · Push a change back (idempotent)
When the ERP changes a price or stock, PATCH it. Always send an Idempotency-Key so a network retry can't double-apply:
await fetch(`${BASE}/products/${baseetId}`, {
method: "PATCH",
headers: { ...H, "Content-Type": "application/json", "Idempotency-Key": crypto.randomUUID() },
body: JSON.stringify({ price: { amount: 39000, currency: "EGP" }, status: "active" }),
});
5 · Create products from the ERP
await fetch(`${BASE}/products`, {
method: "POST",
headers: { ...H, "Content-Type": "application/json", "Idempotency-Key": crypto.randomUUID() },
body: JSON.stringify({ title: { en: "New SKU", ar: "منتج" },
price: { amount: 25000, currency: "EGP" }, status: "draft", sku: "ERP-1001" }),
});
6 · Stay in sync — webhooks, not polling
Instead of re-reading everything, subscribe to products/updated + orders/created and update the ERP on each event. Verify the signature before trusting a payload (see Webhooks below / the Authentication page). That's a two-way sync: ERP → Baseet via writes, Baseet → ERP via webhooks.
Next: the Examples for copy-paste recipes, or the SDK to skip the fetch boilerplate.
Guides
Task-focused how-tos. Start with the Quick start, then reach for these.
| Guide | Covers |
|---|---|
| API overview | base URL, versioning, conventions (money, locales, pagination) |
| Authentication | keys, scopes, rate limits, errors, idempotency |
| SDK | the typed @baseet/sdk client |
| Catalog ↔ ERP sync | the full worked walkthrough |
| Examples | short copy-paste recipes |
| Troubleshooting | error codes and fixes |
Building a theme instead of integrating? See the theme docs (quick-start router) — that's a different track.
Examples
Short recipes. All assume BASE + H from the tutorial.
Find a product by SKU
// no server-side SKU filter yet — page + match client-side
let hit = null;
for await (const p of allProducts()) if (p.sku === "WAL-01") { hit = p; break; }
Bulk price change (+10%)
for await (const p of allProducts()) {
const amount = Math.round(p.price.amount * 1.1);
await fetch(`${BASE}/products/${p.id}`, { method: "PATCH",
headers: { ...H, "Content-Type": "application/json", "Idempotency-Key": crypto.randomUUID() },
body: JSON.stringify({ price: { amount, currency: p.price.currency } }) });
}
Export the catalog to CSV
const rows = [["id","title","price","currency","status"]];
for await (const p of allProducts())
rows.push([p.id, p.title.en, (p.price.amount/100).toFixed(2), p.price.currency, p.status]);
require("fs").writeFileSync("catalog.csv", rows.map(r => r.join(",")).join("\n"));
Verify a webhook (Express)
import { createHmac, timingSafeEqual } from "node:crypto";
app.post("/hook", express.raw({ type: "*/*" }), (req, res) => {
const sig = req.get("X-Baseet-Hmac-SHA256") || "";
const exp = createHmac("sha256", process.env.HOOK_SECRET).update(req.body).digest("hex");
const a = Buffer.from(exp), b = Buffer.from(sig);
if (a.length !== b.length || !timingSafeEqual(a, b)) return res.sendStatus(401);
res.sendStatus(200); // then process JSON.parse(req.body) async, de-dupe on event id
});
Migration guides
How to move between API versions when the time comes.
Today
There is one live version — 2026-07. Nothing to migrate yet. Pin it with Baseet-Version: 2026-07 and you're stable.
When a new version ships
- The old version keeps working for ≥12 months — no rush.
- A migration note lists exactly what changed (added/removed/retyped fields) and the replacement.
- Move at your own pace: change the Baseet-Version header, adjust for the listed diffs, test, ship.
- Within a version nothing breaks (additive only), so day-to-day you never migrate.
See the Deprecation policy for the guarantees.
Themes
A theme version is data (the manifest). A store re-resolves to a newer theme version with its configuration preserved — there's no per-store code migration.
Release notes
2026-07 — initial public API
- API launched at api.baseet.dev/2026-07: GET /store, GET /products (cursor pagination + filters), GET /products/{id}, POST /products, PATCH /products/{id}.
- Auth: scoped bak_live_ keys (per-store, hashed, revocable) with read/write scopes.
- Writes are replay-safe via Idempotency-Key.
- Webhooks contract: signed (X-Baseet-Hmac-SHA256), versioned topics for products/orders/customers/inventory.
- SDK: @baseet/sdk, typed from the same contract.
Full change history: Changelog. Guarantees: Versioning & stability.
API — Overview
Connect an external system — an ERP, a PIM, a custom app — to a store's data over versioned REST.
Base URL: https://api.baseet.dev/2026-07. Send the pinned version on every request as Baseet-Version: 2026-07 — a dated version is an immutable contract; breaking changes ship as a new dated version.
Your first call
curl "https://api.baseet.dev/2026-07/store" \
-H "Authorization: Bearer bak_live_xxx" \
-H "Baseet-Version: 2026-07"
Conventions
- Money is an integer in minor units + currency: { "amount": 110000, "currency": "EGP" } = 1100.00 EGP.
- Text is bilingual: { "en": "…", "ar": "…" }.
- Lists are cursor-paginated — follow next_cursor until it is null.
API — Authentication
Every request carries a scoped bearer key: Authorization: Bearer bak_live_…
A key belongs to one store — resolved from the key, so you never pass a store id, and a key can never touch another store. Keys are stored hashed and are revocable (a revoked key returns 401 on the next request).
Scopes
Reads and writes are separate; grant only what's needed:
read_store read_products write_products read_orders write_orders read_customers write_customers read_inventory write_inventory read_discounts write_discounts
A call missing its scope returns 403 forbidden.
Rate limits
120 requests/minute per key. Responses carry RateLimit-Limit/Remaining/Reset; on exhaustion, 429 with Retry-After.
Errors
One provider-agnostic envelope: { "error": { "type", "message", "field", "request_id" } }. Types: invalid_request · unauthorized · forbidden · not_found · conflict · rate_limited · server_error. Log request_id for support.
Idempotency
Writes accept an Idempotency-Key (a UUID). A retry with the same key returns the original result; reuse with a different body returns 409. Always send one on writes.
API endpoints
The live endpoints — generated from the OpenAPI contract (openapi.ts), so this list can never drift from what the API actually serves.
Loading endpoints…
SDK — @baseet/sdk
A typed client for the Baseet API. Its types are reused from the API contract, so the SDK can't drift from what the API returns.
Install & init
import { Baseet } from "@baseet/sdk";
const baseet = new Baseet({ key: process.env.BASEET_KEY, version: "2026-07" });
Read the store & catalog
const store = await baseet.store.get();
// products.list() is an async iterator over the WHOLE catalog (cursor pagination handled):
for await (const p of baseet.products.list({ status: "active" })) {
console.log(p.id, p.title.en, p.price.amount, p.price.currency); // amount = minor units
}
const one = await baseet.products.get("prod_1a2b");
Write (idempotent)
const created = await baseet.products.create(
{ title: { en: "New", ar: "جديد" }, price: { amount: 25000, currency: store.currency }, status: "draft" },
{ idempotencyKey: crypto.randomUUID() }, // safe to retry
);
await baseet.products.update(created.id, { status: "active" }, { idempotencyKey: crypto.randomUUID() });
Errors
Failures throw a BaseetError mirroring the API envelope — type, status, request_id, field. Ships versioned in lockstep with the API. Thin over fetch; inject one in non-global-fetch runtimes.
Glossary
| Term | Meaning |
|---|---|
| Store | One merchant's shop. The unit a key is scoped to. |
| bak_live_ key | A merchant's scoped API key — read/write their own store's data (integrations, ERP). |
| bth_live_ key | A developer's key — build & submit themes for many stores. Not a store key. |
| Scope | A permission a key holds, e.g. read_products. Least-privilege; read ≠ write. |
| Version (dated) | An immutable API contract like 2026-07. Breaking changes ship as a new dated version. |
| Minor units | Money as an integer in the smallest unit: 110000 = 1100.00. Never a decimal. |
| Cursor | Opaque pagination token; follow next_cursor until null. |
| Idempotency key | A UUID on a write; a retry with the same key returns the original result. |
| Webhook topic | An event name like products/updated you subscribe to. |
| Bespoke theme | A hand-built React theme, gated on theme_id. |
| Engine theme | A data-not-code theme (manifest + preset) rendered by one component. |
| Manifest | The data that declares a theme's sections & fields — edited by merchants, published as data. |
| Preset | A theme's design tokens (color, type, radii, motion). |
| Section | A composable storefront block (hero, collections…) with editable fields. |
FAQ
How do I get an API key?
A merchant creates one in the Baseet dashboard → Settings → API Keys, choosing scopes. It's shown once.
Is the API read-only?
No — with write_products you can create/update products. Reads and writes are separate scopes.
Why are prices huge numbers?
Money is in minor units: 110000 = 1100.00. Divide by 100 (or the currency's exponent) to display.
How do I paginate?
Follow next_cursor until it's null, or use the SDK's products.list() async iterator.
How do I avoid duplicate writes on retry?
Send an Idempotency-Key (UUID) on every write.
Can one key access more than one store?
No. A key is bound to exactly one store; the store is resolved from the key.
How do I build a theme?
See the theme docs (start with the quick-start router). Developers use a bth_live_ key + the theme CLI.
Troubleshooting
| Symptom | Cause & fix |
|---|---|
| 401 unauthorized | Missing/malformed/revoked key. Check the Authorization: Bearer bak_live_… header; mint a new key if revoked. |
| 403 forbidden | The key lacks the scope. Add the scope (e.g. write_products) when creating the key. |
| 400 invalid_request on create | Missing title.en, bad price, or the store has no product category — create a category first. |
| 409 conflict | An Idempotency-Key was reused with a different body. Use a fresh UUID per distinct write. |
| 429 rate_limited | 120 req/min exceeded. Honor Retry-After and back off. |
| Empty product titles | You're reading a raw field — use the API's title.{en,ar}, not internal columns. |
| Webhook payload can't be trusted | Verify the X-Baseet-Hmac-SHA256 signature over the raw body before parsing. |
| Arabic renders in a Latin font | Lead the Arabic-primary font stack with the Arabic face (Latin fallbacks silently cover Arabic). |
Still stuck? Include the request_id from the error envelope when you contact support.
Deprecation policy
Everything you depend on is a versioned contract. We change it predictably.
- Additive by default. Within a dated version (2026-07), fields are only added — never removed or retyped.
- Breaking changes = a new version. A removed/renamed field or tightened validation ships as a new dated version, never in place.
- Support window. When a new version ships, the previous one is supported for ≥12 months.
- Notice. Deprecations are announced with the version that introduces the replacement and a migration note.
- Themes follow the same rule via the manifest: a store re-resolves to a newer version with its config preserved.
See also Versioning & stability.
Sections & fields reference
The complete section vocabulary the engine renders — generated from the code (SECTION_SCHEMA), so it can never drift from what actually ships.
Loading reference…
Versioning & stability
The promise that lets you build on Baseet without fear of it moving under you.
- Additive by default. New capability = a new field / option / version. Existing fields don't change meaning or disappear inside a version.
- Deprecation is scheduled, never silent. Anything going away is announced on the changelog with a migration guide and a support window (target: ≥ 12 months) before removal.
- Contracts are versioned. The theme manifest schema, the CLI, and — soon — the public API and webhooks each carry a version you can pin against.
- Calendar versioning for the platform API (dated, e.g. 2026-07): a version you adopt never changes underneath you.
Security
The model that makes building on Baseet safe for you and for merchants.
Your key
- Scoped to one capability (submit your own themes) — nothing else. It cannot reach billing, tenants, or other developers' data.
- Stored hashed — the raw value is shown once. Rotate or revoke it any time from the dashboard.
- A leaked key's worst case is a theme that gets rejected in review.
Why data-not-code is a security feature
A theme carries no executable code and no secrets — it's the least-privileged thing on the platform. That's what lets Baseet review, install, and run third-party themes across thousands of stores with confidence.
Your responsibilities
- Never commit or expose your key.
- Never ship placeholder secrets or third-party tokens inside a theme.
- Report anything that looks like a way to exceed a theme's privileges.
Changelog
Every change to the developer platform, dated and categorized. This page is a contract — nothing changes without appearing here.
2026-07 · Developer platform — early access
- Added — the theme marketplace: scoped developer keys, CLI submit, the review queue, and publish-with-no-deploy.
- Added — the developer dashboard at developers.baseet.dev.
- Added — these docs at docs.baseet.dev.
Roadmap
What we're building, roughly in order. Directional, not a commitment on dates.
Now
- Theme platform to GA — the developer dashboard, submission, review, and publish loop.
Next
- Generated reference — manifest, section, and CLI reference generated from the code schemas so they can't drift.
- The public API — a versioned REST API + a typed SDK, designed so the same schema powers the SDK and AI/MCP tools.
- Webhooks — a signed, versioned event contract.
Later
- Apps & extensions · a partner program · earnings statements & payouts.