NUMU Docs
Contact
APIThemesPartner Apps
APIThemesPartner Apps
  1. Partner Apps
  • 🧩 Partner apps
  • Join the partner program
  • Register your app
  • App manifest
  • OAuth and app tokens
  • App webhooks
  • Review and publishing
  • The numu CLI
  • Build with an AI assistant
  • Troubleshooting apps
  1. Partner Apps

App manifest

One file describes your app: numu.app.json. Every version you upload is a copy of it. NUMU checks it with the same rules everywhere: in numu app validate, in the portal, and at upload.

A complete example#

{
  "manifest_version": 1,
  "slug": "shipping-sync",
  "version": "1.0.0",
  "type": ["connected"],
  "name": { "ar": "مزامنة الشحن", "en": "Shipping Sync" },
  "tagline": {
    "ar": "ابعت طلباتك لشركة الشحن بضغطة واحدة",
    "en": "Send orders to your courier in one click"
  },
  "description": {
    "ar": "كل طلب جديد بيوصل لشركة الشحن لوحده، من غير ما تكتب العنوان تاني. وتقدر تتابع كل شحنة من مكان واحد.",
    "en": "Every new order goes to your courier on its own, with no retyping. Track every shipment in one place."
  },
  "icon": "https://cdn.example.com/shipping-sync/icon-512.png",
  "screenshots": [
    {
      "src": "https://cdn.example.com/shipping-sync/shipments.png",
      "caption": { "ar": "كل الشحنات قدامك في صفحة واحدة", "en": "Every shipment on one page" }
    }
  ],
  "category": "shipping",
  "developer": {
    "support_email": "support@example.com",
    "support_url": "https://example.com/help",
    "privacy_policy_url": "https://example.com/privacy",
    "terms_url": "https://example.com/terms"
  },
  "app_url": "https://app.example.com/numu",
  "oauth": {
    "redirect_urls": ["https://app.example.com/numu/callback"],
    "scopes": ["orders:read", "orders:write"],
    "optional_scopes": ["catalog:read"]
  },
  "webhooks": [
    { "event": "order.paid", "url": "https://app.example.com/numu/webhooks" },
    { "event": "order.status_changed", "url": "https://app.example.com/numu/webhooks" },
    { "event": "app.uninstalled", "url": "https://app.example.com/numu/webhooks" },
    { "event": "store.redact", "url": "https://app.example.com/numu/webhooks" }
  ],
  "settings_schema": [
    {
      "id": "auto_send",
      "type": "checkbox",
      "default": true,
      "locales": {
        "ar": { "label": "ابعت الطلبات أوتوماتيك" },
        "en": { "label": "Send orders automatically" }
      }
    }
  ],
  "pricing": { "model": "free" },
  "languages": ["ar", "en"]
}

Fields#

FieldRequiredRules
manifest_versionYesAlways 1
slugYes3 to 41 lowercase letters, digits and dashes, starting with a letter: ^[a-z][a-z0-9-]{2,40}$. It must match the app you registered, and it never changes
versionYesMAJOR.MINOR.PATCH. Every upload must be higher than the one before
typeYes["connected"]: the app runs on your server
name, tagline, descriptionYes{ "ar": "…", "en": "…" }. A tagline is at most 80 characters and a description at most 4,000, in each language
iconYesPublic https:// URL of the icon
screenshotsNoUp to 8. Each is { "src": "https://…", "caption": { "ar": "…", "en": "…" } }
categoryYesshipping, marketing, sales, customer_support, inventory, analytics, payments, store_design, productivity or other
developer.support_emailYesWhere merchants reach you
developer.privacy_policy_urlFor personal dataSee Scopes
developer.support_url, developer.terms_urlNohttps:// URLs
app_urlYesYour app's own page. Open app in the dashboard links here. Give it no query string: see Open app
oauth.redirect_urlsYes1 to 10 URLs. The App Store's Install button uses the first one
oauth.scopesYesWhat the app needs to work. At least one
oauth.optional_scopesNoScopes you may ask for later, with the merchant's approval
webhooksYes{ "event": "…", "url": "https://…" } items. app.uninstalled is required
settings_schemaNoA settings form for the merchant, up to 60 fields. See Settings form
pricingYesSee Pricing
languagesNo["ar", "en"], the default
Unknown fields are refused, so a typo fails loudly instead of being ignored.

