Zid Docs
Apps
ThemesPayments
Apps
ThemesPayments
Help Center
Slack
  1. Plans & billing
  • πŸ—‚οΈ Overview
  • πŸš€ Start Here
  • Create your First App
  • Responses
  • Rate Limiting
  • Embedded Apps
  • StoreFront Events
  • Zid MUI
  • Zid SDKs
  • Our custom MCP server
  • Zid AI Agent Skill
  • Authorization
    • Authorization
    • Public Apps OAuth Requirements
    • OAuth Errors & Troubleshooting
    • Zid Bridge Tool
  • Merchant APIs
    • Account
      • Me
        • Me
      • Store
        • Store
        • Branding
        • Localization
        • Social
        • Operations
        • Business
        • Upload Logo Image
        • Delete Logo Image
        • Upload Icon Image
        • Delete Icon Image
        • Upload Cover Image
        • Delete Cover Image
    • Orders
      • Order Tags
        • List Order Tags
        • Create Order Tag
      • Validate Order Request
      • Create Order
      • Change Order Status
      • Add Order Comment
      • View Order
      • List Orders
      • List Custom Order Statuses
      • List Order Credit Notes
      • Get Orders Highlights
      • Order Fulfillment Inventories
      • Bulk Create/Update Custom Order Statuses
    • Reverse Orders
      • Create Reverse Orders
      • Create Reverse Orders Waybill
      • Add Reverse Order Reasons
      • List Reverse Reasons
      • Calculate Reverse Totals
      • Create refund for reverse order
      • Upload bank transfer receipt
      • Update return products
      • Order Details – View for Return
    • Abandoned Carts
      • List Carts
      • View Cart
      • Validate Abandoned Cart Messages
      • Send Abandoned Cart Notification Manually
    • Products
      • Managing Products
        • Create Product Types
        • Create Product
        • List Products
        • View Product
        • List Product Settings
        • Update Product
        • Bulk Update Products
        • Delete Product
      • Digital Vouchers
        • List Vouchers
        • Order Vouchers
        • Create Voucher
        • Import Vouchers
        • Export Vouchers
        • Update Voucher
        • Remove Voucher
      • Product Categories
        • List Categories
        • View Category
        • Create Category
        • Create Subcategory
        • Update Category
        • Assign Product to Category
        • Bulk Assign Products to Category
        • Publish Category
        • Detach Category from All Products
        • Remove Product from Category
        • Set Categories Nesting
        • Delete Category Cover Image
        • Upload Category Cover Image
        • Delete Category
        • Delete Category Image
        • Upload Category Image
        • Update Category
      • Product Brands
        • List Brands
        • Single Brand
      • Product Badge
        • List Badges
      • Product Attributes
        • List Attributes
        • View Attribute
        • Create Attribute
        • Update Attribute
        • Delete Attribute
      • Product Attribute Presets
        • List Presets
        • Create Preset
        • Update Preset
        • Delete Preset
      • Product Variants
        • Create Variants
        • Create Custom Option
        • Update Custom Option
        • Delete Custom Option Field
        • Create Custom Input Field
        • Update Custom Input Field
        • Delete Custom Input Field
      • Product Sorting
        • Set Manual Product Order
        • Reset Manual Product Order
      • Product Images
        • List Images
        • Upload Image
        • Update Image Order
        • Delete Image
      • Product Availability Notifications
        • Notification Stats
        • Noticiation Settings
        • List Notifications
        • Create Notification
        • Update Settings
        • Send Notification Email
        • Export Notifications
      • Product Export
        • Email All Products to Store Owner
        • Import Products via CSV or xlsx File
      • Product Stock
        • Retrieve Product Stock
        • List Product Stock Records
        • Create Product Stock
        • Update Product Stock
        • Bulk Update Product Stock Records
      • Product Questions & Answers
        • Retrieve Product Question
        • Retrieve Product Answer
        • List Product Questions
        • List Answers for Question
        • Create Product Question
        • Create Product Answer
        • Update Product Question
        • Update Product Answer
        • Delete Product Question
        • Delete Product Answer
        • List Store Product Questions
      • Product Reviews
        • List Reviews
        • Count Reviews
      • Digital Products
        • Create Downloadable Product
        • Generate Upload URL
        • Upload File to S3
        • Create Product Downloadable
        • Get Product Downloadables
        • Delete Product Downloadable
        • List Store Downloadables
        • Create Store Downloadable
        • Delete Store Downloadable
    • Inventories
      • Create Location
      • Update Location
      • Update Product Stock for Location
      • List Locations
      • View Location
    • Shipping
      • List Store Shipping Methods
    • Marketing
      • Coupons
        • List Coupons
        • View Coupon
        • Create Coupon
        • Generate Bulk Coupons
        • Duplicate Coupon
        • Duplicate Bulk Coupons
        • Update Coupon Note
        • Update Coupon
        • Update Bulk Coupons
        • Update Coupon Status
        • Update Bulk Coupons Status
        • Delete Coupon
        • Delete Bulk Coupons
      • Bundle Offers
        • List Bundle Offers
        • View Bundle Offer
        • Create Bundle Offer
        • Update Bundle Offer
        • Delete Bundle Offer
        • Bulk Delete Bundle Offers
      • Loyalty Program
        • Loyalty Program Status
        • Loyalty Program Details
        • Loyalty Program Info
        • Customer Loyalty Summary
        • Customer Points History
        • Activate Loyalty Program
        • Set Points Expiration Rules
        • Update Cashback Rule
        • Create Points Redemption Method
        • Update Points Redemption Method
        • Delete Points Redemption Method
        • Adjust Customer Points
        • Update Redemption Method Status
        • Loyalty Program Analytics
        • Loyalty Program Settings
      • Customer Wallets
        • Cashback Rules
          • List Cashback Rules
          • Create Cashback Rule
          • Retrieve Cashback Rule
          • Update Cashback Rule
          • Delete Cashback Rule
        • Wallet Analytics
          • Get Wallet Analytics
          • Get Wallet Analytics by Rule
        • Manager Customer Wallet
          • List Customer Wallets
          • Bulk Credit Customer Wallets
          • Bulk Debit Customer Wallets
          • Export Customer Wallets
          • Get Customer Wallet Balance
          • Credit Customer Wallet
          • Debit Customer Wallet
          • Customer Pending Cashbacks
          • Customer Wallet Transactions
    • Customers
      • Customer Tags
        • List Customer Tags
        • Add Customer Tag
        • Ω’Update Customer Tag
        • Delete Customer Tag
      • Customer Portal Tickets
        • List Customer Portal Tickets
        • Customer Portal Ticket Detail
      • List Customers
      • View Customer
      • Primary Customer List
      • FInd Customer By Phone Number
      • Customer Profile
      • Add Customer
      • Update Customer
      • Delete Customer
      • Add Bulk Customers
      • Import Customers
    • Store Settings
      • πŸ“„ User Roles and Permissions
      • Retrieve Store Manager Profile
      • Retrieve VAT Settings
      • List Payment Methods
      • List Store Operating Countries
      • OneSignal Store Settings
      • Create or Update OneSignal Store Settings
      • Get Payment Options
    • Countries and Cities
      • List Countries
      • List Cities for Country
    • Blogs
      • Settings
        • Create
        • List
      • Categories
        • Create
        • List
        • Bulk Activate
        • Bulk Deactivate
        • Bulk Delete
        • Retrieve
        • Destroy
        • Partial Update
        • Bulk Add To Posts
        • Bulk Remove From Posts
        • Bulk Delete Blog Categories
      • Posts
        • Media
          • List
          • Create
          • Destroy
        • Create
        • List
        • Retrieve
        • Partial Update
        • Destroy
        • Archive
        • Publish
        • Bulk Archive
        • Bulk Publish
        • Bulk Delete
        • Export Posts
        • Import Template
        • Import Posts
      • Tags
        • Create
        • List
        • Retrieve
        • Partial Update
        • Destroy
        • Bulk Delete Tags
        • Bulk Add To Posts
        • Bulk Remove From Posts
      • Storefront
        • Posts
          • List
          • Retrieve
        • Categories
          • List
          • Retrieve
        • Tags
          • List
  • Webhooks
    • Overview
    • Webhook Health Tracking
    • Events
      • Order
      • Product
      • Abandoned Cart
      • Customer
      • Product Category
    • APIs
      • Health Summary
      • Broken Webhooks
      • Recover Broken Webhooks
      • List Webhooks
      • Create Webhook
      • Delete Webhook
      • Delete Webhook By subscriber
  • App Management
    • Events
    • APIs
      • Subscription Details
      • Update Usage-Based Charges
  • Build an app
    • Justifying your scopes
    • Plans & billing
      • Plans and pricing
      • Creating a plan
      • Usage-based plans
      • Private plans
      • Subscription and app events
  1. Plans & billing

