03 - Customizing your Marketplace Listing


How to compose a listing's detail page in the Super App. A listing is made
of ordered panels (sections), and each panel holds ordered cards
(offers). The on-screen look is the combination of a panel's panelType +
layout and a card's design + linkType.

See also: Getting Started for the onboarding
checklist and Integration & API Reference
for the full lifecycle walkthrough.


1. Storefront at a glance

You can customize how your marketplace listing appears on our app through our composable interface.

2. Panel styles

2.1 panelType — what the section accepts


ValuePurpose
OFFERSPurchasable in-app offers (bought via POST /marketplace/purchase)
PROMOTIONSExternal promos / deeplinks / webviews — no purchase flow
OCCASIONSSeasonal / themed campaign (Ramadan, National Day…)
CARD_GRIDGeneral catch-all; what the app synthesizes from a legacy cards[]-only payload
INFOText-only section (bodyEn/bodyAr), no cards

2.2 layout — how the row renders

ValueLookRecommended for
HERO_CAROUSELSwipeable wide cardsOCCASIONS
GRID2-column tile gridOFFERS
LISTStacked vertical rows (default)PROMOTIONS / CARD_GRID
BANNERSingle full-width card, no scrollone featured hero item

2.3 Other fields

FieldTypeNotes
titleEn/Arstring ≤200Section title, shown when showTitle: true
showTitlebooleanDefault false; mainly used for OCCASIONS
subtitleEn/Arstring ≤200One-line subtitle
themeColor#RRGGBBHex accent for the section chrome
bannerImageUrlURL/gs://Panel hero banner (set via the banner upload endpoint)
expiresAtISO 8601Campaign expiry; null = never expires
bodyEn/Arstring ≤2000Plain body copy — INFO panels only
featuredStoreId, featuredStoreLabelEn/Ar—Featured store reference

3. Card (offer) styles

FieldTypeNotes
designbanner | tile | compactCard visual treatment (required)
linkTypedeeplink | webview | offerLaunch behavior (required)
urlstring ≤2048webview needs http(s); deeplink accepts any scheme; offer may be empty
titleEn/Arstring ≤200Card title (required)
descriptionEn/Arstring ≤2000Body copy
imageUrlURL/gs://Card thumbnail (image upload endpoint)
pricedecimal stringUnit price; omit to keep the card non-purchasable
originalPricedecimal stringPre-discount price, shown struck through
currencyISO 4217Default SAR
inStockbooleanDefault true; false soft-disables the card
perUserLimitint 1–999Max purchases per customer
badgeLabelstring ≤60Attention badge (e.g. "Best seller")
badgeColor#RRGGBBStyles badgeLabel
bannerImageUrlURL/gs://Hero image for the card's detail screen
highlightTextstring ≤200Short highlight copy
termsEn/Arstring ≤2000Purchase terms shown near checkout
offerExpiresAtISO 8601After this moment the card is not purchasable
fulfillmentModeINSTANT | PARTNER_CONFIRMATIONDefault INSTANT

4. Style recipes

Pick the section type, its layout, and the cards' design to produce each view.

Desired viewpanelTypelayoutCard designCard linkType
Seasonal hero carouselOCCASIONSHERO_CAROUSELbanneroffer/deeplink
Purchasable 2-column gridOFFERSGRIDtileoffer
Stacked promos / deeplinksPROMOTIONSLISTtile/compactdeeplink/webview
Single full-width featurePROMOTIONSBANNERbannerdeeplink
Text-only section (how it works)INFOLIST——
Legacy / unclassified dumpCARD_GRIDLISTtileany

Set showTitle: true, subtitle, themeColor, and bannerImageUrl on
campaigns (OCCASIONS), and bodyEn/Ar on INFO sections.


5. The flow

5.1 Listing lifecycle

