curl --request POST \
--url https://api-uat.dimetrades.com/api/partner/customers/refresh-token \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--header 'X-API-Secret: <api-key>' \
--data '
{
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"externalCustomerId": "ext-123"
}
'import requests
url = "https://api-uat.dimetrades.com/api/partner/customers/refresh-token"
payload = {
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"externalCustomerId": "ext-123"
}
headers = {
"X-API-Key": "<api-key>",
"X-API-Secret": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'X-API-Key': '<api-key>',
'X-API-Secret': '<api-key>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
refreshToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
externalCustomerId: 'ext-123'
})
};
fetch('https://api-uat.dimetrades.com/api/partner/customers/refresh-token', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api-uat.dimetrades.com/api/partner/customers/refresh-token",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'refreshToken' => 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
'externalCustomerId' => 'ext-123'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <api-key>",
"X-API-Secret: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api-uat.dimetrades.com/api/partner/customers/refresh-token"
payload := strings.NewReader("{\n \"refreshToken\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...\",\n \"externalCustomerId\": \"ext-123\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-Key", "<api-key>")
req.Header.Add("X-API-Secret", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api-uat.dimetrades.com/api/partner/customers/refresh-token")
.header("X-API-Key", "<api-key>")
.header("X-API-Secret", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"refreshToken\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...\",\n \"externalCustomerId\": \"ext-123\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api-uat.dimetrades.com/api/partner/customers/refresh-token")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-Key"] = '<api-key>'
request["X-API-Secret"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"refreshToken\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...\",\n \"externalCustomerId\": \"ext-123\"\n}"
response = http.request(request)
puts response.read_body{
"data": {
"message": "Token refreshed successfully",
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expiresIn": 7200,
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"isKycVerified": false
},
"errors": []
}Refresh a partner customer's token
Rotates an existing refreshToken and returns a fresh token + refreshToken pair. The partner flow never uses cookies, so the refresh token is supplied in the request body.
Server-to-server only. All /partner/* endpoints are authenticated with your brand credentials — X-API-Key + X-API-Secret headers — not with an end-user bearer token. Never expose these credentials to a browser or mobile app.
Possession is proven by validating the presented token (signature via the refresh JWT secret and the stored jti in Redis), so you cannot mint new tokens without holding a current refresh token. Rotation writes a new jti into the same device slot, invalidating the presented token (replay-safe) without affecting the customer’s other devices. Refresh stays allowed even when the customer is at the session limit, so an over-limit state can be resolved via logout.
curl --request POST \
--url https://api-uat.dimetrades.com/api/partner/customers/refresh-token \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--header 'X-API-Secret: <api-key>' \
--data '
{
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"externalCustomerId": "ext-123"
}
'import requests
url = "https://api-uat.dimetrades.com/api/partner/customers/refresh-token"
payload = {
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"externalCustomerId": "ext-123"
}
headers = {
"X-API-Key": "<api-key>",
"X-API-Secret": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'X-API-Key': '<api-key>',
'X-API-Secret': '<api-key>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
refreshToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
externalCustomerId: 'ext-123'
})
};
fetch('https://api-uat.dimetrades.com/api/partner/customers/refresh-token', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api-uat.dimetrades.com/api/partner/customers/refresh-token",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'refreshToken' => 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
'externalCustomerId' => 'ext-123'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <api-key>",
"X-API-Secret: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api-uat.dimetrades.com/api/partner/customers/refresh-token"
payload := strings.NewReader("{\n \"refreshToken\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...\",\n \"externalCustomerId\": \"ext-123\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-Key", "<api-key>")
req.Header.Add("X-API-Secret", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api-uat.dimetrades.com/api/partner/customers/refresh-token")
.header("X-API-Key", "<api-key>")
.header("X-API-Secret", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"refreshToken\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...\",\n \"externalCustomerId\": \"ext-123\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api-uat.dimetrades.com/api/partner/customers/refresh-token")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-Key"] = '<api-key>'
request["X-API-Secret"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"refreshToken\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...\",\n \"externalCustomerId\": \"ext-123\"\n}"
response = http.request(request)
puts response.read_body{
"data": {
"message": "Token refreshed successfully",
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expiresIn": 7200,
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"isKycVerified": false
},
"errors": []
}Authorizations
ISV / partner credential — public half. Required on every request.
Identifies the integration partner (ISV) making the call. Issued by Dime
Trades when the ISV is onboarded and sent on every /partner/* endpoint:
X-API-Key: dt_pk_live_7f3c9a2e5b18
- On the two partner endpoints that create accounts or issue tokens (
POST /partner/customers,POST /partner/customers/login), it is accompanied byX-API-Secretand is the only authentication — there is no user token yet. - On every other partner endpoint it is sent alongside the user's
Authorization: Bearer <token>: the API key says which platform is calling, the bearer token says which user it is calling for.
Credentials are scoped to one or more brands; using a key with a brandId outside that scope returns 403. Staging and production keys are separate.
The key identifies your platform — treat it as a backend credential.
ISV / partner credential — secret half. Sent on every /partner/* endpoint.
The confidential counterpart to X-API-Key. It is required, together with the key, on every /partner/* endpoint: register, login, refresh-token, logout, kyc, wallet-instructions and the replay endpoints. Outside /partner/* — the ordinary user API, called with a user's bearer token — the key is sent without the secret.
X-API-Key: dt_pk_live_7f3c9a2e5b18
X-API-Secret: dt_sk_live_9d41ba07c6e2f85a3b7c1049de26f8b1
A request to a /partner/* endpoint that has a key without its matching secret is rejected with 401. The secret is shown once at issue time and stored only as a hash on our side — if it is lost or exposed, rotate the pair from the partner console rather than asking for a copy. Never ship it in a browser or mobile client: anyone holding it can mint a token for any of your users.
Body
The current refresh token issued by register, session, or a previous refresh.
1"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
The customer's identifier on your platform. Optional when the previous step returned a customer object; required on every subsequent partner call.
1 - 128"ext-123"
