Worked example · partner integration
Add a “Get your tax report” button to SixpenceX
This is the live, openly-readable walkthrough of the Coinfig partner integration. SixpenceX is a fictional exchange we use as the worked example so prospective partners can validate the whole flow — read the API, walk the handoff, send a sandbox request — before committing a single sprint.
▶ Jump to the sandbox·← Back to the partner programme
Everything below — endpoints, payloads, error states, the sandbox console — mirrors the real production integration exactly. The sandbox at the bottom sends a real request through Coinfig's proxy, which injects the SixpenceX bearer token server-side (it never reaches the browser). Real partners get the same docs under their own private URL with their own bearer and discount code wired in.
The integration is deliberately light: one server-to-server API call followed by a redirect. No SDK, no embedded widget, no ongoing data feed for the partner to maintain. The Coinfig partner bearer token and the user's exchange API secret must never be exposed in the browser or mobile client.
How it works
SixpenceX adds a “Get your tax report” entry point — a button in the portfolio screen, a profile-menu row, or a tax-season banner. When a user opts in:
- User opts in inside SixpenceXThey tap “Get your tax report” and consent to share read-only history with Coinfig.
- SixpenceX's backend mints a read-only API keyGenerate (or reuse) a per-user API key/secret with read-only permissions scoped to transaction history.
- SixpenceX calls one Coinfig endpointA single
POSTwith the user's email and those credentials, authenticated with SixpenceX's partner bearer token. - Coinfig provisions the accountWe create or find the user, attach the SixpenceX data source, and begin importing transactions.
- Coinfig returns a passwordless sign-in linkA time-limited
redirect_urlcomes back in the response. - SixpenceX redirects the userThey land in Coinfig already signed in — no password needed on first arrival — with their history syncing in the background.
The first arrival is passwordless (a one-time sign-in link). To return afterwards the user needs a password: they can set one on that first visit when prompted, or if they skip it, sign in later via the standard “forgot password” / reset flow on their email. SSO is also supported where available.
Your backend must be able to programmatically create (or reuse) a per-user read-only API key. Everything else is one HTTP call and a redirect.
Authentication
Coinfig issues each real partner a unique bearer token per environment. It is stored only as a SHA-256 hash on the Coinfig side and can be rotated on request. Keep it in the partner's server-side secret store.
Authorization: Bearer <PARTNER_TOKEN>
| Environment | Base URL |
|---|---|
| Staging | https://staging-api.coinfig.tax |
| Production | https://api.coinfig.tax |
Real partner tokens are delivered through a separate secure channel — never in email and never in client code. Inject the token server-side only. The sandbox below uses the public SixpenceX bearer; it is injected by a same-origin proxy and never reaches the browser, exactly mirroring how real partner code should call this API in production.
Endpoint
# Provisions (or finds) a Coinfig user, attaches the SixpenceX source, # starts the import, and returns a passwordless sign-in link. POST https://api.coinfig.tax/api/v1/partner/register Authorization: Bearer <PARTNER_TOKEN> Content-Type: application/json
Request
Send a JSON body. Content-Type must be application/json.
{
"email": "user@example.com",
"name": "Jordan",
"surname": "Mensah",
"partner_source": "SIXPENCE",
"discount_code": "SIXPENCE_WELCOME_500",
"jurisdiction": "RSA",
"api_credentials": [
{
"exchange_name": "SIXPENCE",
"api_key": "user_sixpencex_api_key",
"api_secret": "user_sixpencex_api_secret"
}
]
}
Fields
| Field | Required | Notes |
|---|---|---|
email | YES | Valid email, max 255 chars. Identifies the Coinfig user. |
name | no | Max 100 chars. Pulled from the user's logged-in partner session in production. |
surname | no | Max 100 chars. |
partner_source | YES | Must match the partner identifier issued to you (uppercase). For this example it is SIXPENCE. |
discount_code | no | Optional per-partner discount applied at checkout. Issued per partner — defaults to your partner-specific code if omitted. |
jurisdiction | YES | The user's tax jurisdiction — send their country (ISO code or short code, e.g. RSA, USA). No fixed allow-list. |
api_credentials | YES | 1–15 items. For SixpenceX, exchange_name must be SIXPENCE. |
api_credentials[].api_key | YES | Min 10 chars. |
api_credentials[].api_secret | YES | Min 10 chars. |
api_credentials[].api_passphrase | no | Send only if your exchange uses a third credential. |
Always request API keys with read-only permission. Coinfig only reads transaction history — it never trades or withdraws. Credentials are encrypted at rest (AES-256) and decrypted only during sync.
Response
A new user returns 201 Created. An existing user returns 200 OK with the same shape and user_created: false. Sources already present return status: "skipped_duplicate".
{
"user_id": "usr_01HZA9F3K2WPS6T4VYXNK8B0Q1",
"user_created": true,
"sources_added": 1,
"sources": [
{
"source_id": "src_01HZA9F3K2WPS6T4VYXNK8B0Q2",
"exchange_name": "SIXPENCE",
"status": "processing"
}
],
"discount_applied": true,
"discount_code": "SIXPENCE_WELCOME_500",
"redirect_url": "https://coinfig.tax/r/eyJhbGciOi…",
"redirect_expires_at": "2026-07-23T08:15:00Z"
}
Fields SixpenceX should use
| Field | Notes |
|---|---|
redirect_url | One-time, time-limited sign-in URL. Redirect the user's browser straight to this — they land signed in. |
redirect_expires_at | ISO-8601. The link is single-use and expires after 30 days, but redirect immediately for the best experience. |
sources[].status | processing means import is queued; skipped_duplicate means we already had that source for the user. |
discount_applied | false means the code was rejected — see discount_error_code. Registration still succeeds. |
The redirect handoff
The redirect_url is the entire handoff. You don't need to embed Coinfig or share session state — just redirect the user's browser to that URL. The link carries a signed, single-use sign-in token; Coinfig validates it and drops the user into their report area.
- Single use. Once consumed, the URL is invalid. Generate a fresh one if you need to re-link.
- Time-limited. Default lifetime is 30 days, but you should redirect immediately on the same request.
- Stateful only at Coinfig. SixpenceX doesn't store the URL — it's user-facing once and then discarded.
# pseudo-code, any language resp = post("https://api.coinfig.tax/api/v1/partner/register", ...) redirect(resp.body.redirect_url, status=302)
Errors
| Status | Meaning | How to handle |
|---|---|---|
| 200 | OK · existing user, idempotent re-register. | Use the returned redirect_url as you would on 201. |
| 201 | Created · new user. | Redirect to redirect_url. |
| 400 | Validation failure (missing field, bad email, etc.). | Surface the message to your support tooling; the body lists the offending field. |
| 401 | Missing or invalid bearer token. | Confirm the env var is set; rotate the token if it leaked. |
| 403 | Bearer doesn't match the requested partner_source. | Send the partner_source you were issued; don't mix tokens between partners. |
| 409 | The user is already linked to a different partner. | Reach out — most cases are resolvable by attaching a new source rather than re-registering. |
| 429 | Rate-limited. | Back off (exponential), retry. Production limits are generous for normal partner traffic. |
| 500 | Server error. | Retry with backoff; if persistent, contact Coinfig with the timestamp. |
Discount problems do not fail the request — the account is still created and discount_error_code / discount_message explain the issue (e.g. INVALID_DISCOUNT_CODE).
Try the sandbox
Edit the payload and hit Send request. The browser POSTs to this site's same-origin proxy, which adds the SixpenceX bearer token server-side and forwards the call to Coinfig's real partner API. The bearer never reaches the browser. The request body is exactly what a real SixpenceX backend would send.
Partner registration sandbox
POST /api/v1/partner/register
Switching environments changes only the upstream URL the proxy talks to — the request body and headers are identical. Real partners get private bearer tokens for both environments; this example uses the public SixpenceX bearer for the worked walkthrough.
The placeholder credentials pass validation but won't actually sync. To watch a real import flow through end-to-end, enter genuine read-only SixpenceX (or, in a real partner integration, your exchange's) API credentials for a test account before sending.
Integration checklist
- Apply via the partner programme and receive your bearer token (staging first) from Coinfig.
- Store the token in the partner's server-side secret manager.
- Add a “Get your tax report” entry point in the partner UI.
- On opt-in, generate a read-only API key for that user (or reuse an existing one).
- Call
POST /api/v1/partner/registerfrom the partner's backend with the payload above. - Redirect the user to the returned
redirect_url. - Test against staging end-to-end, then repeat on production with the production token.
Testing on staging
- Get your staging bearer from Coinfig.
- Send the curl below against staging.
- Expect
201,sources_added: 1, and aredirect_url. - Open
redirect_urlin a browser — you should land in Coinfig signed in. - Wait ~1–2 minutes; the source moves from processing to populated.
curl -sS -X POST https://staging-api.coinfig.tax/api/v1/partner/register \ -H "Authorization: Bearer $PARTNER_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "email": "your-test+sixpencex@example.com", "partner_source": "SIXPENCE", "jurisdiction": "RSA", "api_credentials": [ { "exchange_name": "SIXPENCE", "api_key": "<read_only_key>", "api_secret": "<read_only_secret>" } ] }'
Security
- Server-to-server only — the bearer token never leaves the partner's backend.
- Exchange API keys should be read-only; Coinfig never trades or withdraws.
- Credentials are encrypted at rest (AES-256), decrypted only during sync.
- Sign-in links are cryptographically signed and single-use.
- All data access is scoped per user.
Browser ──▶ Partner backend ──▶ Coinfig Partner API ──▶ returns redirect_url ──▶ user lands signed in
(holds the bearer token)
OAuth 2.0 Planned · not yet available
For partners that prefer not to handle exchange API credentials, we are scoping an OAuth-style flow where the user authorises Coinfig directly with the partner — no bearer-mediated key handoff. The partner-facing API stays the same shape; only the credential exchange changes. We'll publish dates as we close out the pilot.
Talk to us
Convinced? Apply to partner via the partner programme application form. The Coinfig team reviews, sends your private docs and bearer, and a real human is on the other end if you get stuck.