Subscription and app events

Zid sends your app an event whenever something changes about a merchant's installation or subscription β€” authorization, installation, activation, renewal, expiry, uninstallation. Use these to keep your own records in sync: activating features, blocking access, or updating a merchant's status on your side.
This page applies to OAuth apps published in Zid App Market.
Shipping apps receive a different set of events β€” installation, order and product events, but no subscription events. Private apps are not sold through the market and have no subscriptions.

Two ways to track a subscription#

There are two ways to know what a merchant's subscription looks like, and most apps need both.
Events (push). Zid sends a request to your endpoint the moment something changes. You subscribe once per app, and it covers every merchant who installs you.
The Subscription Details endpoint (pull). You call GET /v1/market/app/subscription with a merchant's token and get their current subscription back. You decide when to ask. Full details are in Reference: the Subscription Details endpoint below.
EventsSubscription Details endpoint
Tells youThat something changed, as it happensWhat is true right now
SetupSubscribe to each event in the Partner DashboardRequest the Subscription.read scope
CoversAll your merchants, through one endpointOne merchant per call
Charge detailsNot included in the usage-based payloadsFull charge records β€” id, amount, status, overdue date, and pending and settled totals
Depends onYour endpoint being reachable when Zid callsYou remembering to call it
After a merchant uninstallsYou still receive the uninstall eventStops working β€” see below

