Integrations
Connect a provider
Attach Stripe, Paddle, LemonSqueezy or Polar to a site — and what this changes in your provider account.
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
| Provider | account_id |
| Stripe | not used |
| Paddle | not used |
| LemonSqueezy | required — the store id |
| Polar | required — 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
| Status | Meaning |
400 | The key is wrong, the wrong mode, missing permissions, or an account id is required |
402 | Plan or quota — see errors |
502 | The provider refused or could not be reached; its own message is included |
503 | Revenue integrations are not configured on this deployment |
Authorizations
AuthorizationstringheaderrequiredAn 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)pathrequiredproviderenum<string>pathstripepaddlelemonsqueezypolarRequest bodyapplication/json
api_keystringbodyrequiredaccount_idstringbodyResponse
The answer.
dataobjectmetaobjecterrorobjecterrorobjecterrorobjecterrorobject