One script tag in the browser. One idempotent POST from your server.
Written for someone deciding whether this wastes their weekend. The tracker is one tag. The event is one request with an Idempotency-Key, and a retry after a timeout is always safe.
<script
src="https://go.refficks.com/refficks.js?a=rk_pub_…"
data-account="rk_pub_…">
</script>curl https://go.refficks.com/api/v1/events \
-H "Authorization: Bearer rk_sec_…" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"event_type": "subscription.created",
"external_id": "sub_123",
"customer": { "external_id": "cus_123", "email": "customer@example.com" },
"properties": { "plan": "pro", "amount": 29900, "currency": "USD" }
}'Idempotency
Retries are free. Duplicates are structurally impossible.
Send the same event twice with the same key and it is recorded once. A retried webhook or a double-submitted event resolves to the original.
- Idempotency is a unique index in the database, not a check-then-write in code: two concurrent requests both pass a SELECT, and only one passes the index
- The second send answers 200 with status duplicate, so a client that lost the first answer learns what happened
- The publishable key in the browser can record visits and identify customers. It cannot read anything, and its beacon refuses revenue
- Anything involving money comes from your server with the secret key, or from a provider that signs what it sends
The data model
Append-only, and traceable end to end
Events, attributions, commission entries and audit logs are never updated or deleted. A correction is a new row. Every number can explain itself, because the rows it came from are still there.
integration_eventWhat arrived, exactly as it arrived, with its signature checked.
eventThe one event it became. A duplicate resolves to this row.
attributionEvery touch considered, which won, which lost and why, and the confidence.
commission_entryThe arithmetic, literally “20% of USD 299.00”. A refund is a new row beside it.
The audit log records who did what, when, with the values before and after. Attribution is never silently changed, and nothing is ever recomputed to be explained.
Multi-tenancy, credentials and the team
Isolation is a tested property
Every resource carries a test proving one organization cannot read another's data. Stated exactly that way, because that is what is true.
No merchant Stripe key is held
Refficks connects as a platform. Other integrations are OAuth first with the least scope, under their own encryption key, and never shown back.
Roles, two-factor, single sign-on
Owner, admin, manager, analyst and support. TOTP two-factor with recovery codes. OIDC single sign-on.
What you can build on
Four doors, each with a lock that is described rather than implied.
The Server API
With a secret key: partners, programmes, enrolments, links, codes, read-only commissions and payouts, and webhook subscriptions. It has no endpoint that approves or pays.
Signed outbound webhooks
Send events to your own systems, each delivery signed. And a Zapier app whose key cannot approve applicants, change earnings or record a sale.
An MCP server for AI apps
Claude and ChatGPT connect with a merchant's permission, read what that person's role may read, and can save drafts. No tool can approve, reverse, pay, reattribute, suspend or send.
The export
The whole account as CSV files in one archive, any time, every download recorded. Your data, out when you want it.
OpenAPI
454 paths, specified
An OpenAPI 3.1 specification ships with the product and covers the whole Server API. The live API answers at go.refficks.com.
The specification has no public address yet. It ships with the product, and this page carries the reference until it does.
One script tag. One idempotent POST.
Retries are free, duplicates are impossible, and every number can explain itself.