Quickstart
Connect your sandbox test seller to your own sandbox app, call the API, create your first order and receive its webhooks — in about ten minutes.
This walk-through runs on the sandbox: replace https://coliswift.com with https://coli.swiftmanager.net in every URL below, and use the credentials of the app you created there.
0. What you need
- A sandbox app you created on « Applications développeur » (how), with
http://localhost:3000/callbackamong its redirect URIs, and itsclient_idandclient_secret. - Your own test seller on the sandbox — the one that created the app — with at least one product (note its
reference). - A small server on
localhost:3000that handles the callback.
1. Send the seller to the consent page
Generate a PKCE verifier and challenge plus a random state, keep them server-side, and redirect the seller to the authorize URL. PKCE (S256) is mandatory, even for confidential clients.
import crypto from 'node:crypto';
// 43–128 chars of [A-Za-z0-9-._~] — 32 random bytes in base64url are 43.
const codeVerifier = crypto.randomBytes(32).toString('base64url');
const codeChallenge = crypto.createHash('sha256').update(codeVerifier).digest('base64url');
const state = crypto.randomBytes(16).toString('hex');
// Keep codeVerifier and state in the user's session on YOUR server.
const authorizeUrl = new URL('https://coliswift.com/oauth/authorize');
authorizeUrl.search = new URLSearchParams({
response_type: 'code',
client_id: process.env.COLISWIFT_CLIENT_ID,
redirect_uri: 'http://localhost:3000/callback',
scope: 'profile:read catalogue:read orders:write orders:read',
state,
code_challenge: codeChallenge,
code_challenge_method: 'S256',
}).toString();
// Redirect the seller's browser to authorizeUrl.$b64url = fn ($bin) => rtrim(strtr(base64_encode($bin), '+/', '-_'), '=');
$codeVerifier = $b64url(random_bytes(32));
$codeChallenge = $b64url(hash('sha256', $codeVerifier, true));
$state = bin2hex(random_bytes(16));
$_SESSION['cs_verifier'] = $codeVerifier;
$_SESSION['cs_state'] = $state;
$authorizeUrl = 'https://coliswift.com/oauth/authorize?' . http_build_query([
'response_type' => 'code',
'client_id' => getenv('COLISWIFT_CLIENT_ID'),
'redirect_uri' => 'http://localhost:3000/callback',
'scope' => 'profile:read catalogue:read orders:write orders:read',
'state' => $state,
'code_challenge' => $codeChallenge,
'code_challenge_method' => 'S256',
], '', '&', PHP_QUERY_RFC3986);
header('Location: ' . $authorizeUrl);import base64, hashlib, os, secrets
from urllib.parse import urlencode
code_verifier = secrets.token_urlsafe(32) # 43 chars
code_challenge = base64.urlsafe_b64encode(
hashlib.sha256(code_verifier.encode("ascii")).digest()
).rstrip(b"=").decode()
state = secrets.token_hex(16)
# Store code_verifier and state in the user's server-side session.
authorize_url = "https://coliswift.com/oauth/authorize?" + urlencode({
"response_type": "code",
"client_id": os.environ["COLISWIFT_CLIENT_ID"],
"redirect_uri": "http://localhost:3000/callback",
"scope": "profile:read catalogue:read orders:write orders:read",
"state": state,
"code_challenge": code_challenge,
"code_challenge_method": "S256",
})The seller signs in to ColiSwift (if needed), reads the permissions and clicks approve. ColiSwift then redirects to your redirect_uri with ?code=cs_code_…&state=….
2. Exchange the code for tokens
Check that state matches what you stored, then POST the code with your verifier. The code is valid 5 minutes and once.
curl -X POST "https://coliswift.com/api/oauth/token" \
--data-urlencode "grant_type=authorization_code" \
--data-urlencode "code=$CODE" \
--data-urlencode "redirect_uri=http://localhost:3000/callback" \
--data-urlencode "code_verifier=$CODE_VERIFIER" \
--data-urlencode "client_id=$COLISWIFT_CLIENT_ID" \
--data-urlencode "client_secret=$COLISWIFT_CLIENT_SECRET"const res = await fetch('https://coliswift.com/api/oauth/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'authorization_code',
code: process.env.CODE,
redirect_uri: 'http://localhost:3000/callback',
code_verifier: process.env.CODE_VERIFIER,
client_id: process.env.COLISWIFT_CLIENT_ID,
client_secret: process.env.COLISWIFT_CLIENT_SECRET,
}),
});
const tokens = await res.json();$ch = curl_init('https://coliswift.com/api/oauth/token');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POSTFIELDS => http_build_query([
'grant_type' => 'authorization_code',
'code' => getenv('CODE'),
'redirect_uri' => 'http://localhost:3000/callback',
'code_verifier' => getenv('CODE_VERIFIER'),
'client_id' => getenv('COLISWIFT_CLIENT_ID'),
'client_secret' => getenv('COLISWIFT_CLIENT_SECRET'),
]),
]);
$tokens = json_decode(curl_exec($ch), true);import os, requests
res = requests.post("https://coliswift.com/api/oauth/token", data={
"grant_type": "authorization_code",
"code": os.environ["CODE"],
"redirect_uri": "http://localhost:3000/callback",
"code_verifier": os.environ["CODE_VERIFIER"],
"client_id": os.environ["COLISWIFT_CLIENT_ID"],
"client_secret": os.environ["COLISWIFT_CLIENT_SECRET"],
})
tokens = res.json(){
"access_token": "cs_at_…",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "cs_rt_…",
"scope": "profile:read catalogue:read orders:write orders:read",
"seller_id": "6a1c2f0e-3b7d-4c55-9e10-2f8a4b7c9d01",
"seller_name": "Atlas Beauty"
}Store both tokens encrypted, keyed by seller_id. The access token lives expires_in seconds; refresh it with the refresh token (see OAuth).
3. Say hello
curl "https://coliswift.com/api/partner/v1/me" \
-H "Authorization: Bearer $COLISWIFT_ACCESS_TOKEN"const res = await fetch('https://coliswift.com/api/partner/v1/me', {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.COLISWIFT_ACCESS_TOKEN}`,
},
});
const data = await res.json();$ch = curl_init('https://coliswift.com/api/partner/v1/me');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('COLISWIFT_ACCESS_TOKEN'),
],
]);
$data = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);import os, requests
res = requests.get(
"https://coliswift.com/api/partner/v1/me",
headers={"Authorization": f"Bearer {os.environ['COLISWIFT_ACCESS_TOKEN']}"},
)
data = res.json(){
"seller": {
"id": "6a1c2f0e-3b7d-4c55-9e10-2f8a4b7c9d01",
"name": "Samira Benali",
"email": "seller@example.com",
"companyName": "Atlas Beauty",
"countries": [
"MA"
]
},
"client": {
"id": "b7e2c4a1-9f3d-4e6b-8a20-5c1d7e9f0a3b",
"name": "Your App"
},
"grant": {
"id": "f3a9d2c1-7e5b-4a8f-9c60-1b2d3e4f5a6b",
"scopes": [
"profile:read",
"catalogue:read",
"orders:write",
"orders:read"
],
"createdAt": "2026-11-02T09:14:03.000Z"
},
"stores": [
{
"id": "b2d4e6f8-1a3c-4e5f-8a9b-0c1d2e3f4a5b",
"name": "atlas-beauty.example",
"countryCode": "MA",
"status": "active"
}
]
}4. Create an order
Each line names a product by its reference (or a variant SKU, or the SKU of an adopted COD Drop product). externalId is your order id: sending the same one again returns the existing order with duplicate: true instead of creating a second one.
curl -X POST "https://coliswift.com/api/partner/v1/orders" \
-H "Authorization: Bearer $COLISWIFT_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"externalId": "shop_10482",
"countryCode": "MA",
"customer": {
"name": "Youssef El Amrani",
"phone": "+212600000000",
"address": "12 rue des Oliviers, Casablanca"
},
"storeId": "b2d4e6f8-1a3c-4e5f-8a9b-0c1d2e3f4a5b",
"notes": "Deliver after 6 pm",
"lines": [
{
"reference": "SERUM-ARGAN-30",
"quantity": 2,
"unitPrice": "199.00"
}
]
}'const res = await fetch('https://coliswift.com/api/partner/v1/orders', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.COLISWIFT_ACCESS_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"externalId": "shop_10482",
"countryCode": "MA",
"customer": {
"name": "Youssef El Amrani",
"phone": "+212600000000",
"address": "12 rue des Oliviers, Casablanca"
},
"storeId": "b2d4e6f8-1a3c-4e5f-8a9b-0c1d2e3f4a5b",
"notes": "Deliver after 6 pm",
"lines": [
{
"reference": "SERUM-ARGAN-30",
"quantity": 2,
"unitPrice": "199.00"
}
]
}),
});
const data = await res.json();$ch = curl_init('https://coliswift.com/api/partner/v1/orders');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('COLISWIFT_ACCESS_TOKEN'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => <<<'JSON'
{
"externalId": "shop_10482",
"countryCode": "MA",
"customer": {
"name": "Youssef El Amrani",
"phone": "+212600000000",
"address": "12 rue des Oliviers, Casablanca"
},
"storeId": "b2d4e6f8-1a3c-4e5f-8a9b-0c1d2e3f4a5b",
"notes": "Deliver after 6 pm",
"lines": [
{
"reference": "SERUM-ARGAN-30",
"quantity": 2,
"unitPrice": "199.00"
}
]
}
JSON,
]);
$data = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);import os, requests
res = requests.post(
"https://coliswift.com/api/partner/v1/orders",
headers={"Authorization": f"Bearer {os.environ['COLISWIFT_ACCESS_TOKEN']}"},
json={
"externalId": "shop_10482",
"countryCode": "MA",
"customer": {
"name": "Youssef El Amrani",
"phone": "+212600000000",
"address": "12 rue des Oliviers, Casablanca",
},
"storeId": "b2d4e6f8-1a3c-4e5f-8a9b-0c1d2e3f4a5b",
"notes": "Deliver after 6 pm",
"lines": [
{
"reference": "SERUM-ARGAN-30",
"quantity": 2,
"unitPrice": "199.00",
},
],
},
)
data = res.json(){
"lead_id": "6f1c2a9e-3b7d-4c11-9a52-0d8e4b7f2c10",
"external_id": "shop_10482",
"order_code": "MA03112026-0042",
"currency": "MAD",
"country": "MA",
"store_id": "b2d4e6f8-1a3c-4e5f-8a9b-0c1d2e3f4a5b",
"status": "new",
"confirmed_at": null,
"articles_amount": "398.00",
"lines": [
{
"line_id": "c0a8e1f2-5d6b-4a7c-9e8f-1a2b3c4d5e6f",
"product_id": "9e8d7c6b-5a4f-4e3d-2c1b-0a9f8e7d6c5b",
"product_reference": "SERUM-ARGAN-30",
"product_name": "Sérum à l'huile d'argan 30 ml",
"variant_id": null,
"variant_label": null,
"quantity": 2,
"unit_price": "199.00"
}
],
"created_at": "2026-11-03T09:58:41.000Z",
"updated_at": "2026-11-03T09:58:41.000Z"
}5. Follow the order
Read it back by your id at any time:
curl "https://coliswift.com/api/partner/v1/orders/shop_10482" \
-H "Authorization: Bearer $COLISWIFT_ACCESS_TOKEN"const res = await fetch('https://coliswift.com/api/partner/v1/orders/shop_10482', {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.COLISWIFT_ACCESS_TOKEN}`,
},
});
const data = await res.json();$ch = curl_init('https://coliswift.com/api/partner/v1/orders/shop_10482');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('COLISWIFT_ACCESS_TOKEN'),
],
]);
$data = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);import os, requests
res = requests.get(
"https://coliswift.com/api/partner/v1/orders/shop_10482",
headers={"Authorization": f"Bearer {os.environ['COLISWIFT_ACCESS_TOKEN']}"},
)
data = res.json()If your app has a webhook URL, ColiSwift also POSTs events to it as the order moves: lead.confirmation_status_changed when it is confirmed with the customer and locked for shipping (status: "confirmed"), then the delivery events. In production the call centre and the warehouse move it; on the sandbox you move it yourself with the advance helper (POST /test/orders/shop_10482/advance with {"to": "confirmed"}). Verify the X-Coliswift-Signature header before trusting the body (how) and answer 2xx quickly.
{
"data": {
"articles_amount": "398.00",
"confirmed_at": "2026-11-03T10:15:05.000Z",
"country": "MA",
"created_at": "2026-11-03T09:58:41.000Z",
"currency": "MAD",
"external_id": "shop_10482",
"lead_id": "6f1c2a9e-3b7d-4c11-9a52-0d8e4b7f2c10",
"lines": [
{
"line_id": "c0a8e1f2-5d6b-4a7c-9e8f-1a2b3c4d5e6f",
"product_id": "9e8d7c6b-5a4f-4e3d-2c1b-0a9f8e7d6c5b",
"product_name": "Sérum à l'huile d'argan 30 ml",
"product_reference": "SERUM-ARGAN-30",
"quantity": 2,
"unit_price": "199.00",
"variant_id": null,
"variant_label": null
}
],
"order_code": "MA03112026-0042",
"status": "confirmed",
"store_id": "b2d4e6f8-1a3c-4e5f-8a9b-0c1d2e3f4a5b",
"updated_at": "2026-11-03T10:15:05.000Z"
},
"event": "lead.confirmation_status_changed",
"event_id": "evt_5f1c9a0b2d3e4f5a6b7c8d9e",
"occurred_at": "2026-11-02T11:20:41.302Z",
"seller_id": "6a1c2f0e-3b7d-4c55-9e10-2f8a4b7c9d01",
"sequence": 4012
}Next steps
- Read every field of the order: Orders.
- Sync the catalogue: Products.
- Adopt COD Drop products for the seller: COD Drop.
- Before production: Go-live checklist.

