# Subi developer reference > Subi is a Shopify subscriptions app. Its public REST API and webhooks are included in the Starter, Subi and Subi Plus plans. Guide: https://subi.co/developers Snapshot taken 2026-10-10 from the live files below. If a field here disagrees with the live file, the live file wins. # Public API Reference page: https://api.subi.co/public/v1.0/redoc/ OpenAPI file: https://api.subi.co/public/v1.0/schema/ Welcome to the **Subi Public API**. This API allows you to read subscribers and subscription contracts and run actions on a contract for your Shopify store. ## Authentication All API requests require authentication using an API key. Include your API key in the request header: ``` X-Api-Key: your_api_key_here ``` You can generate an API key from your Subi Admin Panel. ## Rate Limits To ensure fair usage and system stability, the API enforces rate limits: | Endpoint Type | Limit | |--------------|-------| | Standard endpoints | 60 requests/minute | When you exceed the rate limit, you'll receive a `429 Too Many Requests` response. ## Pagination List endpoints return paginated results using `limit` and `offset` parameters: | Parameter | Description | Default | Maximum | |-----------|-------------|---------|---------| | `limit` | Number of results to return | 15 | 100 | | `offset` | Starting position in the result set | 0 | - | **Example:** `https://api.subi.co/public/v1.0/subscribers/?limit=25&offset=50` Paginated responses include: ```json { "count": 150, "next": "https://api.subi.co/public/v1.0/subscribers/?limit=25&offset=75", "previous": "https://api.subi.co/public/v1.0/subscribers/?limit=25&offset=25", "results": [...] } ``` ## Response Format All responses are returned in JSON format. Successful responses include the requested data, while error responses include an `error` field with details. ## Need Help? - [Help Center](https://help.subi.co) - Detailed guides and tutorials - [Contact Support](mailto:support@subi.co) - Get help from our team ## GET /public/v1.0/subscribers/ Subscribers List Retrieve a paginated list of subscribers for your shop. - parameter `email` (query, string): - parameter `first_name` (query, string): - parameter `last_name` (query, string): - parameter `state` (query, string): - parameter `limit` (query, integer): Number of results to return. Default: 15, Max: 100 - parameter `offset` (query, integer): Starting position of the result set. - response 200: -> PaginatedCustomerList - response 401: Authentication failed -> object - response 403: Permission denied -> object - response 429: Rate limit exceeded -> object ## GET /public/v1.0/subscribers/{id}/ Get Subscriber Retrieve details of a specific subscriber by ID. - parameter `id` (path, integer, required): A unique value identifying this customer. - response 200: -> Customer - response 401: Authentication failed -> object - response 403: Permission denied -> object - response 429: Rate limit exceeded -> object - response 404: Object not found -> object ## GET /public/v1.0/subscription-contracts/ Subscription Contracts List Retrieve a paginated list of subscription contracts for your shop. - parameter `billing_policy_interval` (query, string): - parameter `billing_policy_interval__in` (query, array of string): Multiple values may be separated by commas. - parameter `created_at__gte` (query, string): - parameter `created_at__lte` (query, string): - parameter `currency_code` (query, string): - parameter `currency_code__in` (query, array of string): Multiple values may be separated by commas. - parameter `customer_id` (query, integer): - parameter `delivery_policy_interval` (query, string): - parameter `delivery_policy_interval__in` (query, array of string): Multiple values may be separated by commas. - parameter `last_payment_status` (query, string (FAILED, SUCCEEDED), nullable): * `FAILED` - FAILED * `SUCCEEDED` - SUCCEEDED - parameter `last_payment_status__in` (query, array of string): Multiple values may be separated by commas. - parameter `next_billing_date__gte` (query, string): - parameter `next_billing_date__lte` (query, string): - parameter `status` (query, string (ACTIVE, CANCELLED, DEACTIVATED, EXPIRED, FAILED, PAUSED), nullable): * `ACTIVE` - ACTIVE * `CANCELLED` - CANCELLED * `EXPIRED` - EXPIRED * `FAILED` - FAILED * `PAUSED` - PAUSED * `DEACTIVATED` - DEACTIVATED - parameter `status__in` (query, array of string): Multiple values may be separated by commas. - parameter `updated_at__gte` (query, string): - parameter `updated_at__lte` (query, string): - parameter `limit` (query, integer): Number of results to return. Default: 15, Max: 100 - parameter `offset` (query, integer): Starting position of the result set. - response 200: -> PaginatedSubscriptionContractRetrieveListExternalList - response 401: Authentication failed -> object - response 403: Permission denied -> object - response 429: Rate limit exceeded -> object ## GET /public/v1.0/subscription-contracts/{id}/ Get Subscription Contract Retrieve details of a specific subscription contract by ID. - parameter `id` (path, integer, required): A unique value identifying this subscription contract. - response 200: -> SubscriptionContractDetailWithSkipBlockedExternal - response 401: Authentication failed -> object - response 403: Permission denied -> object - response 429: Rate limit exceeded -> object - response 404: Object not found -> object ## POST /public/v1.0/subscription-contracts/{id}/cancel/ Cancel subscription contract - parameter `id` (path, integer, required): A unique value identifying this subscription contract. - response 200: No response body - response 401: Authentication failed -> object - response 403: Permission denied -> object - response 429: Rate limit exceeded -> object ## PATCH /public/v1.0/subscription-contracts/{id}/lines/ Edit subscription contract lines - parameter `id` (path, integer, required): A unique value identifying this subscription contract. - request body: PatchedPublicApiLineEdit - response 200: -> SubscriptionContractDetailExternal - response 401: Authentication failed -> object - response 403: Permission denied -> object - response 429: Rate limit exceeded -> object ## POST /public/v1.0/subscription-contracts/{id}/pause/ Pause subscription contract - parameter `id` (path, integer, required): A unique value identifying this subscription contract. - response 200: No response body - response 401: Authentication failed -> object - response 403: Permission denied -> object - response 429: Rate limit exceeded -> object ## POST /public/v1.0/subscription-contracts/{id}/reschedule/ Reschedule subscription contract - parameter `id` (path, integer, required): A unique value identifying this subscription contract. - request body: SubscriptionContractSetNextBillingDateExternal - response 200: -> SubscriptionContractSetNextBillingDateExternal - response 401: Authentication failed -> object - response 403: Permission denied -> object - response 429: Rate limit exceeded -> object ## POST /public/v1.0/subscription-contracts/{id}/resume/ Resume subscription contract - parameter `id` (path, integer, required): A unique value identifying this subscription contract. - response 200: No response body - response 401: Authentication failed -> object - response 403: Permission denied -> object - response 429: Rate limit exceeded -> object ## POST /public/v1.0/subscription-contracts/{id}/skip/ Skip subscription contract - parameter `id` (path, integer, required): A unique value identifying this subscription contract. - response 200: No response body - response 401: Authentication failed -> object - response 403: Permission denied -> object - response 429: Rate limit exceeded -> object ## Public API schemas ### AdjustmentValueExternal - `amount` (string): - `currency_code` (string): - `percentage` (number, nullable): ### AdvancedDiscount - `type` (string (percentage, fixed_amount, price)): * `percentage` - percentage * `fixed_amount` - fixed_amount * `price` - price - `fixed` (number): - `recurring` (number): - `after_cycle` (integer): ### Customer - `id` (integer): - `first_name` (string, nullable): - `last_name` (string, nullable): - `email` (string, nullable): - `state` (string (DECLINED, DISABLED, ENABLED, INVITED, None), nullable): * `DECLINED` - DECLINED * `DISABLED` - DISABLED * `ENABLED` - ENABLED * `INVITED` - INVITED - `locale` (string, nullable): ### CustomerPaymentMethodExternal - `id` (string): - `revoked_at` (string, nullable): - `revoked_reason` (string, nullable): ### CycleDiscountExternal - `adjustment_type` (string (FIXED_AMOUNT, PERCENTAGE, PRICE)): * `FIXED_AMOUNT` - FIXED_AMOUNT * `PERCENTAGE` - PERCENTAGE * `PRICE` - PRICE - `adjustment_value` (AdjustmentValueExternal): - `after_cycle` (integer, nullable): - `computed_price` (MoneyV2External): ### DeliveryOptionExternal - `code` (string, nullable): - `description` (string, nullable): - `presentment_title` (string, nullable): - `title` (string, nullable): ### DiscountExternal - `id` (integer): ### LineAdd - `product_variant_id` (integer): - `quantity` (integer): - `discount_percentage` (number): - `selling_plan_id` (integer, nullable): ### LineDiscountAllocationExternal - `amount` (MoneyV2External): - `discount` (LineDiscountExternal): ### LineDiscountExternal - `id` (string): ### LineToSwap - `id` (string): - `product_variant_id` (integer): ### LineUpdate - `quantity` (integer): - `discount_percentage` (number): - `advanced_discount` (AdvancedDiscount): - `id` (string): ### LocalDeliveryMethodExternal - `address` (SubscriptionMailingAddressExternal): - `local_delivery_option` (LocalDeliveryOptionExternal): - `__typename` (string): Delivery method type ### LocalDeliveryOptionExternal - `code` (string, nullable): - `description` (string, nullable): - `presentment_title` (string, nullable): - `title` (string, nullable): - `instructions` (string, nullable): - `phone` (string): ### MoneyV2External - `amount` (string): - `currency_code` (string): ### PaginatedCustomerList - `count` (integer): - `next` (string, nullable): - `previous` (string, nullable): - `results` (array of Customer): ### PaginatedSubscriptionContractRetrieveListExternalList - `count` (integer): - `next` (string, nullable): - `previous` (string, nullable): - `results` (array of SubscriptionContractRetrieveListExternal): ### PatchedPublicApiLineEdit - `lines_to_swap` (array of LineToSwap): - `lines_to_update` (array of LineUpdate): - `lines_to_add` (array of LineAdd): - `lines_to_remove` (array of string): ### PickupDeliveryMethodExternal - `pickup_option` (DeliveryOptionExternal): - `__typename` (string): Delivery method type ### PricingPolicyExternal - `base_price` (MoneyV2External): - `cycle_discounts` (array of CycleDiscountExternal): ### SellingPlanAnchorExternal - `cutoff_day` (integer, nullable): - `day` (integer): - `month` (integer, nullable): - `type` (string (MONTHDAY, WEEKDAY, YEARDAY)): * `MONTHDAY` - MONTHDAY * `WEEKDAY` - WEEKDAY * `YEARDAY` - YEARDAY ### ShippingDeliveryMethodExternal - `address` (SubscriptionMailingAddressExternal): - `shipping_option` (DeliveryOptionExternal): - `__typename` (string): Delivery method type ### SubscriptionBillingPolicyExternal - `anchors` (array of SellingPlanAnchorExternal): - `interval` (string (DAY, MONTH, WEEK, YEAR)): * `DAY` - DAY * `MONTH` - MONTH * `WEEK` - WEEK * `YEAR` - YEAR - `interval_count` (integer): - `min_cycles` (integer, nullable): - `max_cycles` (integer, nullable): ### SubscriptionContractDetailExternal - `id` (integer): - `created_at` (string, nullable): - `updated_at` (string, nullable): - `status` (string (ACTIVE, CANCELLED, EXPIRED, FAILED, PAUSED, DEACTIVATED, None), nullable): * `ACTIVE` - ACTIVE * `CANCELLED` - CANCELLED * `EXPIRED` - EXPIRED * `FAILED` - FAILED * `PAUSED` - PAUSED * `DEACTIVATED` - DEACTIVATED - `next_billing_date` (string, nullable): - `lines_count` (integer): - `last_payment_status` (string (FAILED, SUCCEEDED, None), nullable): * `FAILED` - FAILED * `SUCCEEDED` - SUCCEEDED - `customer_id` (integer, nullable): - `next_cycle_index` (integer): - `currency_code` (string, nullable): - `total_price` (number): - `delivery_price` (MoneyV2External): - `billing_policy` (SubscriptionBillingPolicyExternal): - `delivery_policy` (SubscriptionDeliveryPolicyExternal): - `delivery_method` (SubscriptionDeliveryMethodExternal): - `prepaid` (boolean): - `prepaid_count` (number): - `min_billing_cycles` (integer, nullable): - `max_billing_cycles` (integer, nullable): - `customer_payment_method` (CustomerPaymentMethodExternal): - `initial_price_amount` (number, nullable): - `note` (string, nullable): - `discounts` (array of DiscountExternal): - `lines` (array of SubscriptionLineExternal): ### SubscriptionContractDetailWithSkipBlockedExternal - `id` (integer): - `created_at` (string, nullable): - `updated_at` (string, nullable): - `status` (string (ACTIVE, CANCELLED, EXPIRED, FAILED, PAUSED, DEACTIVATED, None), nullable): * `ACTIVE` - ACTIVE * `CANCELLED` - CANCELLED * `EXPIRED` - EXPIRED * `FAILED` - FAILED * `PAUSED` - PAUSED * `DEACTIVATED` - DEACTIVATED - `next_billing_date` (string, nullable): - `lines_count` (integer): - `last_payment_status` (string (FAILED, SUCCEEDED, None), nullable): * `FAILED` - FAILED * `SUCCEEDED` - SUCCEEDED - `customer_id` (integer, nullable): - `next_cycle_index` (integer): - `currency_code` (string, nullable): - `total_price` (number): - `delivery_price` (MoneyV2External): - `billing_policy` (SubscriptionBillingPolicyExternal): - `delivery_policy` (SubscriptionDeliveryPolicyExternal): - `delivery_method` (SubscriptionDeliveryMethodExternal): - `prepaid` (boolean): - `prepaid_count` (number): - `min_billing_cycles` (integer, nullable): - `max_billing_cycles` (integer, nullable): - `customer_payment_method` (CustomerPaymentMethodExternal): - `initial_price_amount` (number, nullable): - `note` (string, nullable): - `discounts` (array of DiscountExternal): - `lines` (array of SubscriptionLineExternal): - `skip_blocked_by_limit` (boolean): ### SubscriptionContractRetrieveListExternal - `id` (integer): - `created_at` (string, nullable): - `updated_at` (string, nullable): - `status` (string (ACTIVE, CANCELLED, EXPIRED, FAILED, PAUSED, DEACTIVATED, None), nullable): * `ACTIVE` - ACTIVE * `CANCELLED` - CANCELLED * `EXPIRED` - EXPIRED * `FAILED` - FAILED * `PAUSED` - PAUSED * `DEACTIVATED` - DEACTIVATED - `next_billing_date` (string, nullable): - `lines_count` (integer): - `last_payment_status` (string (FAILED, SUCCEEDED, None), nullable): * `FAILED` - FAILED * `SUCCEEDED` - SUCCEEDED - `customer_id` (integer, nullable): - `next_cycle_index` (integer): - `currency_code` (string, nullable): - `total_price` (number): - `billing_policy_interval` (string (DAY, MONTH, WEEK, YEAR)): * `DAY` - DAY * `MONTH` - MONTH * `WEEK` - WEEK * `YEAR` - YEAR - `billing_policy_interval_count` (integer): - `delivery_policy_interval` (string (DAY, MONTH, WEEK, YEAR)): * `DAY` - DAY * `MONTH` - MONTH * `WEEK` - WEEK * `YEAR` - YEAR - `delivery_policy_interval_count` (integer): - `prepaid` (boolean): - `prepaid_count` (number): - `min_billing_cycles` (integer, nullable): - `max_billing_cycles` (integer, nullable): ### SubscriptionContractSetNextBillingDateExternal - `date` (string): ### SubscriptionDeliveryMethodExternal ### SubscriptionDeliveryPolicyExternal - `anchors` (array of SellingPlanAnchorExternal): - `interval` (string (DAY, MONTH, WEEK, YEAR)): * `DAY` - DAY * `MONTH` - MONTH * `WEEK` - WEEK * `YEAR` - YEAR - `interval_count` (integer): ### SubscriptionLineExternal - `id` (string): - `current_price` (MoneyV2External): - `line_discounted_price` (MoneyV2External): - `quantity` (integer): - `product_id` (integer, nullable): - `title` (string, nullable): - `variant_id` (integer, nullable): - `variant_title` (string, nullable): - `selling_plan_id` (integer, nullable): - `selling_plan_name` (string, nullable): - `variant_image_src` (string, nullable): - `pricing_policy` (PricingPolicyExternal): - `discount_allocations` (array of LineDiscountAllocationExternal): ### SubscriptionMailingAddressExternal - `address1` (string, nullable): - `address2` (string, nullable): - `city` (string, nullable): - `company` (string, nullable): - `country` (string, nullable): - `country_code` (string, nullable): - `first_name` (string, nullable): - `last_name` (string, nullable): - `name` (string, nullable): - `phone` (string, nullable): - `province` (string, nullable): - `province_code` (string, nullable): - `zip` (string, nullable): # Webhooks Reference page: https://api.subi.co/webhooks/v1.0/redoc/ OpenAPI file: https://api.subi.co/webhooks/v1.0/schema/ Welcome to the **Subi Webhooks Reference**. Webhooks let your application receive real-time HTTP notifications when subscription events occur in your store. Instead of polling the API for changes, you register a URL and Subi sends an HTTP `POST` request to that URL every time a relevant event happens. --- ## How It Works 1. **Register** a webhook endpoint for a topic through the Subi dashboard. 2. When the event occurs, Subi sends an HTTP `POST` request with a JSON payload to your URL. 3. Your server **verifies** the request using HMAC, processes the payload, and responds with a `2xx` status code. --- ## Webhook Headers Every webhook request includes the following headers. Header names are **case-insensitive**. | Header | Description | |--------|-------------| | `Content-Type` | Always `application/json`. The body is a UTF-8 encoded JSON string. | | `X-Subi-Topic` | The event topic that triggered this webhook (e.g. `SUBSCRIPTION_CREATED`). Use this to route the payload to the correct handler in your application. | | `X-Subi-Hmac-Sha256` | Base64-encoded HMAC-SHA256 signature of the raw request body. **Always verify this header** to confirm the request was sent by Subi and has not been tampered with. See [Verifying Webhooks](#section/Verifying-Webhooks-HMAC) below. | | `X-Subi-Event-Id` | A unique identifier for this event. You can use this for **idempotency**: if you receive the same Event ID twice, you can safely ignore the duplicate. | | `X-Subi-Webhook-Id` | A unique identifier for this specific delivery attempt. | | `X-Subi-Triggered-At` | ISO 8601 timestamp indicating when the event was triggered (e.g. `2025-06-15T14:30:00+00:00`). | --- ## Verifying Webhooks (HMAC) Every webhook is signed using your shop's **HMAC secret key** (available in the Subi dashboard under Webhook Settings). To verify a webhook is authentic and unmodified: 1. Read the **raw request body** as bytes (do not parse JSON first). 2. Compute the **HMAC-SHA256** hash of the body using your HMAC secret key. 3. **Base64-encode** the resulting hash. 4. **Compare** the result with the value in the `X-Subi-Hmac-Sha256` header using a timing-safe comparison. ### Python ```python import base64, hashlib, hmac def verify_webhook(raw_body: bytes, secret: str, header_signature: str) -> bool: computed = hmac.new(secret.encode("utf-8"), raw_body, hashlib.sha256).digest() expected = base64.b64encode(computed).decode("utf-8") return hmac.compare_digest(expected, header_signature) ``` ### Node.js ```javascript const crypto = require("crypto"); function verifyWebhook(rawBody, secret, headerSignature) { const computed = crypto .createHmac("sha256", secret) .update(rawBody, "utf8") .digest("base64"); return crypto.timingSafeEqual( Buffer.from(computed), Buffer.from(headerSignature) ); } ``` ### PHP ```php function verify_webhook(string $rawBody, string $secret, string $headerSignature): bool { $computed = base64_encode(hash_hmac("sha256", $rawBody, $secret, true)); return hash_equals($computed, $headerSignature); } ``` > **Important:** Always use a **timing-safe comparison** function (e.g. `hmac.compare_digest` in Python, `crypto.timingSafeEqual` in Node.js, `hash_equals` in PHP) to prevent timing attacks. --- ## Responding to Webhooks Your endpoint **must** respond with an HTTP `2xx` status code (e.g. `200 OK`) to acknowledge receipt. Any non-2xx response is treated as a delivery failure. **Best practices:** - Respond **quickly** (within a few seconds). If processing takes time, accept the webhook first and process asynchronously. - Use the `X-Subi-Event-Id` header for **idempotency**: store processed event IDs and skip duplicates. --- ## Available Topics Each topic below describes the event that triggers it and the JSON payload your endpoint will receive. ## Webhook topic SUBSCRIPTION_CREATED Subscription Created Triggered when a new subscription contract is created. The payload contains the full subscription contract object including customer, lines, billing policy, and delivery details. - payload: SubscriptionContractWebhookPayload ## Webhook topic SUBSCRIPTION_CANCELED Subscription Canceled Triggered when a subscription contract is canceled. The payload contains the subscription contract object with its status set to `CANCELLED`, a `cancellation` object carrying why the customer canceled, and a `winback_url` link that restarts this subscription. `cancellation.reasons` is always present and is never null. It holds one entry per reason the customer selected, and is an **empty list** when no reason was selected (a merchant- or API-initiated cancellation, a shop that does not capture reasons, or a customer who submitted none). `cancellation.custom_reason` is the free text the customer typed, and is **null** when they typed none. - payload: SubscriptionCanceledWebhookPayload ## Webhook topic SUBSCRIPTION_PAUSED Subscription Paused Triggered when a subscription contract is paused. The payload contains the subscription contract object with its status set to `PAUSED`. - payload: SubscriptionContractWebhookPayload ## Webhook topic SUBSCRIPTION_RESUMED Subscription Resumed Triggered when a paused subscription contract is resumed. The payload contains the subscription contract object with its status set to `ACTIVE`. - payload: SubscriptionContractWebhookPayload ## Webhook topic SUBSCRIPTION_BILLING_SUCCEEDED Billing Succeeded Triggered when a billing attempt completes successfully. The payload contains the billing attempt object with its associated subscription contract details and the Shopify order ID. - payload: BillingAttemptWebhookPayload ## Webhook topic SUBSCRIPTION_BILLING_FAILED Billing Failed Triggered when a billing attempt fails. The payload contains the billing attempt object with its error code, error message, and the associated subscription contract. - payload: BillingAttemptWebhookPayload ## Webhooks schemas ### AdjustmentValueExternal - `amount` (string): - `currency_code` (string): - `percentage` (number, nullable): ### BillingAttemptExternal - `id` (integer): - `created_at` (string): - `status` (string): - `error_code` (string (CUSTOMER_INVALID, CUSTOMER_NOT_FOUND, FREE_GIFT_CARD_NOT_ALLOWED, INVALID_BILLING_ADDRESS, MERCHANT_ACCOUNT_ERROR, NON_TEST_ORDER_LIMIT_REACHED, PAYMENT_METHOD_INCOMPATIBLE_WITH_GATEWAY_CONFIG, PAYMENT_METHOD_NOT_FOUND, PAYMENT_METHOD_NOT_SPECIFIED, PAYMENT_PROVIDER_IS_NOT_ENABLED, INSUFFICIENT_INVENTORY, INVENTORY_ALLOCATIONS_NOT_FOUND, AMOUNT_TOO_LARGE, AMOUNT_TOO_SMALL, AUTHENTICATION_ERROR, AUTHENTICATION_FAILED, AUTHENTICATION_REQUIRED, BUYER_CANCELED_PAYMENT_METHOD, CALL_ISSUER, CANCELLED_PAYMENT, CARD_DECLINED, CARD_NUMBER_INCORRECT, CONFIRMATION_REJECTED, DO_NOT_HONOR, EXPIRED_BUYER_ACTION, EXPIRED_CARD, EXPIRED_PAYMENT_METHOD, FRAUD_SUSPECTED, GENERIC_ERROR, INCORRECT_ADDRESS, INCORRECT_NUMBER, INCORRECT_ZIP, INSUFFICIENT_FUNDS, INVALID_CURRENCY, INVALID_CUSTOMER_BILLING_AGREEMENT, INVALID_EXPIRY_DATE, INVALID_NUMBER, INVALID_PAYMENT_METHOD, INVALID_PURCHASE_TYPE, INVALID_SHIPPING_ADDRESS, INVOICE_ALREADY_PAID, MERCHANT_RULE, OFF_SESSION_REJECTED, PAYMENT_METHOD_DECLINED, PAYMENT_METHOD_UNSUPPORTED, PAYMENT_PROVIDER_ERROR, PAYPAL_ERROR_GENERAL, PROCESSING_ERROR, PURCHASE_TYPE_NOT_SUPPORTED, RETRY_DECLINED, TEST_MODE, TRANSACTION_LIMIT_EXCEEDED, TRANSIENT_ERROR, UNEXPECTED_ERROR, None), nullable): * `CUSTOMER_INVALID` - CUSTOMER_INVALID * `CUSTOMER_NOT_FOUND` - CUSTOMER_NOT_FOUND * `FREE_GIFT_CARD_NOT_ALLOWED` - FREE_GIFT_CARD_NOT_ALLOWED * `INVALID_BILLING_ADDRESS` - INVALID_BILLING_ADDRESS * `MERCHANT_ACCOUNT_ERROR` - MERCHANT_ACCOUNT_ERROR * `NON_TEST_ORDER_LIMIT_REACHED` - NON_TEST_ORDER_LIMIT_REACHED * `PAYMENT_METHOD_INCOMPATIBLE_WITH_GATEWAY_CONFIG` - PAYMENT_METHOD_INCOMPATIBLE_WITH_GATEWAY_CONFIG * `PAYMENT_METHOD_NOT_FOUND` - PAYMENT_METHOD_NOT_FOUND * `PAYMENT_METHOD_NOT_SPECIFIED` - PAYMENT_METHOD_NOT_SPECIFIED * `PAYMENT_PROVIDER_IS_NOT_ENABLED` - PAYMENT_PROVIDER_IS_NOT_ENABLED * `INSUFFICIENT_INVENTORY` - INSUFFICIENT_INVENTORY * `INVENTORY_ALLOCATIONS_NOT_FOUND` - INVENTORY_ALLOCATIONS_NOT_FOUND * `AMOUNT_TOO_LARGE` - AMOUNT_TOO_LARGE * `AMOUNT_TOO_SMALL` - AMOUNT_TOO_SMALL * `AUTHENTICATION_ERROR` - AUTHENTICATION_ERROR * `AUTHENTICATION_FAILED` - AUTHENTICATION_FAILED * `AUTHENTICATION_REQUIRED` - AUTHENTICATION_REQUIRED * `BUYER_CANCELED_PAYMENT_METHOD` - BUYER_CANCELED_PAYMENT_METHOD * `CALL_ISSUER` - CALL_ISSUER * `CANCELLED_PAYMENT` - CANCELLED_PAYMENT * `CARD_DECLINED` - CARD_DECLINED * `CARD_NUMBER_INCORRECT` - CARD_NUMBER_INCORRECT * `CONFIRMATION_REJECTED` - CONFIRMATION_REJECTED * `DO_NOT_HONOR` - DO_NOT_HONOR * `EXPIRED_BUYER_ACTION` - EXPIRED_BUYER_ACTION * `EXPIRED_CARD` - EXPIRED_CARD * `EXPIRED_PAYMENT_METHOD` - EXPIRED_PAYMENT_METHOD * `FRAUD_SUSPECTED` - FRAUD_SUSPECTED * `GENERIC_ERROR` - GENERIC_ERROR * `INCORRECT_ADDRESS` - INCORRECT_ADDRESS * `INCORRECT_NUMBER` - INCORRECT_NUMBER * `INCORRECT_ZIP` - INCORRECT_ZIP * `INSUFFICIENT_FUNDS` - INSUFFICIENT_FUNDS * `INVALID_CURRENCY` - INVALID_CURRENCY * `INVALID_CUSTOMER_BILLING_AGREEMENT` - INVALID_CUSTOMER_BILLING_AGREEMENT * `INVALID_EXPIRY_DATE` - INVALID_EXPIRY_DATE * `INVALID_NUMBER` - INVALID_NUMBER * `INVALID_PAYMENT_METHOD` - INVALID_PAYMENT_METHOD * `INVALID_PURCHASE_TYPE` - INVALID_PURCHASE_TYPE * `INVALID_SHIPPING_ADDRESS` - INVALID_SHIPPING_ADDRESS * `INVOICE_ALREADY_PAID` - INVOICE_ALREADY_PAID * `MERCHANT_RULE` - MERCHANT_RULE * `OFF_SESSION_REJECTED` - OFF_SESSION_REJECTED * `PAYMENT_METHOD_DECLINED` - PAYMENT_METHOD_DECLINED * `PAYMENT_METHOD_UNSUPPORTED` - PAYMENT_METHOD_UNSUPPORTED * `PAYMENT_PROVIDER_ERROR` - PAYMENT_PROVIDER_ERROR * `PAYPAL_ERROR_GENERAL` - PAYPAL_ERROR_GENERAL * `PROCESSING_ERROR` - PROCESSING_ERROR * `PURCHASE_TYPE_NOT_SUPPORTED` - PURCHASE_TYPE_NOT_SUPPORTED * `RETRY_DECLINED` - RETRY_DECLINED * `TEST_MODE` - TEST_MODE * `TRANSACTION_LIMIT_EXCEEDED` - TRANSACTION_LIMIT_EXCEEDED * `TRANSIENT_ERROR` - TRANSIENT_ERROR * `UNEXPECTED_ERROR` - UNEXPECTED_ERROR - `error_message` (string, nullable): - `order_id` (integer, nullable): - `subscription_contract` (SubscriptionContractDetailExternal): ### BillingAttemptWebhookPayload - `billing_attempt` (BillingAttemptExternal): ### CancellationReasonSchema - `title` (string): The reason label exactly as the customer was shown it. ### CancellationSchema - `reasons` (array of CancellationReasonSchema): Every reason the customer selected. Always present and never null: an empty list means no reason was selected, which is the case for merchant- and API-initiated cancellations, for shops that do not capture reasons, and when the customer submitted none. A cancellation flow contributes exactly one entry; a cancellation reason list can contribute several. - `custom_reason` (string, nullable): The free text the customer typed, or null when they typed none. Always present. Never an empty string. ### CustomerPaymentMethodExternal - `id` (string): - `revoked_at` (string, nullable): - `revoked_reason` (string, nullable): ### CycleDiscountExternal - `adjustment_type` (string (FIXED_AMOUNT, PERCENTAGE, PRICE)): * `FIXED_AMOUNT` - FIXED_AMOUNT * `PERCENTAGE` - PERCENTAGE * `PRICE` - PRICE - `adjustment_value` (AdjustmentValueExternal): - `after_cycle` (integer, nullable): - `computed_price` (MoneyV2External): ### DeliveryOptionExternal - `code` (string, nullable): - `description` (string, nullable): - `presentment_title` (string, nullable): - `title` (string, nullable): ### DiscountExternal - `id` (integer): ### LineDiscountAllocationExternal - `amount` (MoneyV2External): - `discount` (LineDiscountExternal): ### LineDiscountExternal - `id` (string): ### LocalDeliveryMethodExternal - `address` (SubscriptionMailingAddressExternal): - `local_delivery_option` (LocalDeliveryOptionExternal): - `__typename` (string): Delivery method type ### LocalDeliveryOptionExternal - `code` (string, nullable): - `description` (string, nullable): - `presentment_title` (string, nullable): - `title` (string, nullable): - `instructions` (string, nullable): - `phone` (string): ### MoneyV2External - `amount` (string): - `currency_code` (string): ### PickupDeliveryMethodExternal - `pickup_option` (DeliveryOptionExternal): - `__typename` (string): Delivery method type ### PricingPolicyExternal - `base_price` (MoneyV2External): - `cycle_discounts` (array of CycleDiscountExternal): ### SellingPlanAnchorExternal - `cutoff_day` (integer, nullable): - `day` (integer): - `month` (integer, nullable): - `type` (string (MONTHDAY, WEEKDAY, YEARDAY)): * `MONTHDAY` - MONTHDAY * `WEEKDAY` - WEEKDAY * `YEARDAY` - YEARDAY ### ShippingDeliveryMethodExternal - `address` (SubscriptionMailingAddressExternal): - `shipping_option` (DeliveryOptionExternal): - `__typename` (string): Delivery method type ### SubscriptionBillingPolicyExternal - `anchors` (array of SellingPlanAnchorExternal): - `interval` (string (DAY, MONTH, WEEK, YEAR)): * `DAY` - DAY * `MONTH` - MONTH * `WEEK` - WEEK * `YEAR` - YEAR - `interval_count` (integer): - `min_cycles` (integer, nullable): - `max_cycles` (integer, nullable): ### SubscriptionCanceledWebhookPayload - `subscription_contract` (SubscriptionContractDetailExternal): - `cancellation` (CancellationSchema): - `winback_url` (string, nullable): A link that reactivates this subscription at its current price, with no offer attached. Always present; null only in the rare case the link could not be issued, which is logged on our side. One link is issued per cancellation and stays valid for 30 days; cancelling the same subscription again issues a new one. The link needs no login, so treat it as a secret: anyone holding it can restart the subscription and its recurring charges. Use it in your own win-back emails, and add your own discount in your own flow if you want one. ### SubscriptionContractDetailExternal - `id` (integer): - `created_at` (string, nullable): - `updated_at` (string, nullable): - `status` (string (ACTIVE, CANCELLED, EXPIRED, FAILED, PAUSED, DEACTIVATED, None), nullable): * `ACTIVE` - ACTIVE * `CANCELLED` - CANCELLED * `EXPIRED` - EXPIRED * `FAILED` - FAILED * `PAUSED` - PAUSED * `DEACTIVATED` - DEACTIVATED - `next_billing_date` (string, nullable): - `lines_count` (integer): - `last_payment_status` (string (FAILED, SUCCEEDED, None), nullable): * `FAILED` - FAILED * `SUCCEEDED` - SUCCEEDED - `customer_id` (integer, nullable): - `next_cycle_index` (integer): - `currency_code` (string, nullable): - `total_price` (number): - `delivery_price` (MoneyV2External): - `billing_policy` (SubscriptionBillingPolicyExternal): - `delivery_policy` (SubscriptionDeliveryPolicyExternal): - `delivery_method` (SubscriptionDeliveryMethodExternal): - `prepaid` (boolean): - `prepaid_count` (number): - `min_billing_cycles` (integer, nullable): - `max_billing_cycles` (integer, nullable): - `customer_payment_method` (CustomerPaymentMethodExternal): - `initial_price_amount` (number, nullable): - `note` (string, nullable): - `discounts` (array of DiscountExternal): - `lines` (array of SubscriptionLineExternal): ### SubscriptionContractWebhookPayload - `subscription_contract` (SubscriptionContractDetailExternal): ### SubscriptionDeliveryMethodExternal ### SubscriptionDeliveryPolicyExternal - `anchors` (array of SellingPlanAnchorExternal): - `interval` (string (DAY, MONTH, WEEK, YEAR)): * `DAY` - DAY * `MONTH` - MONTH * `WEEK` - WEEK * `YEAR` - YEAR - `interval_count` (integer): ### SubscriptionLineExternal - `id` (string): - `current_price` (MoneyV2External): - `line_discounted_price` (MoneyV2External): - `quantity` (integer): - `product_id` (integer, nullable): - `title` (string, nullable): - `variant_id` (integer, nullable): - `variant_title` (string, nullable): - `selling_plan_id` (integer, nullable): - `selling_plan_name` (string, nullable): - `variant_image_src` (string, nullable): - `pricing_policy` (PricingPolicyExternal): - `discount_allocations` (array of LineDiscountAllocationExternal): ### SubscriptionMailingAddressExternal - `address1` (string, nullable): - `address2` (string, nullable): - `city` (string, nullable): - `company` (string, nullable): - `country` (string, nullable): - `country_code` (string, nullable): - `first_name` (string, nullable): - `last_name` (string, nullable): - `name` (string, nullable): - `phone` (string, nullable): - `province` (string, nullable): - `province_code` (string, nullable): - `zip` (string, nullable):