Authentication
Every SASOM Partners API endpoint requires HTTP Basic Authentication. There is no unauthenticated route.
Getting your credentials
Credentials are issued per supplier by SASOM. Contact your SASOM account manager with:
- your business name
- the email address on your SASOM seller account
- what you intend to build
You will receive:
api_key— identifies your supplier account. Not a secret in the cryptographic sense, but do not publish it.secret— the credential. Treat it like a password.
The secret can create listings, reprice them, confirm orders, and download
shipping labels containing buyer names, addresses and phone numbers. There is no
scoping: one credential grants every endpoint in this API. Anyone holding it can
act as you.
This is a server-to-server API
Call it only from a backend you control.
- Never put the
secretin a browser, a mobile app, a desktop client, or anything shipped to a user. Anyone can read it out. - Never call these endpoints from front-end JavaScript. Do not rely on the
browser to stop you: these endpoints return permissive CORS headers
(
Access-Control-Allow-Origin: *), so a cross-origin call from page JavaScript is not reliably blocked. The credential is compromised the moment it reaches a client, whether the request succeeds or not. - Store the secret in environment variables or a secrets manager. Not in source control, not in a config file you commit, not in a CI log.
- If you need to give a client app access to your SASOM data, proxy it through your own backend and apply your own authorization there.
Making an authenticated request
Basic auth: api_key as the username, secret as the password.
cURL
curl -sS https://partners.sasomapi.com/partner/processing/orders \
-u "$SASOM_API_KEY:$SASOM_API_SECRET"
Explicit header
Authorization: Basic base64(api_key:secret)
CREDS=$(printf '%s:%s' "$SASOM_API_KEY" "$SASOM_API_SECRET" | base64)
curl -sS https://partners.sasomapi.com/partner/processing/orders \
-H "Authorization: Basic $CREDS"
Use printf, not echo — echo appends a newline, which corrupts the encoded
credential and produces a 403 that looks like a wrong password.
Node.js
// Credentials come from the environment. Never hardcode them.
const apiKey = process.env.SASOM_API_KEY;
const apiSecret = process.env.SASOM_API_SECRET;
if (!apiKey || !apiSecret) {
throw new Error('SASOM_API_KEY and SASOM_API_SECRET must be set');
}
const authorization = `Basic ${Buffer.from(`${apiKey}:${apiSecret}`).toString('base64')}`;
const response = await fetch(
'https://partners.sasomapi.com/partner/processing/orders',
{
headers: {
Authorization: authorization,
'Content-Type': 'application/json',
'Accept-Encoding': 'gzip',
},
},
);
Python
import os
import requests
from requests.auth import HTTPBasicAuth
api_key = os.environ["SASOM_API_KEY"]
api_secret = os.environ["SASOM_API_SECRET"]
response = requests.get(
"https://partners.sasomapi.com/partner/processing/orders",
auth=HTTPBasicAuth(api_key, api_secret),
timeout=30,
)
Authentication failures: 401, 403, or 500
This is the single most common source of confusion, so it is worth being precise.
Three different failures produce three different statuses, and one of them is a
500:
| What happened | Status | Body |
|---|---|---|
Authorization header absent | 401 | {"message":"Unauthorized"} |
Header malformed (not Basic , bad base64) | 500 | {"message":"Internal Server Error"} |
api_key not recognised | 500 | {"message":"Internal Server Error"} |
api_key recognised, secret wrong | 403 | {"message":"Forbidden"} |
| Rate limit exceeded | 403 | {"message":"Forbidden"} |
500 here usually means your credential is wrongAn unrecognised api_key makes our authorizer fail rather than deny, and
that surfaces to you as 500 Internal Server Error. During onboarding, or after a
typo in a key, 500 is the expected response — check the credential before
reporting an outage.
This is a known defect on our side. When it is fixed the status will become 403,
so do not build logic that depends on 500 meaning "bad key". Treat 401, 403
and 500 on the auth path as one class: verify the credential and your request
rate, and escalate only if a known-good credential keeps failing.
The API never returns 429. A rate-limit denial comes back as 403, which is
indistinguishable from a wrong secret.
The practical consequence: a burst of 403s does not mean your credentials
broke if they were working a minute ago. Check your request rate first — see
Rate Limiting. If your rate is well under the limit and a
known-good credential is failing, contact support.
A separate 403 with body {"statusCode":403,"message":"Supplier account not configured"} means your credential authenticated but your supplier account is not
fully set up. That one is a provisioning issue — contact your account manager.
Rotation and revocation are not instant
- A newly issued credential works immediately.
- A rotated or revoked credential can keep working for up to 5 minutes while the old secret ages out of cache.
So:
- After rotating, keep the old secret valid in your own config until you have confirmed the new one works — both will authenticate during the overlap.
- Revocation starts a 5-minute clock; it does not stop traffic at once.
Tell SASOM immediately — do not wait for a scheduled rotation, and do not assume
revocation is instant. Assume anything the credential could do may have been done
during the exposure window, and reconcile your listings
(GET /partner/live/listings/{type}) and orders
(GET /partner/processing/orders) afterwards.
Practices worth following
- Use HTTPS only. Plain HTTP is not served. Do not disable certificate verification to work around a local trust-store problem.
- Keep the secret out of logs. Log the request path and status, never the
Authorizationheader. If you log request objects wholesale, redact that header explicitly. - One credential per integration. If you run several systems, ask for separate credentials so one can be revoked without stopping the others.
- Rotate on staff change. A credential a departing engineer had access to should be rotated.
- Reconcile, don't trust. Because the API has no webhooks and writes are not idempotent, periodically compare your own view of listings and orders against the read endpoints.