subscription.created
An agency started a new platform subscription
Category: Billing
Emitted when: After AgencySubscription is inserted in app/api/v1/subscriptions/agency.py subscribe route, OR after Square subscription.created webhook commits our internal subscription record
Envelope
Every delivery wraps the event-specific data block in the canonical
envelope documented on the
webhook overview page. The body carries SIX keys;
the HMAC signature is delivered as the X-Webhook-Signature request
header on the inbound POST to your endpoint (NOT as a body field;
including it in the body would make the HMAC a function of its own
output).
| Field | Type | Description |
|---|---|---|
event_id | string | ULID; globally unique. Safe to persist as the dedup key. |
event_type | string | Always subscription.created for this event. |
api_version | string | Payload schema version (YYYY-MM-DD). |
timestamp | integer | Unix epoch seconds at dispatch time. |
nonce | string | ULID; unique per delivery, used for replay rejection. |
data | object | Event-specific payload (see below). |
Delivery also sets three HTTP headers on the inbound POST:
| Header | Meaning |
|---|---|
X-Webhook-Event-Id | Mirrors event_id; cheaper than parsing the body to dedup. |
X-Webhook-Timestamp | Mirrors timestamp for replay-window checks. |
X-Webhook-Signature | sha256=<hex> HMAC over timestamp.body. |
Data schema
| Field | Type | Required | Description |
|---|---|---|---|
agency_id | string | yes | Agency Id |
subscription_id | string | yes | Internal subscription id (string of AgencySubscription._id for dashboard creates; Square id when Square-provisioned). |
plan_id | string | yes | Internal plan/tier identifier, e.g. 'plan_pro_monthly' |
status | "active" | "trialing" | yes | Status |
started_at | string | yes | Started At |
ends_at | string | null | no | End of the current billing window. None means 'indefinite' - subscription renews until cancelled. |
price | object | yes | Pricing tuple for a subscription plan. Locked as a nested sub-object on both subscription.created and subscription.cancelled payloads. Receivers can share a single decoder for the two event shapes. Fields ------ amount: int Price in INTEGER CENTS. Never float. Matches Square v44's money.amount contract. currency: str ISO-4217 code, validated as ^[A-Z]{3}$. interval: Literal["month", "year"] Billing interval. Only monthly and yearly are supported on the platform; a weekly / quarterly subscription would be a new event type, not a shape drift here. |
Sample payload
The sample below is a live fixture. Feed the exact body bytes shown
plus the timestamp into the HMAC-SHA256 recipe from the
webhook overview using the
documented test-vector secret (test_secret_001 )
and you will recover the signature header value printed below.
Body (delivered as the HTTP request body):
{
"event_id": "evt_2P6WHC9CGSA7GV0F07EZ715850",
"event_type": "subscription.created",
"api_version": "2026-04-17",
"timestamp": 1745339401,
"nonce": "136CYWVQ9R3HF3Q5AERWG4XFT4",
"data": {
"agency_id": "user_01HXAGENCY0000000000000",
"subscription_id": "sub_01HXSUB0000000000000000",
"plan_id": "01HX5Y7Z2M3N4P5Q6R7S8T9U0V",
"status": "active",
"started_at": "2026-05-29T12:00:00Z",
"ends_at": "2026-05-29T12:00:00Z",
"price": {
"amount": 0,
"currency": "USD",
"interval": "month"
}
}
}
Signature header (delivered as X-Webhook-Signature on the same request):
sha256=70d4a5f835c9139ba6a9bf6ad08afd5b4316fa172094245bc452cd6718eeb427
Retry behaviour
Failed deliveries retry on the sequence 2, 4, 8, 16, 32 seconds
(five attempts plus the initial call for a total of six over
approximately 62 seconds of wall clock). After the final attempt the
delivery lands in the dead-letter queue and the dashboard operator can
replay it from Settings > API Keys > Webhook Endpoint > Deliveries.
See the webhook overview for the full
rules.
Verification
Every receiver MUST verify the X-Webhook-Signature header using the
recipe in the webhook overview.
Rejecting deliveries whose timestamp is more than 5 minutes off your
wall clock (after NTP correction on your side) or whose nonce has
already been consumed in the last 10 minutes is part of the contract.