A single REST endpoint that tells you which suppliers in the SourceSheets network carry a given ASIN, how many, and at what price — with full supplier detail unlocked for any mutual customer who has connected their account.
The Partner API has one job right now: given an ASIN, tell you whether SourceSheets' supplier network has a match, and how good a deal it is. Every request is authenticated as your organization using a partner key. Requests can optionally also carry a customer token — a credential one of your mutual customers generates from their own SourceSheets account and hands to you — which unlocks that customer's actual supplier detail instead of an aggregate summary.
Neither side is required to connect for the other to work. You can show "3 suppliers carry this ASIN, from $4.50" to every user of your product using nothing but your partner key. A customer token only upgrades the response for the specific customer who chose to connect one.
Two credentials, sent as headers on every request:
| Header | Required | Identifies |
|---|---|---|
x-partner-key | Yes | Your organization. Issued once per key, can be scoped and revoked independently. |
x-customer-token | No | One specific SourceSheets customer, generated by them and pasted into your product. |
Both use the same shape — a public identifier and a secret, joined by a period:
x-partner-key: pak_5f2c9a1b7e0d4c3f.9b1e7a2d4c6f8091a3b5c7d9e1f30284
x-customer-token: pct_8a41d0f2c6b93e77.1d3f5b7a9c0e2416385a7c9e0b2d4f68A customer token is only ever valid alongside the partner key of the organization it was generated for — pairing it with a different partner's key doesn't upgrade the response, it's treated the same as not sending one at all.
60 requests per minute, tracked per API key rather than per IP address — several of your customers can sit behind a shared outbound IP without affecting each other's limit, and your sandbox key never eats into your live key's budget. Requests over the limit receive a 429 response. Get in touch if your integration needs a higher ceiling.
Partner keys are issued directly by the SourceSheets team, not self-serve. Reach out to your SourceSheets contact with the scopes your integration needs — today that's just asin-search — and you'll be issued a key shown to you exactly once at creation time.
Each mutual customer generates their own token from Settings → Integrations in their SourceSheets account, then pastes it into your product wherever you store third-party credentials. There's nothing for you to request or provision on your end — it arrives the same way an API key from any other connected service would.
Ask for a sandbox key alongside your live one — same auth, same endpoints, same shapes, but every response is fixed mock data. No real supplier data is touched, and x-customer-token isn't validated against a real customer — any non-empty value resolves as "connected." Build and test your whole integration before you have a single real customer connected.
| Endpoint | Sandbox behavior |
|---|---|
GET /partner/asin/:asin | Any valid-shaped ASIN returns the same 3-supplier fixture — base tier without a customer token, enriched tier with any non-empty one. |
GET /partner/customer/verify | Any non-empty x-customer-token returns { valid: true, connectedAt: "2026-01-15T09:00:00.000Z" }. |
curl https://api.sourcesheets.co.uk/v1/partner/asin/B0ANYTHING1 \
-H "x-partner-key: pak_1a2b3c4d5e6f7890.sandboxsecretexampleexampleexampleexample" \
-H "x-customer-token: anything-non-empty"Returns whatever tier of detail your credentials unlock for the given ASIN. The ASIN is matched case-insensitively and normalized to uppercase before lookup.
| Path parameter | Type | Notes |
|---|---|---|
asin | string | 10-character alphanumeric ASIN, e.g. B0EXAMPLE1. Anything else returns a 400. |
Real cost, total cost, profit, and ROI for every matching supplier — just with no name, ID, or link attached, so you can show the deal without revealing who it's from.
curl https://api.sourcesheets.co.uk/v1/partner/asin/B0EXAMPLE1 \
-H "x-partner-key: pak_5f2c9a1b7e0d4c3f.9b1e7a2d4c6f8091a3b5c7d9e1f30284"{
"asin": "B0EXAMPLE1",
"amazonTitle": "Wireless Mechanical Keyboard, 87-Key",
"amazonImageUrl": "https://images.example.com/b0example1.jpg",
"matches": 3,
"suppliers": [
{ "cost": 5.1, "profit": 3.2, "roi": 62.7, "isProfitable": true },
{ "cost": 5.85, "profit": 2.9, "roi": 49.6, "isProfitable": true },
{ "cost": 10.75, "profit": 1.4, "roi": 13.0, "isProfitable": true }
]
}No matches found returns 200 with matches: 0, null title/image, and an empty suppliers array — not a 404. Entries are sorted cheapest first.
Same shape, but each supplier entry gains an identity and a link — scoped to exactly what that customer's own SourceSheets account can see, the same set they'd get in the SourceSheets Viewer.
curl https://api.sourcesheets.co.uk/v1/partner/asin/B0EXAMPLE1 \
-H "x-partner-key: pak_5f2c9a1b7e0d4c3f.9b1e7a2d4c6f8091a3b5c7d9e1f30284" \
-H "x-customer-token: pct_8a41d0f2c6b93e77.1d3f5b7a9c0e2416385a7c9e0b2d4f68"{
"asin": "B0EXAMPLE1",
"amazonTitle": "Wireless Mechanical Keyboard, 87-Key",
"amazonImageUrl": "https://images.example.com/b0example1.jpg",
"matches": 3,
"suppliers": [
{
"supplierId": "3e7a1c9d-2b4f-4e8a-9c1d-7f2b5a8e0d3c",
"supplierName": "Northgate Wholesale",
"cost": 5.1,
"profit": 3.2,
"roi": 62.7,
"isProfitable": true,
"supplierLogoUrl": "https://cdn.sourcesheets.co.uk/supplier/northgate-wholesale.png",
"supplierViewerUrl": "https://app.sourcesheets.co.uk/viewer/3e7a1c9d-2b4f-4e8a-9c1d-7f2b5a8e0d3c?search=B0EXAMPLE1"
}
]
}| Field | Type | Notes |
|---|---|---|
asin | string | Normalized to uppercase. |
amazonTitle | string | null | Null when there are no matches. |
amazonImageUrl | string | null | |
matches | number | Count of distinct suppliers carrying this ASIN. |
suppliers | array | Always present, cheapest first. Shape depends on tier — see below. |
| Field | Type | Tier | Notes |
|---|---|---|---|
cost | number | null | Both | Total cost for the unit quantity on the sheet. |
profit | number | null | Both | |
roi | number | null | Both | |
isProfitable | boolean | Both | True only when profit is a known positive number — a quick condition if you don't want to inspect profit yourself. |
supplierId | string | Enriched | |
supplierName | string | null | Enriched | |
supplierLogoUrl | string | null | Enriched | The supplier's logo, served from our CDN. |
supplierViewerUrl | string | Enriched | Deep link into the SourceSheets Viewer, pre-filtered to this ASIN — not a link to the supplier's own site. The visitor needs to be logged into a SourceSheets account; if not, they're sent to log in first and land back here. |
Check a customer token the moment it's pasted into your product, instead of waiting for their first ASIN search to discover it was wrong. No scope required — any active partner key can call this. Doesn't count toward the token's own usage stats and reveals no customer identity, just whether it's connected.
curl https://api.sourcesheets.co.uk/v1/partner/customer/verify \
-H "x-partner-key: pak_5f2c9a1b7e0d4c3f.9b1e7a2d4c6f8091a3b5c7d9e1f30284" \
-H "x-customer-token: pct_8a41d0f2c6b93e77.1d3f5b7a9c0e2416385a7c9e0b2d4f68"{
"valid": true,
"connectedAt": "2026-07-14T09:32:00.000Z"
}An unrecognized, revoked, or cross-partner token isn't an error — you get 200 with { valid: false, connectedAt: null }. A missing x-customer-token header is the one case that's a 400, since that's a caller mistake rather than a token to check.
Errors return a JSON body of the shape { message: string }.
| Status | Meaning |
|---|---|
| 400 | Malformed request — an invalid ASIN, or a missing required header. |
| 401 | x-partner-key is missing, unrecognized, revoked, or belongs to a suspended partner. |
| 403 | Your key doesn't have the scope required for this endpoint. |
| 429 | Rate limit exceeded — back off and retry. |
x-customer-token problems are never in this table — see the callout above, they degrade silently instead.
Every route is versioned in the URL — everything here lives under /v1. Breaking changes ship as a new version rather than altering /v1 in place, so an integration written against this page keeps working indefinitely.