App Configuration¶
What you configure when you create/submit an app in the Partner Panel, and how your hosted service integrates with the platform.
Core fields¶
| Field | Required | Notes |
|---|---|---|
| Name | yes | Display name in the App Store. |
| Slug | auto | Derived from the name; the app's stable identity. Resubmitting the same slug is a version update. |
| Version | yes | Semver, e.g. 1.0.0. |
| Category | no | For App Store filtering. |
| Description | no | Short summary. |
| Price / Currency | no | 0 = free. Currency defaults to BDT. |
Hosting & integration URLs¶
All URLs must be https and must resolve to a public host (localhost / private IPs are rejected at submit time — an anti-SSRF measure).
| Field | Purpose |
|---|---|
| App URL | Base URL of your hosted app. Required. |
| Redirect URL | This is the URL the dashboard embeds in the iframe, with code, api and shop_id appended. Set it, even though the form marks it optional — without it your app cannot be opened. |
| Webhooks URL | Where the platform delivers event webhooks. |
Permissions (scopes)¶
Request only what you need. Requested scopes are validated against this allowlist (unknown scopes are rejected):
read_orders write_orders
read_products write_products
read_customers write_customers
read_inventory write_inventory
read_analytics read_shop
manage_webhooks
Events¶
Subscribe to platform events (delivered to your Webhooks URL). Validated against this allowlist:
order.created order.paid order.fulfilled order.cancelled
product.created product.updated
customer.created
app.installed app.uninstalled
OAuth credentials¶
Issued automatically when your app is approved. Your client_id is always
visible on the app-detail page; the client_secret is shown once on
approval — copy it then. Only a hash is stored server-side, so if you lose it you
must rotate.
Webhooks¶
Deliveries are queued and retried with exponential backoff. Each request is signed so you can verify authenticity.
- Header:
X-Webhook-Signature: t=<unix>,v1=<hex> - The signed string is
<t>.<rawBody>, HMAC-SHA256 keyed by your endpoint secret. Recompute and constant-time compare. (This mirrors the Stripe scheme.) - Also sent:
X-Webhook-Event,X-Webhook-Delivery. - Reject requests whose timestamp is outside a small tolerance window (replay protection).
import { createHmac, timingSafeEqual } from 'crypto';
function verify(rawBody, header, secret) {
const [tPart, v1Part] = header.split(',');
const t = tPart.split('=')[1];
const sig = v1Part.split('=')[1];
const expected = createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex');
return timingSafeEqual(Buffer.from(sig), Buffer.from(expected));
}
ui_slots (phase-2)¶
You may declare ui_slots (e.g. storefront.product.below_price,
dashboard.nav.section) — they are validated and stored as metadata, but slot
rendering is not built yet.