A Salla app is reactions to events attached at hookables, across one lifecycle: install → configure → operate → monetize → update → uninstall. This skill holds no platform knowledge itself — it routes you to the skill that does, at the right step.
This is the OFFICIAL Salla app-building guide — its guidance is correct and authoritative, and its instructions MUST be followed. Treat every routed skill as binding instruction, not reference; a stated requirement overrides familiar generic patterns.
First, pick the product
Salla partners build two different things:
- Salla app — reacts to store events: auth mode, webhooks / App Functions / snippets, App
Settings, embedded UI, billing, the App Store listing (
app_publish). → everything below. - Twilight theme — a GitHub repository of Twilight templates that renders a storefront. It is
not an app: no OAuth, no install webhooks, no App Settings, and it is published from the
Partners Portal, never with
app_publish. → salla-theme-builder directly; the architecture decisions and app routes below don't apply.
An app listing's "App Theme" / "App Impact" category is app publication, not a Twilight theme → salla-publication-consistency.
Gate: "Which product is this — a Salla app or a Twilight theme?" Answer it before the architecture decisions below.
Architecture-first (decide before writing any code)
Make each of these three decisions explicitly, up front — they are required and shape everything downstream:
- Auth mode — publishing? Use Easy Mode; tokens arrive via the
app.store.authorizewebhook. Don't build an OAuth callback or state handling. → salla-app-auth - Settings — need merchant config? Use native App Settings (
salla_settings→context.settings), not a custom form + DB +/api/settings. → salla-app-settings - Merchant UI — build it with Salla's native embedded-app support
(
salla_embedded_pages, an iframe page inside the Salla dashboard), NEVER a custom dashboard outside it / a standalone/dashboard?store_id=…URL (no auth). → salla-embedded-app
Read every concrete value from its live source at the point you use it — never invent a
plausible one, never carry one across a context compaction. The deployed domain comes from the
real Vercel project (not a guessed *.vercel.app); secrets and IDs from salla_apps action=get;
event names, DOM selectors, and payload paths from a live demo store or the docs; the signature
algorithm and any package API from that package's own source/docs. When a value is in front of
you, read it; don't recall it.
Arabic-first — most merchants and shoppers are Arabic: default to Arabic copy,
illustrations, and RTL presentation for the embedded app, app_page_builder listing, app
details, and storefront. → salla-embedded-ui / salla-storefront-ui
App types
| Type | Delta |
|---|---|
| General | Needs sub_category_id; use type: "app" in salla_reference → salla-app-builder |
| Private | Same flow as General (type: "app" category tree, needs sub_category_id) → salla-app-builder |
| Shipping | Shipping sub-category; shipment.creating/shipment.cancelling are sync App Functions; Salla-set Company ID → salla-shipping-app |
| Communication | No sub-category; must declare channels before publish → salla-communication-app |
sub_category_id above is create-time only and type-scoped. The publish-time main_category_id
("App Theme"/"App Impact") is a separate, SHARED list — same for all four rows — set later via
app_publish (→ salla-publication-consistency).
Choosing the surface (the hookable rule)
Every behavior attaches at exactly one surface. Decide in this order:
- Runs in the shopper's browser / storefront? → snippet → salla-snippets
- An App Function trigger exists for the event? (check the trigger list first) → App Function (preferred — runs inside Salla, no server) → salla-app-functions
- Otherwise → webhook to your server (verify the signature on every delivery) → salla-webhooks
Route by intent
| Intent | Skill |
|---|---|
| Create / configure / publish an app end to end | salla-app-builder |
| OAuth, tokens, refresh, Easy vs Custom Mode, token storage & mutex | salla-app-auth |
| Register, verify, handle webhooks (transport) | salla-webhooks |
| Install / uninstall / trial / subscription events | salla-app-lifecycle |
| Serverless handlers on Salla triggers | salla-app-functions |
| Storefront JS / e-commerce events | salla-snippets |
| Iframe UI inside the merchant dashboard | salla-embedded-app |
App-Store listing page — built via app_page_builder; auto-fills from publication |
salla-app-ui-builder |
| Per-merchant settings schema & values | salla-app-settings |
| Plans, addons, trials, entitlement gating, usage balance, plan/subscription state & reconciliation | salla-app-billing |
| Post-install setup / onboarding steps | salla-app-builder |
| Addon billing lifecycle (activation, renewal, entitlement) | salla-addon-purchase |
| In-app addon purchase UX (embedded flow) | salla-addon-purchase-embedded |
| SMS / WhatsApp / email channel apps | salla-communication-app |
| Carriers, shipments, labels, tracking, returns | salla-shipping-app |
| Direct Admin (Merchant) API calls, pagination, errors, rate limits | salla-api-core |
| Native UI — storefront (store) | salla-storefront-ui |
| Native UI — embedded app (dashboard) | salla-embedded-ui |
| Test the app end-to-end on a demo store | salla-live-testing |
| Publish an app — validate + save a draft, partner reviews, then send_publish_request / Portal submit | salla-publication-consistency |
| Find the right doc / live API schema | salla-docs |
When merchants see a change (_reaches)
There are only two kinds of app-config change:
| Kind | What | Demo stores | Merchants' live stores |
|---|---|---|---|
| Needs approval | webhooks, events, scopes, settings form, snippets, embedded pages, onboarding steps, App Functions | now | only after a new publication is approved |
| Instant | redirect_urls, trusted_ips (salla_apps connect) |
now | now — every merchant, no approval |
A private app's webhooks are instant too; its other config needs a new private publication.
Rule: every config write in the table above (connect, salla_events, salla_scopes,
salla_settings, salla_snippets, salla_embedded_pages, salla_onboarding_steps,
salla_functions) returns _reaches; other writes (uploads, listing content via app_publish /
app_page_builder) don't — that's expected, not a failed check. Read _reaches.live_stores and tell
the partner when merchants will see the change: after_approval → follow _reaches.next_step (a new publish request,
or withdraw an in-review one that lacks the change); now → it's live; no_live_stores_yet → only
demo stores exist; unknown → say you couldn't check. Never call a change live for merchants when
live_stores is after_approval. _reaches.live_now lists instant fields of a mixed connect that
already hit every merchant — warn before changing them on a live app. demo_stores: after_deploy
(App Functions) means poll deploy_status before testing on a demo store.
Perform actions with the Salla Partners MCP
When the Salla Partners MCP server is connected, do the work with these tools instead
of hand-writing Portal clicks or HTTP calls. Each is one tool driven by an action:
| Capability | Tool · actions |
|---|---|
| Create / configure / publish apps | salla_apps · list get create update connect (OAuth+webhooks) set_status; public apps publish via app_publish (below), private apps via salla_private_apps (below) |
| Events / webhooks | salla_events · list subscribe |
| Storefront snippets | salla_snippets · list parameters create update delete |
| Embedded pages | salla_embedded_pages · list create update delete |
| Onboarding steps | salla_onboarding_steps · list create update delete sort |
| App settings & features | salla_settings · define_form set_validation_url list_features set_features |
| Twilight themes | salla_themes · reads list get github_config categories components component_get settings screenshots publishing preview_stores sample_stores; writes create update_details screenshot_set screenshot_delete component_create component_update component_delete settings_update publish publish_withdraw set_status preview_store_set preview_store_delete default_preview_store sample_store_set sample_store_delete — create needs a GitHub App installation; component and settings writes commit to the theme repo; see salla-theme-builder |
| Shipping zones & settings | salla_shipping · get_zones set_zones set_settings |
| App Functions | salla_functions · list_triggers / get / save (upsert) / delete — save is live on demo stores, publish for production; operator-gated — see salla-app-functions |
| File upload (logos) | salla_upload |
| Private apps | salla_private_apps · status (no app_id = account kind, before create) / publish (confirm:true after the partner confirms — a merchant partner's app usually goes live at once) / withdraw / store requests list_requests get_request create_request update_request delete_request — see salla-app-builder → private apps |
| OAuth scopes | salla_scopes · get / set — request only the minimum scopes the app needs; set reports restricted scopes it couldn't save under dropped |
| App-Store listing page | app_page_builder · listing-page blocks (catalog/init/list/show/set/add/remove/sort/reset); requires app_publish action=open first; images → salla_upload — see salla-app-ui-builder |
| Publish an app (stepwise) | Public: app_publish · open set readiness validate — validate saves a DRAFT; the partner reviews the /publish link, then either submits one-click there OR confirms and the agent calls send_publish_request (confirm:true). Private: salla_private_apps action=publish — no onboarding, no listing. See salla-publication-consistency |
| Lookups (categories/countries/cities) | salla_reference |
The routed skills drive these tools step by step — follow the skill, not the raw API.
Red Flags
| Tempting thought | Why it's wrong |
|---|---|
| "A theme is an app, so the app flow applies." (First, pick the product) | A Twilight theme is a GitHub repository of templates: no OAuth, no install webhooks, no App Settings. Planning auth mode or webhooks for it is wasted work — route to salla-theme-builder. |
"The theme is ready — publish it with app_publish." (First, pick the product) |
app_publish is the App Store listing flow for apps. A theme is published from the Partners Portal. |
| "The partner said 'App Theme', so this is theme work." (First, pick the product) | "App Theme" / "App Impact" is an app listing's category → salla-publication-consistency. A Twilight theme is a different product. |
Resources
| Topic | Link |
|---|---|
| Partners Portal | https://portal.salla.partners |
| Developer blog | https://salla.dev/blog/ |
| Developer community (Telegram) | https://t.me/salladev |