Skip to main content

Integrations

Connect a provider

Attach Stripe, Paddle, LemonSqueezy or Polar to a site — and what this changes in your provider account.

POST/sites/{siteId}/integrations/{provider}/connect
Connect a payment provider
curl --request POST \
  --url 'https://truestat.io/api/v1/sites/{siteId}/integrations/{provider}/connect' \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '{
  "api_key": "<string>",
  "account_id": "<string>"
}'
{
  "data": {
    "backfill": {
      "state": "queued"
    },
    "provider": "stripe",
    "connected": true,
    "webhook_url": "https://truestat.io/api/webhooks/revenue/stripe/6fed8980-a119-4a9c-a4d4-53e448ef9f9e"
  },
  "meta": {
    "site_id": "6fed8980-a119-4a9c-a4d4-53e448ef9f9e"
  }
}

Attaches a payment provider to a site using a key from that provider.

This does three things, and two are outside TrueStat

Verifies the key

Its shape, its environment and its permissions, before anything is written. A mistyped key costs nothing and answers immediately.

Registers a webhook in your provider account

A real endpoint, created under your own credentials, which you will see in your provider's dashboard. This is how live sales reach TrueStat.

Queues a full history import

Your existing payments are imported afterwards, not during this call.

If the connection cannot be saved, the webhook is removed again — nothing is left registered in your account that TrueStat no longer knows how to delete.

backfill.state comes back as queued, never done

The import runs after this call returns. Treating a 200 here as "the figures are ready" shows an empty panel to somebody who will assume it is broken.

Poll GET /integrations and watch import.state reach done.

Providers that need an account id

Provideraccount_id
Stripenot used
Paddlenot used
LemonSqueezyrequired — the store id
Polarrequired — the organisation id

Stripe and Paddle scope a key to the account itself, so there is nothing to choose. The other two scope it to something narrower, and an account can hold several.

We will not pick one for you. Choosing the first one the provider returns would connect you to whichever it happened to list first — and the only symptom is an empty panel, or worse, another shop's revenue in yours.

Connecting again

The same provider is a reconnection. That is how a connection broken by a revoked key is repaired: post a fresh key. It re-queues the import, which is safe — a second pass over history you already have writes nothing.

A different provider is refused. A site holds one, and switching means disconnecting first — which deletes the stored revenue, so it has to be asked for deliberately.

The environment has to match

A test key on a live deployment reads nothing, and a live key on a test deployment writes real revenue into test data. Stripe and Paddle put the environment in the key itself, so a mismatch is caught before any network call. LemonSqueezy does not, so it is caught on the first API answer instead.

Either way it is a 400 naming which direction is wrong.

When it fails

StatusMeaning
400The key is wrong, the wrong mode, missing permissions, or an account id is required
402Plan or quota — see errors
502The provider refused or could not be reached; its own message is included
503Revenue integrations are not configured on this deployment

Authorizations

Authorizationstringheaderrequired

An API key from Settings → API keys. Scopes available: analytics:read, sites:read, sites:write, settings:read, settings:write, goals:read, goals:write, funnels:read, funnels:write, notes:read, notes:write, alerts:read, alerts:write, team:read, team:write, revenue:read, revenue:write.

Bearer authentication header of the form Bearer <token>, where <token> is your auth token.

Path parameters

siteIdstring (uuid)pathrequired
The site's id, from `GET /sites`. A site that is not yours and a site that does not exist both answer 403, so this cannot be used to discover other people's ids.
providerenum<string>path
`stripe`, `paddle`, `lemonsqueezy` or `polar`.
options:stripepaddlelemonsqueezypolar

Request bodyapplication/json

api_keystringbodyrequired
The provider's key. Its shape and environment are checked by that provider before anything is written.
account_idstringbody
The store or organisation to read, for providers that scope to one. Omit for Stripe and Paddle.

Response

application/json

The answer.

dataobject
metaobject