Marketplace Selling

Shopee Open Platform API Integration: Auth, Signing & Tokens

How Shopee Open Platform API v2 integration works: app categories, OAuth flow, HMAC-SHA256 signing, token refresh, sandbox, IP whitelist and key rotation.

Photo de profil de Long Nguyen

Long Nguyen

Développeur fullstack · Ingénieur IA · Chercheur

• • 4 min de lecture •

How the Shopee Open Platform API works (v2)

A Shopee Open Platform API integration is a signed REST integration. Your server registers an app, each seller authorizes that app through an OAuth-style redirect, and every call afterwards carries a partner ID, a timestamp and an HMAC-SHA256 signature, plus a short-lived access token for shop-level calls. Listing sync, order import and inventory updates all sit on those pieces.

Shopee scheduled the older v1 API for full deprecation after , so anything new targets v2. The vocabulary is where first-time integrators lose time, so here is the map:

Term What it is Lifetime or rule
partner_id Identifies your app Fixed per app and per environment
partner_key Secret used to sign requests (never sent over the wire) Valid 180 days, then must be reset
shop_id The seller shop you act for Returned in the redirect after authorization
merchant_id Used in place of shop_id on merchant-level APIs Tokens are stored per merchant, separately from shops
code One-time authorization code 10 minutes, single use
access_token Credential for shop-level calls 4 hours
refresh_token Exchanged for a new access token 30 days
sign HMAC-SHA256 of the request, computed per call Tied to a timestamp accepted for about 5 minutes

Registering an app: the category decides everything

Shopee admits two kinds of developer: Third-Party Partners (companies building software for many sellers) and Registered Business Sellers (a seller integrating its own shop). Once the profile is approved you create an app in the console, and this is the step that costs teams weeks: the category chosen at creation fixes every API and permission the app can ever use.

Shopee's own developer FAQ announcement is blunt about it. The Open Platform team does not switch on individual APIs, permissions cannot be added to an existing app, and needing different capabilities can mean creating a new app under another category.

  • Choose the category from your endpoint list, not from the label. Write down the product, order, logistics and payment endpoints you need and confirm they all belong to one category before you create the app.
  • Do not promise buyer messaging by default. Applications for Customer Service (Chat API) apps from individual third parties and Third-party Partner platforms have been closed since . Confirm access before an inbox or chatbot feature goes into a client scope.
  • Permission denied usually means wrong category, a retired endpoint, or a documented change, not a bug in your signature.

The authorization flow, step by step

Every app type, whatever its category, starts with an authorization link built from Shopee's fixed authorization URL plus required parameters. The full contract is in Shopee's Authorization and Authentication guide; this is the sequence in practice:

  1. Build a signed link. Call /api/v2/shop/auth_partner with partner_id, timestamp, sign and your redirect URL.
  2. Seller approves. The seller logs in on Shopee's page and grants access. They pick the authorization length: 7, 30, 90, 180 or 365 days, or a custom date within 365 days.
  3. Shopee redirects back to your redirect URL with code and shop_id in the query string.
  4. Exchange the code at /api/v2/auth/token/get for an access_token and a refresh_token.
  5. Call shop APIs and refresh at /api/v2/auth/access_token/get before the access token lapses.
Item Valid for If it lapses
Signed timestamp in the auth link 5 minutes Generate a new link
Authorization code 10 minutes, one use Send the seller through the link again
access_token 4 hours Refresh with the refresh token
refresh_token 30 days Refresh earlier; the seller is not asked again
Seller's authorization Up to 365 days, chosen by the seller Seller must authorize again

Two of these rows get misread constantly. Refreshing a token never sends the seller back to Shopee, because it uses only the refresh token. And the seller's authorization is a separate clock from your tokens: a seller who chose 7 days will silently disconnect after a week even if your refresh job is perfect. Store that expiry and prompt the seller to reconnect before it hits.

How to sign a Shopee API request (HMAC-SHA256)

The signature is the hex digest of an HMAC-SHA256 over a base string, keyed with your partner key. What goes into the base string depends on the API type:

API type Base string, concatenated in this order
Public (auth link, token exchange, refresh) partner_id + api_path + timestamp
Shop partner_id + api_path + timestamp + access_token + shop_id
Merchant partner_id + api_path + timestamp + access_token + merchant_id

The result is sent as the sign query parameter next to partner_id and timestamp; shop calls also carry access_token and shop_id. api_path is only the path, for example /api/v2/shop/get_shop_info, with no host and no query string. This Python module covers the whole first-connection flow:

import hashlib
import hmac
import time
from urllib.parse import urlencode

