Account Linking
Account linking is the one-time flow that authorises your app to charge a ShopBack user. At the end of this flow you receive a paymentToken — a long-lived token scoped to a specific user and your merchant channel. Store it server-side and reuse it for all future payments for that user.
One token per userIf the same user links again, ShopBack returns the same
paymentToken. You don't need to update your records.
Flow overview
sequenceDiagram
autonumber
participant App as Merchant App
participant BE as Merchant Backend
participant SB as ShopBack API
App->>BE: User taps "Link ShopBack account"
BE->>SB: POST /tokenized-payment/v1/link-sessions/link
SB-->>BE: 200 { linkToken, redirectUrl, appToken, expiresAt }
BE-->>App: redirectUrl + appToken
App->>SB: Open redirectUrl in in-app browser
Note over App,SB: Header — X-ShopBack-App-Token: appToken
Note over SB: User reviews and approves on ShopBack consent page
SB-->>App: Redirect to callbackUrl?state=<state>&code=<authCode>
App->>BE: Forward authCode
BE->>SB: POST /tokenized-payment/v1/link-sessions/token
SB-->>BE: 200 { paymentToken }
Note over BE: Store paymentToken against merchantUserId
Step-by-step
1. Initiate a link session
Your backend calls POST /tokenized-payment/v1/link-sessions/link to create a new link session.
Request
POST /tokenized-payment/v1/link-sessions/link
Authorization: Bearer <merchant_jwt>
Content-Type: application/json
{
"callbackUrl": "https://your-app.com/shopback/callback",
"state": "csrf-nonce-abc123",
"merchantUserId": "usr_7829",
"userHint": {
"phone": "+6591xxxx67"
}
}| Field | Required | Description |
|---|---|---|
callbackUrl | Yes | HTTPS URL ShopBack redirects to after consent. Must be on the allowlist for your merchant channel. |
state | Yes | A CSRF nonce you generate. ShopBack echoes it back in the redirect so you can verify the response originates from ShopBack. |
merchantUserId | Yes | Your opaque, stable identifier for this user. Must match the merchantUserId you'll use in payment requests. |
userHint.phone | One of phone/email required | A pre-redacted hint displayed on the ShopBack consent page to confirm identity. |
userHint.email | One of phone/email required | As above. |
Response
{
"linkToken": "550e8400-e29b-41d4-a716-446655440000",
"redirectUrl": "https://pay.shopback.com/link",
"appToken": "eyJhbGciOiJIUzI1NiJ9...",
"expiresAt": "2026-06-24T10:20:00.000Z"
}| Field | Description |
|---|---|
linkToken | Identifies this session. Use it to poll session status if needed. |
redirectUrl | The ShopBack consent page URL. Open this in your in-app browser. |
appToken | A short-lived JWT. Pass as X-ShopBack-App-Token header when opening the in-app browser. |
expiresAt | Session TTL — 20 minutes from creation. Start the flow before this time. |
2. Open the consent page in your in-app browser
Open redirectUrl inside your app using an in-app browser (iOS: SFSafariViewController, Android: Custom Tabs). Pass appToken as a custom HTTP header:
X-ShopBack-App-Token: <appToken>
Do not open in a standard WebViewShopBack's consent page requires cookies and secure storage that standard WebViews may block. Use
SFSafariViewControlleror Chrome Custom Tabs.
ShopBack will display the user's linked payment method and prompt them to authorise your app.
3. Handle the redirect back to your app
Once the user approves (or declines), ShopBack redirects the in-app browser to your callbackUrl:
https://your-app.com/shopback/callback
?state=csrf-nonce-abc123
&code=a1b2c3d4e5f6
In your app:
- Verify
statematches what you sent in step 1 (CSRF check). - Extract the
code(auth code). It expires in 60 seconds — swap it immediately. - Close the in-app browser and pass
codeto your backend.
Auth code is single-use and expires in 60 secondsDo not store or display it. Send it straight to your backend for the token swap.
4. Exchange the auth code for a payment token
Your backend calls POST /tokenized-payment/v1/link-sessions/token with the one-time code.
Request
POST /tokenized-payment/v1/link-sessions/token
Authorization: Bearer <merchant_jwt>
Content-Type: application/json
{
"code": "a1b2c3d4e5f6"
}Response
{
"paymentToken": "pt_sg_7829_a1b2c3d4e5f6..."
}Store paymentToken server-side mapped to your merchantUserId. This token is:
- Long-lived — no expiry under normal circumstances.
- Reusable — use it for every subsequent pre-auth or immediate charge for this user.
- Revocable — call
POST /tokenized-payment/v1/tokens/unlinkto revoke it if the user disconnects.
Unlinking
To revoke a user's payment token (e.g. if they request disconnection):
POST /tokenized-payment/v1/tokens/unlink
Authorization: Bearer <merchant_jwt>
Content-Type: application/json
{
"paymentToken": "pt_sg_7829_a1b2c3d4e5f6..."
}
Unlink is blocked if a pre-auth is openIf the user has an
AUTHORIZEDpre-auth, the unlink request returns400. Capture or void the pre-auth first.
Next step
With your paymentToken, proceed to:
- Pre-Authorization — for hold-then-capture payments
- Immediate Charge — for one-shot fixed-price payments