Why you need events, not just the endpoint#

You cannot detect an uninstall by polling. When a merchant uninstalls your app, Zid deletes their X-Manager-Token and revokes your OAuth access and refresh tokens for that store. Your next call fails β€” and a failed call looks the same as a network problem or an expired token. The app.market.application.uninstall event is the only reliable way to learn that it happened, and it is the signal that tells you to stop serving that merchant.
Polling does not scale. The endpoint returns one merchant at a time. With a few hundred merchants, checking everyone regularly means a few hundred requests each time, against your rate limit.
Polling misses the moment. The endpoint tells you the state today, not that it changed overnight. If you need to act when a subscription activates or expires β€” unlocking features, sending a welcome message, cutting off access β€” you would have to poll frequently and compare against your own copy to spot the change.

Why you need the endpoint, not just events#

It is the source of truth. A delivery can fail if your endpoint is down. Before you grant or remove access, confirm the current state with the endpoint rather than trusting your last received event.
Usage-based charge details only live there. The usage-based payment events carry no charge id and no paid amount, so the endpoint is where you read the amount, status and overdue date of each charge.

A good pattern#

Subscribe to the events you care about, and treat each one as a prompt to call the endpoint and refresh your own record. At minimum, subscribe to uninstall and expired β€” those are how you learn to stop serving a merchant.

Subscribing to events#

Events are not sent automatically. You subscribe to each one in the Partner Dashboard.
App Events.png
1.
Go to the Webhooks section when creating or editing your app.
2.
Provide the endpoint where notifications should be sent.
3.
Choose one or more events from the list.
4.
Add any headers you need for authentication.
5.
Save and submit. You can come back later to edit or add more events.
If you don't subscribe to an event, your app receives nothing when it happens β€” there is no error and no retry. Subscribing to one event does not subscribe you to the rest.

Testing with a development store#

1.
Use one of your development stores to simulate real events.
2.
Perform the action in the store that triggers the event you subscribed to.
3.
Check your app's webhook logs in the Partner Dashboard for successful deliveries or errors.

Event reference#

Installation and app events#

EventWhen it fires
app.market.application.authorizedThe merchant grants your app its permissions, before installing
app.market.application.installThe merchant installs your app
app.market.application.uninstallThe merchant removes your app
app.market.application.ratedThe merchant leaves a rating or review
app.market.private.plan.requestThe merchant requests a private plan