Arabic first#

Every text field has an Arabic and an English value, and they must differ: a copy of the English in the ar field is refused. Write the Arabic in Egyptian colloquial, the way merchants here talk: "ابعت طلباتك لشركة الشحن", not "يرجى إرسال الطلبات".

URLs#

Every URL must be https:// on a public host. That covers icon, screenshots, app_url, redirect and webhook URLs, and the developer links. localhost, .local hosts and private or loopback IP addresses are refused. At submit, NUMU also resolves each host and refuses one that points into a private network.
Develop against a tunnel such as ngrok or Cloudflare Tunnel.

Scopes#

Apps use the same scope strings as the rest of the API, <domain>:read and <domain>:write:
ScopeReaches
catalogProducts, variants, inventory, categories, bundles, gift cards
mediaFile uploads and stored assets
ordersOrders, shipments, returns, refunds, abandoned checkouts
customersCustomer records and addresses
analyticsMetrics, reports, dashboard figures
marketingCoupons, promotions, campaigns
messagesCustomer conversations: the inbox, messages, channels and WhatsApp
themes:readThemes, pages, menus. Read only
risk:readRisk assessments. Read only
:write does not imply :read. Ask for both when you need both.
Never available to apps: settings:read, settings:write, themes:write and risk:write. An app cannot reach store settings, locations, shipping settings, payments, invoices, billing or the store's other apps. A manifest that asks for these scopes is refused, and a request that needs one answers 403.
Privacy policy: developer.privacy_policy_url is required for any :write scope, and for customers:read, orders:read, risk:read and messages:read.
Ask for the fewest scopes that work. Reviewers check that you use every scope. Adding a scope later makes every merchant approve again.

Webhooks#

List each event you want, with the URL it goes to:
EventNeeds
app.uninstalledNothing. Required in every manifest
store.redactNothing
order.created, order.paid, order.status_changedorders:read
product.created, product.updated, product.deletedcatalog:read
An event needs its read scope in scopes or optional_scopes. A store sends you the event only if the merchant granted that scope. Details: App webhooks.

Settings form#

settings_schema is a form the dashboard shows the merchant on your app's page, in Arabic and English:
"settings_schema": [
  {
    "id": "default_courier",
    "type": "select",
    "default": "bosta",
    "locales": {
      "ar": { "label": "شركة الشحن الأساسية" },
      "en": { "label": "Default courier" }
    },
    "options": [
      { "value": "bosta", "label": "Bosta", "locales": { "ar": { "label": "بوسطة" } } },
      { "value": "mylerz", "label": "Mylerz", "locales": { "ar": { "label": "مايلرز" } } }
    ]
  }
]
Types: text, textarea, number, range, color, checkbox, select, radio and url, plus header and paragraph for headings and notes.
Labels: every field needs locales.ar.label and locales.en.label. header and paragraph need locales.ar.content and locales.en.content instead, and have no id.
Ids: lowercase letters, digits and _, starting with a letter, unique in the form.
Options: select and radio need options.
Your server cannot read these values yet
NUMU saves what the merchant enters, but no API returns it to an app token today. For any setting your server needs, use your own settings page behind Open app.

Pricing#

pricing.modelMeans
freeNo charge
externalYou bill the merchant yourself. pricing.label is required: what the merchant pays, in both languages, for example { "ar": "من ٢٠٠ ج.م في الشهر", "en": "From EGP 200 / month" }
recurringNUMU bills the merchant every month or year. Not open yet: a manifest with it is refused until NUMU announces it

Changing the manifest later#

Every change is a new version: raise version, upload, submit.
Reviewers look hardest at new scopes, then at changed URLs, then at a changed price. A change to the listing text alone is the lightest review.
A version that adds scopes makes every merchant approve them. Until a merchant does, your token for that store keeps the scopes it had. See Ask for more scopes.
Modified at 2026-09-24 14:17:29
Previous
Register your app
Next
OAuth and app tokens
Built with