Properties
| Name | Type | Description |
|---|---|---|
| event_id | string | |
| type | string | The lifecycle change. - `initial_purchase`: the first period of a subscription started (including a free trial). - `renewal`: a new paid period started. - `product_change`: the subscription moved to a |
| app_user_id | string | |
| product_id | string | The identifier of a product of this custom store, exactly as created (bare, without the SDK's `custom|` prefix). A new purchase (`initial_purchase`, `non_renewing_purchase`) needs an active product; e |
| subscription_id | string | Your stable id for the subscription, constant across renewals (the original transaction). For a `non_renewing_purchase`, the purchase id. |
| transaction_id | string | Your id for this period's transaction or invoice. |
| custom_transaction_id | object | |
| environment | string | `sandbox` for test purchases. Sandbox events are stored and appear in revenue charts only when they are filtered to the Sandbox environment; they never set the store's `reporting_since`. |
| occurred_at | string | |
| purchased_at | string | |
| expires_at | object | End of the current period. Must not be before `purchased_at`. `null` means the period never ends, so it is accepted only where it grants no open-ended access: on a lifetime `non_renewing_purchase`, an |
| period_type | string | `trial` for a free trial, `intro` for an introductory price, otherwise `normal`. |
| price | object | |
| cancel_reason | object | |
| is_trial_conversion | object |
JSON Schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://artifacts.apis.io/superwall/json-schema/superwall-custom-store-event-schema.json",
"title": "CustomStoreEvent",
"x-generated": "2026-10-28",
"x-method": "derived",
"x-generator": "derive-json-schema.py",
"x-source": "openapi/superwall-openapi.json#/components/schemas/CustomStoreEvent",
"type": "object",
"properties": {
"event_id": {
"type": "string"
},
"type": {
"type": "string",
"enum": [
"initial_purchase",
"renewal",
"product_change",
"cancellation",
"uncancellation",
"billing_issue",
"expiration",
"refund",
"non_renewing_purchase"
],
"description": "The lifecycle change.\n\n- `initial_purchase`: the first period of a subscription started (including a free trial).\n- `renewal`: a new paid period started.\n- `product_change`: the subscription moved to another product; `product_id` is the new product. It carries no price: report any charge for the new product as a `renewal`.\n- `cancellation`: auto-renew was turned off. Access continues until `expires_at`.\n- `uncancellation`: auto-renew was turned back on before expiry.\n- `billing_issue`: a renewal payment failed and is being retried. Access continues until `expires_at`.\n- `expiration`: the subscription ended. Access stops.\n- `refund`: the current period was refunded in full. Access stops immediately and the subscription ends: cancel it in your billing system too, so the customer is not billed again. A refunded `subscription_id` is final: no later event restores its access, so a customer who subscribes again needs a new `subscription_id`. Partial refunds are not supported: do not report them.\n- `non_renewing_purchase`: a one-time purchase; send `expires_at: null` for lifetime access."
},
"app_user_id": {
"type": "string",
"minLength": 1,
"maxLength": 255
},
"product_id": {
"type": "string",
"minLength": 1,
"maxLength": 255,
"description": "The identifier of a product of this custom store, exactly as created (bare, without the SDK's `custom|` prefix). A new purchase (`initial_purchase`, `non_renewing_purchase`) needs an active product; every other event also accepts an archived one, so existing subscribers keep renewing, cancelling and expiring after you archive their product."
},
"subscription_id": {
"type": "string",
"minLength": 1,
"maxLength": 255,
"description": "Your stable id for the subscription, constant across renewals (the original transaction). For a `non_renewing_purchase`, the purchase id."
},
"transaction_id": {
"type": "string",
"minLength": 1,
"maxLength": 255,
"description": "Your id for this period's transaction or invoice."
},
"custom_transaction_id": {
"anyOf": [
{
"type": "string",
"minLength": 1,
"maxLength": 255
}
]
},
"environment": {
"type": "string",
"enum": [
"production",
"sandbox"
],
"description": "`sandbox` for test purchases. Sandbox events are stored and appear in revenue charts only when they are filtered to the Sandbox environment; they never set the store's `reporting_since`."
},
"occurred_at": {
"type": "string"
},
"purchased_at": {
"type": "string"
},
"expires_at": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "End of the current period. Must not be before `purchased_at`. `null` means the period never ends, so it is accepted only where it grants no open-ended access: on a lifetime `non_renewing_purchase`, and on `expiration` and `refund`, which end access regardless. Every other type rejects `null` with `expires_at_required`."
},
"period_type": {
"type": "string",
"enum": [
"normal",
"trial",
"intro"
],
"description": "`trial` for a free trial, `intro` for an introductory price, otherwise `normal`."
},
"price": {
"anyOf": [
{
"type": "object",
"properties": {
"amount": {
"type": "string"
},
"currency": {
"type": "string"
}
},
"required": [
"amount",
"currency"
],
"additionalProperties": false,
"description": "What the customer paid for this period. Required on revenue events (`initial_purchase`, `renewal`, `non_renewing_purchase`, `refund`) and rejected on the others. Send `0` for a free trial."
}
]
},
"cancel_reason": {
"anyOf": [
{
"type": "string",
"enum": [
"unsubscribe",
"billing_error",
"developer_initiated",
"price_increase",
"customer_support",
"unknown"
],
"description": "Why the subscription was cancelled or refunded. Only on `cancellation`, `expiration` and `refund`."
}
]
},
"is_trial_conversion": {
"anyOf": [
{
"type": "boolean",
"description": "`true` on the `renewal` that converts a free trial into a paid period."
}
]
}
},
"required": [
"event_id",
"type",
"app_user_id",
"product_id",
"subscription_id",
"transaction_id",
"environment",
"occurred_at",
"purchased_at",
"expires_at",
"period_type"
],
"additionalProperties": false
}
Work with this as data
Every JSON Schema here is available over the APIs.io API and to AI agents over MCP.
MCP server
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
Tools for schemas
4 MCP tools reach this
find_json_schemasBrowse and filter every JSON Schema in the catalog.apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.resolveTurn a domain, URL or GitHub org into the provider it belongs to.find_cohortsEvery scored population of providers in the catalog.
Call it yourself
curl for this page
This JSON Schema
curl "https://apis.io/api/v1/json-schemas/superwall-custom-store-event"
All schemas
curl "https://apis.io/api/v1/json-schemas?limit=25"
Discovery needs no key. Ratings and market analysis are Pro.
Get an API key
Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.
A second provider on the same verified email joins the account you already have.