Subscription events#

EventWhen it fires
app.market.subscription.activeA subscription becomes active after payment
app.market.subscription.warningSee the timing table below
app.market.subscription.suspended1 day after a recurring subscription ends
app.market.subscription.expiredSee the timing table below
app.market.subscription.renewAfter a renewal or extension completes. Also fires on free-plan renewal, when a paused subscription resumes, and when a usage-based charge is paid
app.market.subscription.upgradeThe merchant moves to a different plan
app.market.subscription.refundedA payment is refunded to the merchant
app.market.subscription.usage_based.payment_successA usage-based charge is paid
app.market.subscription.usage_based.payment_failureA usage-based charge payment fails
renew does not warn you before a renewal. It always fires after the fact. No event is sent before a subscription renews or expires β€” use warning for advance notice.

Timings depend on the plan type#

warning and expired are used for both recurring and usage-based plans, but they mean different things and arrive at different times.
EventRecurring plansUsage-based plans
warning3 days before the subscription ends30 days after a charge is left unpaid
suspended1 day after the subscription endsNot used
expired5 days after the subscription ends30 days after the charge became overdue
Check plan_type in the payload if you need to tell them apart.

Payload: the 12 standard events#

All five installation and app events, plus active, warning, suspended, expired, renew, upgrade and refunded, share one payload shape.
{
  "app_id": 1292,
  "store_id": 507530,
  "store_uuid": "d78468cd-4b44-4fee-a00d-76561f35787c",
  "store_url": "https://wyatt.com.sa/",
  "plan_name": "Ψ§Ω„Ω†Ω…Ωˆ",
  "plan_id": 904,
  "plan_type": "Paid",
  "status": "active",
  "start_date": "2025-02-21T08:05:29.000000Z",
  "end_date": "2025-03-22T08:05:29.000000Z",
  "amount_paid": 79.01,
  "old_plan_name": null,
  "merchant_email": "info@ehmp.com.sa",
  "merchant_phone_no": "966554349999",
  "event_name": "app.market.subscription.active",
  "payment_date": "2025-02-21T08:05:29.000000Z"
}
FieldNotes
app_idYour app's ID
store_idInternal numeric store ID
store_uuidUse this to identify the store, not store_id
store_urlThe merchant's storefront URL
plan_nameThe plan the merchant is on. null if they have no subscription
plan_idThe plan's ID
plan_typeOne of Paid, Free, Free Trial, Usage Based, Free (Without Plan). See Identifying free trials
statusThe subscription's status. Not a reliable way to tell events apart β€” use event_name. See below
start_dateWhen the subscription started
end_dateWhen it ends. Always null for usage-based plans, which have no end date
amount_paidAmount paid, including VAT. 0 on many events β€” see below
old_plan_nameThe previous plan's name. Only set on active, renew and upgrade; null otherwise
merchant_emailThe merchant's email
merchant_phone_noThe merchant's phone number
event_nameThe event. Use this to identify what happened
payment_dateFor a usage-based charge, when the charge was paid. Otherwise the subscription start date

What differs between events#

The shape is the same, but not every event carries every value. Two differences catch people out:
Eventsamount_paidstatus
active, renew, upgrade, refundedThe actual amount paid, including VATThe subscription's status
warning, suspended, expiredAlways 0warning, suspend, expire
authorized, install, uninstall, rated, private.plan.requestAlways 0The merchant's current subscription status, not the event name
So do not read amount_paid from an install or authorized event β€” it is always zero. Read it from active, renew or upgrade.

About the status field#

status reports the subscription's status at the moment the event was built. Its possible values are:
inactive, active, warning, suspend, frozen, expire, renew, upgrade, cancel, refund
Note that several are shortened β€” suspend not "suspended", expire not "expired", cancel not "cancelled", refund not "refunded".
When the merchant has no subscription at all, status falls back to the last part of the event name (for example authorized for app.market.application.authorized). Because of this, status is not a dependable event discriminator. Always branch on event_name.

Identifying free trials#

