Maxio (Chargify) Licensing Integration
In short: Maxio, formerly Chargify, signs its form-encoded webhooks with HMAC-SHA256. Your receiver creates a license on signup_success and another on each renewal_success, and deactivates it when the subscription is canceled.
Maxio Advanced Billing is the product formerly known as Chargify (the old developer site developers.chargify.com redirects to developers.maxio.com). It sends an HTTP POST for subscription, billing and payment events.
What Maxio sends
Maxio sends the body as application/x-www-form-urlencoded with the keys id, event and payload[...], for example payload[subscription][product][name]. The documented payload examples contain the subscription (subscription.id) with its nested customer (customer.id, customer.email) and product (product.id, product.handle, product.name). The header X-Chargify-Webhook-Id identifies the delivery. You can set up to 5 endpoints per site by default.
Map Maxio events to NetLicensing
| Maxio event | What to do in NetLicensing |
|---|---|
customer_create | Create a licensee |
signup_success | Create a license from the plan’s template |
renewal_success | Create an additional license for the next period |
payment_success | Payment succeeded. signup_success and renewal_success already cover the periods, so do not add a license here as well |
subscription_product_change, upgrade_downgrade_success | Create a license from the new template and deactivate the old one |
pending_cancellation_change | Fires when cancellation at the end of the period is set or cleared: deactivate at period end, or reactivate if cleared |
subscription_state_change | General state change: read the new state, for example past_due or canceled |
payment_failure, renewal_failure, dunning_step_reached | Your choice: keep access during the platform’s retry period, or deactivate |
Maxio documents no named event for an immediate cancellation; use subscription_state_change. We found no event named subscription_created; signup_success is the documented event for “any successful signup, where a subscription is created”.
Check that the request comes from Maxio
Maxio signs each request. The header X-Chargify-Webhook-Signature-Hmac-Sha-256 holds the hex HMAC-SHA-256 of the raw request body, keyed with the site’s Shared Key (Edit Current Site). The older MD5 header X-Chargify-Webhook-Signature is deprecated: validate only the HMAC-SHA-256 signature. Maxio accepts HTTP endpoints only while the site is in test mode; switch to HTTPS before going live.
Retries and duplicates
Answer with 200. Any other response, or no timely response, triggers retries: up to 6 attempts in total, roughly after 10 s, 15 s, 90 s, 180 s and 15 minutes. After failures 1 to 25 an endpoint stays enabled; after 26 to 50 it is paused and you can resend from the Webhooks panel; from 51 it is disabled. Delivery is asynchronous and events can arrive out of order.
Match the customer and the plan
Customer id and email, and the product id and handle, are in the payload: map product.handle or product.id to your licenseTemplateNumber. Maxio custom fields exist for subscriptions and customers (up to 100 per record type), but they are not part of an ordinary webhook payload; their changes arrive in a separate custom_field_value_change event.
Whatever ids you pick, use them as the NetLicensing numbers so later events can address the licensee and license directly and retries cannot create duplicates; see Use the platform’s IDs as NetLicensing numbers.
Example: the calls
Maxio Your receiver NetLicensing
| | |
| renewal_success --------->| |
| | verify signature |
| | POST /licensee ------------>|
| | number=customer id |
| | POST /license ------------->|
| | number=sub-period |
|< 2xx ---------------------| |
| | |
The values below are illustrative; field names follow the vendor documentation listed under Sources. Form-encoded bodies are shown decoded for readability. Code samples are Python, using only the standard library unless noted.
1. Maxio calls your receiver
POST /webhooks/maxio HTTP/1.1
Content-Type: application/x-www-form-urlencoded
X-Chargify-Webhook-Id: 123456
X-Chargify-Webhook-Signature-Hmac-Sha-256: <hex HMAC-SHA256>
id=123456&event=renewal_success&payload[subscription][id]=987&payload[subscription][customer][id]=55&payload[subscription][customer][email]=jane%40example.com&payload[subscription][product][handle]=pro-monthly
2. Your receiver checks the request
import hashlib, hmac
def verify_maxio(raw_body: bytes, signature_header: str, secret: str) -> bool:
# signature_header = request.headers["X-Chargify-Webhook-Signature-Hmac-Sha-256"]
expected = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature_header)
Verify the raw request body exactly as received, before any JSON or form parsing. The key is the site’s Shared Key. Ignore the deprecated MD5 header.
3. Your receiver calls NetLicensing
NLIC=https://go.netlicensing.io/core/v2/rest
AUTH="apiKey:$NETLICENSING_API_KEY" # API key with ROLE_APIKEY_OPERATION
# customer_create: the Maxio customer id becomes the licensee number
curl --user $AUTH --header "Accept: application/json" \
--data "productNumber=PQVJQ5F7H&number=maxio-55&name=Jane%20Doe" \
$NLIC/licensee
# signup_success and renewal_success: one license per period: <subscription id>-<period you track>
curl --user $AUTH --header "Accept: application/json" \
--data "number=maxio-987-2026-11&licenseeNumber=maxio-55&licenseTemplateNumber=EUJK1BXQ52" \
$NLIC/license
# Cancellation that ends access now
curl --user $AUTH --header "Accept: application/json" \
--data "active=false" \
$NLIC/license/maxio-987-2026-11
PQVJQ5F7H and EUJK1BXQ52 stand for your product and license template numbers. A create with a number that already exists returns HTTP 400 with DuplicateEntityException. That makes both calls safe to repeat: send the licensee create with every paid event and continue when it reports a duplicate, and treat a duplicate license as “already done” and answer the platform with 2xx (see IDs as numbers).
Sources
- Maxio: configure and test webhooks
- Maxio: review webhook events
- Maxio: webhook payload examples
- Maxio: custom fields FAQ
You run this integration yourself; NetLicensing does not host a Maxio connector. The Maxio details on this page are based on the sources above, and the NetLicensing calls it relies on were tested against the live API. Vendors change their APIs, so verify the details against the linked pages before you go live. Back to Billing and Commerce Platforms.