All docs
Webhooks & integrations

Webhooks overview

Outgoing webhooks for slideshow events, plus the Stripe billing events we consume.

1 min readLast updated Edit this page
Outgoing webhooks are live

Register HTTPS endpoints from /integrations/webhooks (UI) or POST /v0/api/webhooks (API). Each delivery is HMAC-SHA256 signed with your per-endpoint secret and carries the X-ViralSlides-Signature, X-ViralSlides-Event, and X-ViralSlides-Delivery-Id headers. Failed deliveries retry on a 1m / 5m / 30m / 2h / 12h backoff for up to six attempts.

Available events

  • slideshow.completed — generation finished; slides + marketing assets are ready.
  • slideshow.failed — generation failed (payload includes the error message).
  • quota.exceeded — the org hit its monthly slideshow / hook-refresh / apps quota.
Example payload (slideshow.completed)json
{
  "slideshow_id": "ss_01HQ...",
  "organization_id": "org_01HQ...",
  "app_id": "app_01HQ...",
  "app_name": "Tidy",
  "hook_text": "POV: your app feed but tidier",
  "language": "en",
  "slide_count": 6,
  "template_set": "default"
}

Verifying signatures

Compute HMAC-SHA256 of the raw request body using your endpoint secret and compare against the hex digest in X-ViralSlides-Signature (formatted as `sha256=<hex>`). Reject the request if the signatures don't match in constant time.

Stripe events we consume

Our Stripe webhook endpoint (https://api.viralslides.app/v0/public/billing/stripe-webhook) handles the events below. Each is signed and verified via STRIPE_WEBHOOK_SECRET; duplicates are deduped by event id.

EventEffect
customer.subscription.createdCreates a local subscription and mirrors plan + status onto the organization.
customer.subscription.updatedUpserts the subscription. Status maps to ACTIVE / TRIALING / PAST_DUE / CANCELED.
customer.subscription.deletedMarks the subscription CANCELED and suspends the organization. Triggers a notification email.
invoice.payment_failedSets the org status to PAST_DUE and emails the owner the amount due.
invoice.payment_succeededReactivates the org (ACTIVE) and rolls over usage_counters for the new billing period.
checkout.session.completedCaptures stripe_customer_id on the organization for fast linkage of the first checkout.

Idempotency

Every Stripe event id is recorded in processed_webhook_events on first delivery and short-circuited on subsequent retries. This means it's safe for Stripe to redeliver events — we'll just acknowledge with received: true, duplicate: true.

Share & oEmbed

Public share links are issued per slideshow from the Slideshows page or POST /v0/api/slideshows/:id/share. Tokens are 32-char base64url, unguessable, and can be rotated or password-protected. Share URLs follow the pattern https://viralslides.app/share/<token>; the same token is valid in the iframe-safe embed at /embed/<token>. oEmbed discovery is exposed at GET /v0/public/oembed?url=<share-url>&format=json.

Slack & Discord notifications

Add incoming webhook URLs from Slack or Discord at /integrations/notify. ViralSlides will format slideshow.completed / slideshow.failed / quota.exceeded events into native Slack attachments or Discord embeds and POST them to your channel. Test-send from the UI before relying on the channel in production.