To tell whether a merchant is on a free trial, check plan_type:
{
  "app_id": 6528,
  "store_id": 3104452,
  "store_uuid": "b2052c72-ddaa-411f-a428-748dcd885a6e",
  "store_url": "https://xle6e8.zid.store/",
  "plan_name": "Test Plan With Trial",
  "plan_id": 3329,
  "plan_type": "Free Trial",
  "status": "active",
  "start_date": "2026-06-14T08:05:40.000000Z",
  "end_date": "2026-07-04T08:05:40.000000Z",
  "amount_paid": 0,
  "old_plan_name": null,
  "merchant_email": "bv3e7xxnx5@zam-partner.email",
  "merchant_phone_no": "+201101050117",
  "event_name": "app.market.subscription.active",
  "payment_date": "2026-06-14T08:05:40.000000Z"
}
plan_type is "Free Trial" here, so this subscription includes a trial.
plan_type tells you the subscription has a trial, not that the trial is still running.
A subscription keeps the "Free Trial" value for as long as that subscription record exists, including after the trial converts to paid. The payload does not include the trial end date.
The Subscription Details endpoint does not help here either β€” it returns no plan_type and no trial dates. To know whether a trial is still running, work it out yourself: you set the trial length on the plan, so add it to start_date.

Payload: the two usage-based payment events#

usage_based.payment_success and usage_based.payment_failure use a different shape. None of the fields above apply.
{
  "action": "usage_based_subscription_payment_success",
  "envelope": {
    "store_id": 12345,
    "app": {
      "app_id": 67,
      "app_name": "My App"
    },
    "subscription": {
      "plan": "Professional",
      "plan_price": 99.00
    }
  }
}
The failure event is identical except for action:
{
  "action": "usage_based_subscription_payment_failure",
  "envelope": {
    "store_id": 12345,
    "app": {
      "app_id": 67,
      "app_name": "My App"
    },
    "subscription": {
      "plan": "Professional",
      "plan_price": 99.00
    }
  }
}
FieldTypeDescription
actionstringEither usage_based_subscription_payment_success or usage_based_subscription_payment_failure
envelope.store_idintegerThe store where the charge was attempted
envelope.app.app_idintegerYour app's ID
envelope.app.app_namestringYour app's name
envelope.subscription.planstringThe plan's name
envelope.subscription.plan_pricenumberThe plan's price
Two limitations to design around:
There is no charge ID and no paid amount. plan_price is the plan's own price, not the amount the merchant just paid.
There is no store_uuid β€” only the numeric store_id.
Both events are delivered asynchronously, after the payment attempt resolves.

Handling a paid usage-based charge#

When a merchant pays a usage-based charge, your app receives two events:
1.
app.market.subscription.usage_based.payment_success β€” tells you a payment succeeded
2.
app.market.subscription.renew β€” carries the amount in amount_paid and the date in payment_date
If you need the amount, read it from the renew event, or call the Subscription Details endpoint.
When a payment fails, only usage_based.payment_failure is sent, and it does not tell you which charge failed or for how much. Call Subscription Details to find out.

Reference: the Subscription Details endpoint#

The companion to these events. Use it to confirm a merchant's current subscription, and to read usage-based charge details that the events don't carry.
GET https://api.zid.sa/v1/market/app/subscription
Required scope: Subscription.read

Headers#

HeaderValue
AuthorizationBearer {your partner token}
X-Manager-TokenThe merchant's token from OAuth
Acceptapplication/json
Accept-Languagear or en. Defaults to en. Controls the language of plan_name

Parameters#

None. Your app is identified from your token, and the merchant from their X-Manager-Token. You do not send an app id.

Response#

