# Custom integrations

URL: https://supapulse.app/docs/guides/custom

Connect Supapulse to any payment processor, CMS or backend. The general pattern, server-side events, manual invoices and what isn't supported.

Supapulse has one ingest endpoint and two tokens. Every integration is a variation of the same steps.

## The pattern [#the-pattern]

1. **Browser:** the tracker runs on your site (script tag or npm). After login or signup, call `supapulse.identify(user.id)` to link the visitor to your user ID.
2. **Your backend:** when money arrives, post a `revenue` event with the secret token and the same ID as `customer_id`.
3. **Optional:** pass `getVisitorFingerprint()` and `getSessionId()` through checkout and send them as `visitor_fingerprint` and `session_id`. Use this when payment can happen before an account exists.

Stripe is the exception: [its webhook](https://supapulse.app/docs/guides/stripe) is built in and needs no backend code.

## Any payment processor [#any-payment-processor]

Most processors have a free-form metadata field that comes back in their webhooks. Put your user ID there:

| Processor | Field |
| --- | --- |
| Paddle Billing | `customData` / `custom_data` |
| Lemon Squeezy | `checkout_data.custom` / `meta.custom_data` |
| Your own checkout | A column on your orders table |

If yours has nothing like it, store your user ID with the order and look it up in the webhook.

```ts
// When the payment is confirmed
const order = await db.orders.find(payment.orderId);
await fetch('https://supapulse.app/api/ingest', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json', 'X-API-Token': process.env.SUPAPULSE_SECRET_TOKEN! },
  body: JSON.stringify({
    type: 'revenue',
    data: {
      customer_id: order.userId,
      amount: payment.amount,
      currency: payment.currency,
      transaction_id: payment.id,
      event_type: 'purchase',
      payment_processor: 'acme-pay',
    },
  }),
});
```

Send refunds as `event_type: "refund"` and subscription changes with `mrr_impact`. See [Basic usage](https://supapulse.app/docs/revenue/usage).

## CMSs and site builders [#cmss-and-site-builders]

WordPress, Webflow, Ghost, Shopify themes and similar tools take the script tag. Add it to the theme's `<head>`, or wherever the tool lets you inject head code:

```html
<script
  defer
  src="https://cdn.jsdelivr.net/npm/@supapulse/core@1/dist/browser.js"
  data-token="YOUR_PUBLIC_TOKEN"
></script>
```

For revenue from a hosted checkout you don't control, use whatever order webhook the platform offers and send revenue from your own server. If you can't pass anything into that checkout, call `identify()` on your site when the customer signs up and send revenue with the same customer ID. Supapulse uses the stored link.

## Manual and offline revenue [#manual-and-offline-revenue]

```bash
curl -X POST https://supapulse.app/api/ingest \
  -H "Content-Type: application/json" \
  -H "X-API-Token: $SUPAPULSE_SECRET_TOKEN" \
  -d '{"type":"revenue","data":{"customer_id":"acme","amount":12000,"currency":"USD","transaction_id":"contract-acme-2026","payment_processor":"manual"}}'
```

Make the `transaction_id` meaningful and unique, like an invoice number, so a repeated run doesn't count twice.

## Server-side events [#server-side-events]

The secret token can also send `event` and `pageview` types. A server-side event needs `event_name` and a full `url`:

```json
{
  "type": "event",
  "data": {
    "event_name": "trial_converted",
    "url": "https://acme.com/billing",
    "session_id": "6f1c2e9a-…"
  }
}
```

The visitor hash is built from the request's IP address and user agent, which are your server's. Every server-side event therefore looks like one visitor, from your server's country. Use it for counts of things that happen on the backend; use browser events for anything about visitors.

## Not supported [#not-supported]

- **Native mobile apps.** `@supapulse/core` needs a browser. There's no mobile SDK.
- **CRM sync.** Supapulse doesn't push data to Salesforce, HubSpot or other tools, and has no API for reading analytics back out. Exports from the dashboard are the way out.
- **Profiles.** `identify()` links a visitor to one customer ID for revenue attribution. Supapulse keeps no names, emails or user profiles.

## Privacy [#privacy]

Use an opaque customer ID, not an email address or a name. Supapulse stores the customer ID as a one-way hash, but it stores whatever else you put in event properties, URLs or `metadata` as sent. See [Privacy & compliance](https://supapulse.app/docs/data-privacy/privacy).
