Create a webhook endpoint
POST /webhooks| Scope | webhooks:manage |
| Customer session token | Not accepted: call from your server with an API key |
| Rate limit class | write (limits) |
| Idempotency key | Required (idempotency) |
| MCP tool | charm_create_webhook |
Subscribes a URL to loyalty events. The response includes the endpoint’s signing secret exactly once; every delivery carries an X-Charm-Hmac-Sha256 header (base64 HMAC-SHA256 of the raw body, keyed with that secret) to verify against. Deliveries are at-least-once — dedupe on the event id — and a 2xx within 5 seconds acknowledges; anything else is retried with backoff for about a day, after which the delivery is dropped. An endpoint that keeps failing is disabled automatically.
Request body
Section titled “Request body”| Field | Type | Description |
|---|---|---|
url | string | Public https URL that receives the POSTed events. |
topics | array of string: points.earned, points.adjusted, reward.redeemed, tier.changed, tier.approaching, store_credit.issued, referral.completed | Event topics to subscribe to. |
Response 201
Section titled “Response 201”Returns WebhookEndpointCreated.
| Field | Type | Description |
|---|---|---|
id | string | |
url | string | |
topics | array of string | |
status | string | |
created_at | string or null | (nullable) |
consecutive_failures | number | |
last_success_at | string or null | (nullable) |
last_failure_at | string or null | (nullable) |
disabled_reason | string or null | (nullable) |
api_version | string | The dated API version this endpoint’s deliveries are rendered in (Charm-Version). |
secret | string | The signing secret, shown exactly once. |
{ "id": "id", "url": "https://example.com/charm-hook", "topics": [ "topics" ], "status": "active", "created_at": "2026-10-01T09:30:00.000Z", "consecutive_failures": 1, "last_success_at": "2026-10-01T09:30:00.000Z", "last_failure_at": "2026-10-01T09:30:00.000Z", "disabled_reason": null, "api_version": "api version", "secret": "whsec_3f9…"}Example
Section titled “Example”curl -X POST "https://charm.appfleece.app/api/v1/webhooks" \ -H "Authorization: Bearer chrm_live_..." \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{"url":"https://example.com/charm-hook","topics":["points.earned"]}'Errors
Section titled “Errors”unauthorized · invalid_token · insufficient_scope · access_required · validation_error · rate_limited · idempotency_conflict
Every error body carries code, message, request_id and a doc_url pointing at the matching entry in the error catalog.