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/embed URL of your hosted app (opened in the dashboard iframe). Required.
Redirect URL Where the platform redirects after install/auth.
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.