import requests

HOST = 'https://partner.test-stable.shopeemobile.com'  # sandbox; production is https://partner.shopeemobile.com
PARTNER_ID = 1000000          # from the console, must match the environment
PARTNER_KEY = 'your-partner-key'


def sign(path, ts, access_token='', entity_id=''):
    # public API: partner_id + path + timestamp
    # shop API: ... + access_token + shop_id (merchant API: merchant_id)
    base = f'{PARTNER_ID}{path}{ts}{access_token}{entity_id}'
    return hmac.new(PARTNER_KEY.encode(), base.encode(), hashlib.sha256).hexdigest()


def auth_url(redirect):
    path = '/api/v2/shop/auth_partner'
    ts = int(time.time())
    query = urlencode({'partner_id': PARTNER_ID, 'timestamp': ts,
                       'sign': sign(path, ts), 'redirect': redirect})
    return f'{HOST}{path}?{query}'


def public_post(path, body):
    ts = int(time.time())
    params = {'partner_id': PARTNER_ID, 'timestamp': ts, 'sign': sign(path, ts)}
    body = dict(body, partner_id=PARTNER_ID)
    return requests.post(HOST + path, params=params, json=body, timeout=15).json()


def get_token(code, shop_id):
    return public_post('/api/v2/auth/token/get', {'code': code, 'shop_id': shop_id})


def refresh_token(refresh_tok, shop_id):
    return public_post('/api/v2/auth/access_token/get',
                       {'refresh_token': refresh_tok, 'shop_id': shop_id})


def shop_get(path, access_token, shop_id, **extra):
    ts = int(time.time())
    params = {'partner_id': PARTNER_ID, 'timestamp': ts, 'access_token': access_token,
              'shop_id': shop_id, 'sign': sign(path, ts, access_token, shop_id)}
    params.update(extra)
    return requests.get(HOST + path, params=params, timeout=15).json()


# info = shop_get('/api/v2/shop/get_shop_info', access_token, shop_id)

Run it against the sandbox host first and swap in the production host, partner ID and key only after that works. Three causes account for most signature failures:

  • Environment mismatch. Key, partner_id and host must all belong to the same environment (sandbox or live). A production key against the sandbox host fails every time.
  • Different timestamps. The timestamp inside the base string must be the exact value sent in the URL. Compute it once per call.
  • A drifting server clock. Shopee only honours a signed timestamp for a few minutes, so a server whose clock has slipped looks like an intermittent signature problem. Keep NTP running.

Storing and refreshing tokens without breaking sync

Store one token record per shop_id and per merchant_id, never per app. A record needs the access token, the refresh token, both expiry times, and the seller's authorization expiry. Refresh proactively, well before the four-hour mark, rather than waiting for a call to fail mid-sync.

The subtle failure is concurrency. If two workers refresh the same shop at once, the loser can overwrite a good token pair with a stale one. Treat the refresh token as rotating: take a per-shop lock, call refresh, and write back both tokens returned in the same transaction, overwriting what was there. Every other worker reads from the database and never refreshes on its own.

This token layer is the unglamorous part that every marketplace connector needs, and it multiplies with each channel you add. Teams syncing Shopee alongside Amazon, eBay or TikTok Shop often decide it is cheaper to have marketplace integration built and maintained for them than to own one auth model per platform.

Sandbox vs production: what test-stable will and will not tell you

The sandbox host is partner.test-stable.shopeemobile.com; production is partner.shopeemobile.com. Shopee describes the sandbox as functional but not a full replica of production, so divergent behavior, limits and instability can be expected there.

  • Use it to validate signing, the authorization flow, token refresh and payload shapes.
  • Do not use it to judge throughput, edge-case order states or logistics behavior.
  • Creating test orders can fail with errors such as error_sandbox_order_checkout_cart_item, invalid product or Failed to get info. Shopee's advice is to create new products, try another category and repeat the flow before assuming your code is wrong.
  • If you open a support ticket, run isolation tests first and attach a full screen recording, a HAR file and the complete request and response.

Why buyer data comes back masked (IP whitelist)

If order responses arrive with masked buyer details, the fix is in your app settings, not in a support request. Access to sensitive data is tied to the app's security configuration, including the IP whitelist, and Shopee states there is no manual release of masked data. The whitelist is configured by you in the console; Shopee staff cannot do it for you.

Check two things in order. First, that the whitelist is set up and enabled for the exact egress IPs your servers use, which matters if you deploy behind a NAT gateway or on autoscaling infrastructure with changing addresses. Second, the order's status: some order states do not expose buyer data through the API at all, so masked fields on a fresh unpaid order are not necessarily a whitelist problem.