This example is a merchant on a usage-based plan:
{
  "status": "object",
  "subscription": {
    "app_id": 2376,
    "store_id": 26520,
    "store_url": "https://example.zid.store/",
    "plan_name": "Pay as you go",
    "subscription_status": "active",
    "start_date": "2025-02-04T15:55:07.000000Z",
    "end_date": null,
    "merchant_phone_no": "+9665XXXXXXX",
    "merchant_email": "merchant@example.com",
    "is_usage_based": 1,
    "pending_charges": 345.00,
    "settled_charges": 1200.00,
    "charges": [
      {
        "id": "9eaac8b0-3530-4bdb-b2fb-34b4efe22179",
        "subscription_id": 333,
        "amount": 345.00,
        "amount_details": {
          "amount": 34500,
          "currency": "SAR",
          "formatted": "Ψ±.Ψ³β€Ž 345.00"
        },
        "status": "pending",
        "overdue_at": null,
        "created_at": "2025-04-13T16:58:06.000000Z"
      }
    ]
  },
  "message": {
    "type": "object",
    "code": null,
    "name": null,
    "description": "Store subscription details of the provided token"
  }
}
FieldNotes
app_idYour app's ID
store_idThe merchant's store ID
store_urlThe merchant's storefront URL
plan_nameThe plan's name, in the language from Accept-Language
subscription_statusOne of inactive, active, warning, suspend, frozen, expire, renew, upgrade, cancel, refund
start_dateWhen the subscription started
end_dateWhen it ends. Always null for usage-based plans
merchant_phone_noThe merchant's phone number
merchant_emailThe merchant's email
is_usage_based1 for a usage-based plan, 0 otherwise

Usage-based plans only#

These three fields appear only when is_usage_based is 1. On a recurring or free plan they are not in the response at all.
FieldNotes
pending_chargesThe unpaid charge's amount, in SAR. 0.0 if there is none
settled_chargesTotal settled so far, in SAR
chargesThe charge records, newest first
Each entry in charges:
FieldNotes
idThe charge's ID. This is the id the events do not give you
subscription_idThe subscription the charge belongs to
amountThe amount in SAR β€” for example 345.00
amount_details.amountThe same amount in halalas β€” for example 34500
amount_details.currencyCurrency code
amount_details.formattedThe amount formatted for display
statusOne of pending, paid, overdue, defaulted
overdue_atWhen the charge became overdue, or null
created_atWhen you created the charge
Two fields named amount, two different units. amount is in SAR; amount_details.amount is in halalas. Don't mix them up.
amount_details is empty when the amount is zero.

Things to know#

It returns the merchant's most recent subscription, which may not be active. Check subscription_status before treating it as current.
subscription comes back empty if the merchant has not activated a plan. You get "subscription": [] β€” an empty value, not an object with empty fields. Installing your app is not enough on its own: a merchant activates a free plan, starts a trial, or pays for a plan, and only then does a subscription exist. An app with no plans at all will always return empty here.
It returns less than the events do. This response has no plan_id, no plan_type and no store_uuid. If you key merchants on store_uuid from events, you cannot match that against this response β€” use store_id as well, or store both.
It stops working once the merchant uninstalls. Their token is revoked, so this is not a way to detect an uninstall β€” see Two ways to track a subscription.

Errors#

StatusMeaning
401Credentials missing, invalid or expired
500Server error
For the full specification, see Subscription Details.

Recommended practice#

Branch on event_name, not status. status is ambiguous across events and uses shortened values.
Treat events as a signal, not your source of truth. Confirm the current state with the Subscription Details endpoint before granting or removing access.
Handle repeats. The same event can arrive more than once. Make your handler safe to run twice with the same payload.
Respond quickly. Return a success response first, then do your processing.
Subscribe to uninstall and expired. These are how you learn to stop serving a merchant. Without them your app keeps working for merchants who no longer have access.

Checking deliveries#

Zid records every delivery attempt for your app's events. Review them in the Partner Dashboard under your app's webhook logs, where you can also send a test delivery.
The webhook health endpoints documented under Webhooks β€” health summary, broken webhooks, recover broken webhooks β€” apply to store data webhooks such as orders, products and customers. They do not cover the app events on this page.

App events are not store webhooks#

These are two separate systems. Don't mix them up:
App events (this page)Store data webhooks
What they tell youYour app was installed, a subscription changedA merchant's order, product or customer changed
Event namesapp.market.*order.*, product.*, customer.*, category.*
How you subscribeOnce per app, in the Partner DashboardPer store, with the Create Webhook API
Scope neededNone β€” it's dashboard configurationthird_webhook_write
See Webhooks for store data webhooks.
Modified atΒ 2026-10-21 14:33:50
Previous
Private plans
Built with