stateDiagram-v2
    [*] --> DRAFT
    DRAFT --> SUBMITTED : submit listing
    CHANGES_REQUESTED --> SUBMITTED : submit listing
    REJECTED --> SUBMITTED : submit listing
    SUBMITTED --> IN_REVIEW : admin review
    IN_REVIEW --> APPROVED : admin approves
    IN_REVIEW --> CHANGES_REQUESTED : changes requested
    IN_REVIEW --> REJECTED : admin rejects
    APPROVED --> PUBLISHED : published in Super App
StatusMeaningEditable?
DRAFTNot yet submitted✔
CHANGES_REQUESTEDAdmin asked for changes✔
REJECTEDAdmin rejected✔
SUBMITTEDQueued for review—
IN_REVIEWUnder admin review—
APPROVED / PUBLISHEDLive / scheduled to go live—

5.2 Panels

MethodEndpointPurpose
GET.../listing/panelsList sections with cards
POST.../listing/panelsCreate a section
PATCH.../listing/panels/reorderReorder sections
PATCH.../listing/panels/:panelIdUpdate a section
DELETE.../listing/panels/:panelIdDelete a section (must be empty)
POST.../listing/panels/:panelId/bannerUpload the panel banner

5.3 Cards (offers)

MethodEndpointPurpose
GET.../listing/offersList cards
POST.../listing/offersCreate a card
PATCH.../listing/offers/:offerIdUpdate a card
PATCH.../listing/offers/reorderReorder cards (per panel)
DELETE.../listing/offers/:offerIdDelete / soft-disable a card
POST.../listing/offers/:offerId/imageUpload the card thumbnail
POST.../listing/offers/:offerId/bannerUpload the card banner

5.4 Worked examples

Create a HERO_CAROUSEL campaign panel via
POST .../listing/panels:

{
  "panelType": "OCCASIONS",
  "layout": "HERO_CAROUSEL",
  "titleEn": "Ramadan Specials",
  "titleAr": "عروض رمضان",
  "showTitle": true,
  "subtitleEn": "Iftar & suhoor deals, all month",
  "themeColor": "#16A34A",
  "expiresAt": "2026-09-18T21:00:00Z"
}

Create a purchasable card inside that panel via
POST .../listing/offers:

{
  "panelId": "12",
  "titleEn": "Silver top-up",
  "titleAr": "تعبئة فضية",
  "design": "tile",
  "linkType": "offer",
  "url": "",
  "price": "49.99",
  "originalPrice": "79.99",
  "currency": "SAR",
  "badgeLabel": "Best seller",
  "badgeColor": "#E8553C",
  "fulfillmentMode": "INSTANT"
}
  • Omit panelId to place a card in the implicit ALL_CARDS panel; set it to
    move a card to another section (same listing).
  • price is a decimal string (≤ 7 integer + 2 fraction digits). Omit it to keep
    the card non-purchasable.

6. Rules & limits

  • Order: the app sorts panels[] then each panel's items[] by sortOrder
    ascending; the reorder endpoints rewrite these.
  • Implicit panel: a listing always has an ALL_CARDS panel once the first
    card is authored.
  • Fallbacks (client-side): unknown layout → LIST; unknown panelType →
    CARD_GRID.
  • Deprecated cards[]: the customer detail API still returns a flattened
    cards[] (union of all panels[].items[]) for backward compatibility — build
    against panels[].
  • Limits: max 20 panels and 20 cards per listing.
  • Delete rules: a panel must be empty before deletion; a card with existing
    orders is soft-disabled (inStock=false) instead of deleted to preserve order
    history.

7. Summary

  • Compose panels with the right panelType + layout, and cards with the right
    design + linkType, then reorder both to control the exact on-screen view.
  • Listing content is editable only in DRAFT / CHANGES_REQUESTED / REJECTED;
    submit it for review once the storefront is final.

You can now build and arrange a storefront. Submit the listing via
POST .../listing/submit
to move it into the admin review queue.


Did this page help you?