Partner Key expiry and safe rotation

The Partner Key is valid for 180 days from generation, and it does not renew itself. Once it expires the platform marks it invalid and blocks API calls that use it, which for a live integration means every seller goes dark at once. Set a calendar reminder well before day 180 and treat the rotation as a planned release.

  • A reset takes effect immediately for the new key.
  • You can keep the old key alive for up to 72 hours after the reset, which gives you a window to roll the new secret across servers.
  • Resetting does not invalidate seller authorizations, so no seller has to reconnect.
  • The key is managed inside the app, under App List in the console. Shopee cannot generate a replacement for you.

Read the key from a secret store at runtime rather than baking it into images, so rotation is a config change and not a redeploy.

Push Mechanism vs polling for orders and inventory

Shopee documents a Push Mechanism, a webhook that notifies a callback URL registered for your app when events such as order status changes occur. It is the right tool for low latency, and it should not be your only tool.

Design it as push plus reconciliation. Verify the push signature as the Push Mechanism documentation describes, acknowledge fast, and put the event on a queue rather than doing the work inline. Then run a scheduled job that queries orders by update-time window and compares them with your database. Pushes can arrive late, twice or not at all, and a reconciliation pass is what turns a best-effort feed into a system you can trust. Make every handler idempotent on the order number so a repeated push is harmless.

Common Shopee API errors and what to check first

Symptom Check first
Invalid sign Environment match (key, partner ID, host), the base string order, the same timestamp in sign and URL, a path with no host or query string, and the right token for shop calls
Invalid timestamp or a dead auth link The signed timestamp lives about 5 minutes. Generate a new link and check the server clock
Code rejected Codes are single use and expire after 10 minutes. Restart authorization
Access token expired Tokens last 4 hours. Refresh with the stored refresh token
Permission denied or endpoint missing Is the API inside your app category, does the endpoint still exist in the API reference, and did an announcement change it
Masked buyer data IP whitelist configured and enabled, then the order status
Sandbox order creation fails Create new test products, try another category, repeat the flow
All calls fail at once, all shops Partner Key expired or was reset without the 72-hour overlap

Build it yourself or hand it over

The Shopee side is manageable for one shop and one developer: sign correctly, store tokens per shop, refresh under a lock, reconcile pushes, and rotate the key on schedule. The cost shows up in maintenance, when a category limitation blocks a feature, a key expires over a weekend, or you add a second marketplace with its own rules.

If you would rather scope that work than carry it, request a free quote with the marketplaces and features you need. Work is priced to scope, and you get an answer without committing to anything.

FAQ

Questions fréquentes

How do I get access to the Shopee Open Platform API?

Register on Shopee Open Platform as either a Third-Party Partner or a Registered Business Seller. After your profile is approved, create an app in the console. The category you choose at creation determines which APIs and permissions the app has, and Shopee does not enable individual APIs on request.

How long do Shopee API access tokens last?

An access_token is valid for 4 hours and a refresh_token for 30 days. Call the refresh endpoint to get a new access token; the seller does not need to authorize again. The seller's own authorization is a separate clock, chosen by the seller at up to 365 days.

How is the Shopee API v2 signature generated?

Concatenate partner_id, the API path and the timestamp, then append access_token and shop_id for shop-level calls (merchant_id for merchant-level calls). Compute an HMAC-SHA256 of that string using your partner key and send the hex digest as the sign parameter.

Can I add permissions to an existing Shopee app?

No. Permissions and available APIs are set by the app category chosen at creation, and the Open Platform team does not enable individual APIs. If you need different capabilities you may have to create a new app under another category.

Is there a Shopee API sandbox?

Yes. The sandbox host is partner.test-stable.shopeemobile.com. It is meant for testing signing, authorization and payloads, but Shopee notes it does not fully replicate production, so some errors and inconsistencies are expected there.

Does the Shopee Partner Key expire?

Yes. A Partner Key is valid for 180 days and is not renewed automatically. After expiry it is marked invalid and calls using it are blocked. You reset it yourself in the console, the new key works immediately, and the old key can stay valid for up to 72 hours. Seller authorizations are not affected.

Why is buyer data masked in Shopee order responses?

Access to sensitive data depends on your app's security setup, including the IP whitelist configured in the console. There is no manual release of masked data, and some order statuses do not expose buyer data at all.

Restez informé avec Netalith

Recevez des ressources de développement, des mises à jour produit et des offres spéciales directement dans votre boîte mail.