---
title: Sources · BuzzKit
description: Inbound webhooks from Stripe, Superwall, RevenueCat or anything custom, turned into subscriber events.
canonical: https://buzzkit.dev/features/sources
last-updated: 2026-09-02
---

# Every webhook becomes an event. Verified, mapped, deduplicated.

A source is an inbound webhook endpoint of a tenant. Stripe posts customer.subscription.created, the source verifies the signature, finds the subscriber and records subscription.started on their timeline, with no code on your side.

## A provider is a template

Stripe, Superwall, RevenueCat and custom each fill in a verification scheme and a default mapping, both editable afterwards. Without a secret the source stays unverified and records deliveries without creating events.

```
POST /v1/sources
{
  "name": "Stripe billing",
  "provider": "stripe",
  "secret": "whsec_…"
}
```

## The mapping decides what lands on the timeline

A mapping names the paths to the provider’s event type, id and timestamp, and how to find the subscriber: your external id, or a payload value matched against an attribute. Provider types map to event names, picked paths become event data, and a where clause filters what gets through.

```
{
  "type": "type",
  "id": "id",
  "timestamp": "created",
  "subscriber": {
    "path": "data.object.customer",
    "attribute": "stripeCustomerId"
  },
  "events": {
    "invoice.paid": "payment.succeeded",
    "customer.subscription.deleted": "subscription.ended"
  },
  "data": { "status": "data.object.status" },
  "where": { "ref": "livemode", "eq": true }
}
```

## Every delivery has one outcome

Each request to the ingest URL is recorded as rejected, dropped with a reason, duplicate, or event with the name and subscriber it landed on. Preview a stored payload against a mapping before you change it.

```
GET /v1/sources/src_2f9/deliveries
{
  "data": [
    {
      "outcome": "event",
      "providerType": "customer.subscription.created",
      "event": "subscription.started"
    },
    {
      "outcome": "duplicate",
      "providerEventId": "evt_1Q…"
    },
    { "outcome": "dropped", "reason": "no_subscriber" },
    { "outcome": "rejected", "reason": "bad_signature" }
  ]
}
```

## Capabilities

- **Stripe, Superwall, RevenueCat.** Presets for the billing and paywall tools apps already run on.
- **Custom sources.** Any service that posts JSON with a shared secret.
- **Subscriber lookup.** Match by your external id or any stored attribute.
- **Secrets sealed at rest.** Signing secrets are encrypted and never returned.
- **Pause without losing anything.** A paused source keeps recording and drops every delivery.
- **Audit and webhooks.** Every change to a source is an audit entry and a webhook event.

## Questions

### How do I turn Stripe webhooks into push notifications?

Create a Stripe source, paste its signing secret, and add the ingest URL in Stripe. Subscription events land on the subscriber’s timeline, and a workflow triggered on subscription.started sends the push.

### What if a webhook arrives for a customer BuzzKit does not know?

The delivery is recorded as dropped with the reason no_subscriber and no event is created. Store the provider’s customer id as an attribute on identify so the mapping can match it.

### Does BuzzKit replay duplicate webhooks?

No. The provider’s event id is the deduplication key per source, so a retried delivery is recorded as duplicate.

## Related

- [Workflows](https://buzzkit.dev/features/workflows.md): Event-triggered automation with waits, branches and sends, run per subscriber.
- [Segments](https://buzzkit.dev/features/segments.md): Saved expressions over attributes and events, evaluated fresh at send time.
- [Sending](https://buzzkit.dev/features/sending.md): One POST sends to a subscriber, a topic or a segment and lands on every device.

## Start

- [Start sending](https://buzzkit.dev/dashboard)
- [API Reference](https://docs.buzzkit.dev)
- [BuzzKit on GitHub](https://github.com/buzzkit-dev/buzzkit)
