PartnerShare API Authentication
This article explains the server-side authentication method for PartnerShare’s open API. Integrators must include an API Key, a second-precision timestamp, and a signature with every request. PartnerShare recalculates the signature server-side using the API Secret to validate the request, preventing forgery, replay, or unauthorized calls.
Key concepts: API Key (identity), API Secret (server-side signing), 5-minute time window, SHA256
1. Overview
PartnerShare’s open API uses API Key + API Secret + Timestamp + Signature for authentication by default. The API Key identifies the calling product; the API Secret is used only to generate the signature server-side and is never sent directly with the request.
Confirm caller identity: X-Api-Key identifies the product/tenant, ensuring the request comes from an authorized product.
Prevent request forgery: The signature is generated using the API Secret — attackers who know the API Key still cannot construct a valid signature.
Reduce replay risk: X-Api-Timestamp is only valid within a 5-minute window; expired requests are rejected.
Security note: The API Secret must be kept on the server side. It must never be exposed in browsers, mini-programs, mobile apps, public repositories, or shared Postman environments.
2. Getting your API Key and API Secret
In the PartnerShare dashboard, go to the relevant product’s Developer Integration or Advanced Settings page to get that product’s API Key and API Secret.
Field responsibilities: The API Key is sent in the request header to identify the calling product; the API Secret is only used locally to compute the signature and is never transmitted in plaintext.
3. Request header conventions
When calling an authenticated open API endpoint, include the following headers:
| Header | Required | Description |
|---|---|---|
X-Api-Key | Yes | The API Key PartnerShare assigned to your product, used to identify the calling product. |
X-Api-Timestamp | Yes | Second-precision timestamp. The server validates it’s within the allowed time window. |
X-Api-Sign | Yes | The SHA256 signature generated per this document’s rules. |
Content-Type | Yes | application/json recommended. |
Header example: #
http
POST /api/open/v1/track/conversion HTTP/1.1
Host: api-service.partnershare.net
Content-Type: application/json
X-Api-Key: pk_xxxxxxxxxxxxxxxxxxxxx
X-Api-Timestamp: 1776677721
X-Api-Sign: 8473ee71d083d9d1650c0e9081b5777d5b6cde2508521d5322d603a007214afd
4. Signature rules
PartnerShare’s signature only uses request parameter field names in the calculation — not the field values. Header fields do not participate in the signature either.
Collect request parameters: Merge top-level field names from the URL query, form body, and JSON body.
Lowercase all field names: e.g., Product_Key becomes product_key for signing purposes.
Sort naturally: The sort order must match the server’s — PHP can use SORT_NATURAL.
Join with &: e.g., extra&product_key&target_product_key&user_id.
Append timestamp and API Secret: The final string is joined_field_names + timestamp + api_secret.
Compute SHA256: Hash the final string with SHA256 to get the hex signature.
4.1 Signature formula #
text
sha256(sorted_lowercase_param_keys_joined_by_ampersand + timestamp + api_secret)
4.2 Worked example #
Request parameters:
json
{
"product_key": "your_product_key",
"target_product_key": "target_product_key",
"user_id": "user_10001",
"extra": {
"locale": "zh"
}
}
Field names included in the signature:
text
product_key
target_product_key
user_id
extra
Sorted and joined:
text
extra&product_key&target_product_key&user_id
Assume:
text
timestamp = 1776677721
api_secret = sk_your_api_secret
Final string to be signed:
text
extra&product_key&target_product_key&user_id1776677721sk_your_api_secret
5. Signature code examples
5.1 JavaScript #
javascript
function makeSign(params, timestamp, apiSecret) {
const keys = Object.keys(params)
.map((key) => key.toLowerCase())
.sort((a, b) => a.localeCompare(b, undefined, { numeric: true }));
const signString = keys.join('&') + timestamp + apiSecret;
return CryptoJS.SHA256(signString).toString(CryptoJS.enc.Hex);
}
5.2 PHP #
php
<?php
function makeSign(array $params, string $timestamp, string $apiSecret): string
{
$keys = array_map('strtolower', array_keys($params));
sort($keys, SORT_NATURAL);
$signString = implode('&', $keys) . $timestamp . $apiSecret;
return hash('sha256', $signString);
}
5.3 Go #
go
package main
import (
"crypto/sha256"
"fmt"
"sort"
"strings"
)
func MakeSign(params map[string]interface{}, timestamp string, apiSecret string) string {
keys := make([]string, 0, len(params))
for key := range params {
keys = append(keys, strings.ToLower(key))
}
sort.Strings(keys)
signString := strings.Join(keys, "&") + timestamp + apiSecret
sum := sha256.Sum256([]byte(signString))
return fmt.Sprintf("%x", sum)
}
5.4 Python #
python
import hashlib
def make_sign(params: dict, timestamp: str, api_secret: str) -> str:
keys = sorted([key.lower() for key in params.keys()])
sign_string = "&".join(keys) + timestamp + api_secret
return hashlib.sha256(sign_string.encode("utf-8")).hexdigest()
6. Full request example
Below is an example of the headers and body structure for a signup event postback request. Different endpoints may have different body fields, but the signature method is the same.
http
POST /api/open/v1/track/conversion HTTP/1.1
Host: api-service.partnershare.net
Content-Type: application/json
X-Api-Key: pk_xxxxxxxxxxxxxxxxxxxxx
X-Api-Timestamp: 1776677721
X-Api-Sign: 8473ee71d083d9d1650c0e9081b5777d5b6cde2508521d5322d603a007214afd
json
{
"event_name": "signup",
"invited_user_id": "user_10001",
"invite_code": "abc123"
}
Field names signed in this example: event_name, invited_user_id, invite_code, sorted and joined as event_name&invite_code&invited_user_id.
7. Common errors & troubleshooting
7.1 Why do I get “API Key or signature cannot be empty”? #
Usually the request header is missing X-Api-Key, X-Api-Timestamp, or X-Api-Sign. Confirm the header names are spelled correctly and that no gateway/proxy is stripping custom headers.
7.2 Why do I get “invalid signature”? #
Check specifically: whether you used the API Secret (not the API Key) to sign; whether field names are lowercased; whether the sort order matches; and whether the fields you signed exactly match the actual top-level fields in the request body.
7.3 Why does my signature work locally but fail in production? #
A common cause is that the serialization format changes in production — e.g., JSON locally but form-encoded in production — or a reverse proxy alters the request body. We recommend logging the actual top-level field names sent to PartnerShare and comparing them.
7.4 How long is the timestamp valid? #
Currently 5 minutes. Use a second-precision timestamp, and make sure your server clock is synced to standard time.
7.5 Can the API Secret be placed in the frontend? #
No. If the API Secret is exposed, anyone can forge valid requests. Always generate the signature server-side; the frontend should only call your own backend.
8. Best practices
- Keep the API Secret on the server only — never in frontend code, mobile app binaries, or public config.
- Generate a fresh timestamp and signature for every request — never reuse a previous signature.
- Log the list of field names used for signing before signing, to make debugging easier.
- Use different API Key/Secret pairs for production and test environments.
- If you suspect the API Secret has leaked, reset it immediately in the dashboard and update your server-side config.