No outbound webhooks yet. LocallyGrown does not currently publish events to third-party systems. There is no admin UI for subscribing to order, user, product, or payment events, and no X-LocallyGrown-Signature header or public webhook payload format. If outbound webhooks would be valuable for your market, let us know via the support channels.

Overview

LocallyGrown receives webhooks from two external services. Both are handled server-side and are not configurable from the admin UI — the endpoints are wired up as part of the platform itself.

💳 Stripe

Payment confirmations, failures, refunds, and card updates arrive at /api/webhooks/stripe and update order and payment records.

📧 Mailgun

Email delivery events — including unsubscribes, permanent bounces, and complaints — arrive at /api/webhooks/mailgun and update user accounts and email analytics.

Stripe webhook

Endpoint: POST /api/webhooks/stripe
Signature verification: Stripe's standard stripe-signature header, validated against STRIPE_WEBHOOK_SECRET.
Per-market routing: requests must include an x-market-id header so we can look up the right Stripe account.

Events handled

  • payment_intent.succeeded — marks the order paid and records the payment with card brand and last-4.
  • payment_intent.payment_failed — records the failure and surfaces the decline reason to the customer.
  • charge.refunded — records the Stripe refund on the order.
  • payment_method.updated — keeps saved card metadata (brand, last-4, expiry) in sync.

Other Stripe event types are accepted but not acted on. The endpoint is rate-limited per client IP.

Mailgun webhook

Endpoint: POST /api/webhooks/mailgun
Signature verification: Mailgun's standard HMAC signature using the configured signing key.

Events handled

  • unsubscribed — the recipient clicked the unsubscribe link in a market email. LocallyGrown treats this as a signal that the user wants to leave the market altogether and deactivates their account. (Users who just want to stop receiving email but stay in the market use the Subscribe/Unsubscribe button on their account page instead — see the Shopper Accounts guide.)
  • failed (permanent severity) — a hard bounce; the address is flagged so we stop sending to it.
  • complained — a spam complaint; the address is flagged.

All event types are also recorded as email-analytics rows for per-market delivery metrics. Events are batched in memory before being written, with a fallback queue for reliability if the database insert fails.

Operational notes

  • No retry configuration inside LocallyGrown. Retry behavior is whatever Stripe or Mailgun provides by default — we don't manage a retry queue for inbound webhooks.
  • Health checks. If a webhook endpoint is misbehaving, the platform health-check endpoints (/api/health, /api/health/queues) are the right place to start looking. Webhooks themselves don't have a dedicated status page.
  • Configuration. Stripe setup is per-market — see the Stripe Integration guide. Mailgun is configured platform-wide and is not exposed in the admin UI.

Related