COD Drop catalogue and adoptions
Browse the Swift Dropshipping (COD Drop) catalogue, adopt products for the seller at their price, update or give them back, and sell them.
A creator publishes a product with a COD Drop price per country (what the reseller pays per delivered unit, in USD); a reseller adopts it with their own sale price, takes orders on it, and ColiSwift ships it. These endpoints are the seller’s own COD Drop screens, through the API: same filters, same visibility rules, same refusals and the same error codes.
- Browse:
GET /cod-drop/catalog(scopecatalogue:read, app enabled for the catalogue synchronisation — see access). Without it, pick products in ColiSwift’s own COD Drop screens. - Adopt:
POST /cod-drop/adoptionswith the sale price per country (scopecod_drop:write). - The adopted product now appears in
GET /productswith"adopted": true. - Sell: create orders whose line
referenceis the adoption’ssellerSku(or the creator’s reference). - Stay in sync:
adoption.created/adoption.updated/adoption.removedtell you when the adoption moves,product.changedwhen the product moves, andcod_drop.catalog_changedwhen the catalogue itself moves (events).
Who may use these endpoints
Two switches sit on top of the scopes. They are checked after the scope (a token without the scope still gets 403 INSUFFICIENT_SCOPE) and before the body is read.
| Switch | Endpoints | When off |
|---|---|---|
| Seller’s COD Drop access — opened or closed by ColiSwift for each seller (open from sign-up on the sandbox) | All five: GET /cod-drop/catalog, GET /cod-drop/catalog/{productId}, POST /cod-drop/adoptions, PUT and DELETE /cod-drop/adoptions/{productId} | 403 COD_DROP_ACCESS_CLOSED — the seller must ask their account manager to open it. |
| App’s COD Drop catalogue synchronisation — enabled by ColiSwift per app, off by default, never on a sandbox app | GET /cod-drop/catalog, GET /cod-drop/catalog/{productId} (and the cod_drop.catalog_changed event) | 403 COD_DROP_CATALOG_NOT_ENABLED — contact ColiSwift. Adoptions are not affected. |
{
"error": {
"message": "COD Drop access is closed for this seller's account. The seller must ask their account manager to open it.",
"code": "COD_DROP_ACCESS_CLOSED"
}
}{
"error": {
"message": "COD Drop catalogue synchronisation is not enabled for this application. Contact ColiSwift to enable it.",
"code": "COD_DROP_CATALOG_NOT_ENABLED"
}
}Closing a seller’s access does not undo anything: their existing adoptions stay, keep taking resale orders through POST /orders, and still appear in GET /products. The switch is read on every call, so it takes effect on the next one.
Browse the catalogue
/cod-drop/catalogNeeds the app’s catalogue synchronisation and the seller’s COD Drop access (access).
searchstringFree-text search.
categorystringProduct category.
badgestringCatalogue badge filter.
countrystring (2)One of the seller’s countries (else
403 COUNTRY_NOT_ALLOWED). Without it the catalogue is limited to all the seller’s countries.sortstringDefault
newest.newestcession_asccession_desc
cursor · limitOpaque cursor; default 50, max 100.
curl "https://coliswift.com/api/partner/v1/cod-drop/catalog?country=MA&sort=newest" \
-H "Authorization: Bearer $COLISWIFT_ACCESS_TOKEN"const res = await fetch('https://coliswift.com/api/partner/v1/cod-drop/catalog?country=MA&sort=newest', {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.COLISWIFT_ACCESS_TOKEN}`,
},
});
const data = await res.json();$ch = curl_init('https://coliswift.com/api/partner/v1/cod-drop/catalog?country=MA&sort=newest');
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/cod-drop/catalog",
headers={"Authorization": f"Bearer {os.environ['COLISWIFT_ACCESS_TOKEN']}"},
params={
"country": "MA",
"sort": "newest",
},
)
data = res.json(){
"data": [
{
"id": "3d4e5f6a-7b8c-4d9e-a0f1-b2c3d4e5f6a7",
"reference": null,
"label": "Sunset lamp",
"description": "Warm sunset light, USB powered.",
"category": "electronics",
"imageUrl": "https://cdn.example.com/lamp.jpg",
"imageUrls": [
"https://cdn.example.com/lamp.jpg"
],
"countryCodes": [
"MA"
],
"pricesByCountry": [
{
"countryCode": "MA",
"price": "6.0000",
"currency": "USD"
}
],
"variants": [
{
"id": "2b3c4d5e-6f7a-4b8c-9d0e-1f2a3b4c5d6e",
"label": "White",
"sku": null
}
],
"adopted": false,
"createdAt": "2026-10-28T12:00:00.000Z",
"updatedAt": "2026-11-01T09:00:00.000Z"
}
],
"nextCursor": null,
"hasMore": false
}The COD Drop product
idstringProduct id — the
productIdto adopt.referencestring | nullThe creator’s SKU —
nulluntil the seller adopts the product (adopted: false), as in ColiSwift’s COD Drop catalogue.label · descriptionstring · string | nullName and text.
categorystring | nullProduct category.
imageUrl · imageUrlsstring | null · string[]Main image and gallery.
countryCodesstring[]Countries where the seller can sell it.
pricesByCountry[]object[]countryCode,price,currency— the COD Drop price shown in ColiSwift’s COD Drop catalogue: what the seller pays per delivered unit in that country (4-decimal string,USD).variants[]object[]id,label,sku—skuisnulluntil the seller adopts the product.adoptedbooleanWhether this seller already adopted it.
createdAt · updatedAttimestamp
Private products appear only for sellers in their audience; the seller’s own products are never listed (a page may therefore be shorter than limit with hasMore: true).
One catalogue item
/cod-drop/catalog/{productId}Exactly the row the list would return for this seller, or 404 PRODUCT_NOT_FOUND when it is not (or no longer) in their adoptable catalogue — unpublished, deactivated, deleted, private without them, no shared country, or their own. This is what to re-read on cod_drop.catalog_changed: a 404 means « remove it ». Same access rules as the list.
Adopt a product
/cod-drop/adoptionsproductIdstringrequiredCatalogue item id.
prices[]object[], 1–20countryCode+salePrice(money string), one row per country, each country once. Recommended.salePricemoney stringFallback sale price. Required when
pricesis absent; defaults to the first row ofpricesotherwise.sellerSkustring ≤ 100 | nullThe seller’s own SKU for this product — what their store will put on order lines. Unique among their adoptions.
curl -X POST "https://coliswift.com/api/partner/v1/cod-drop/adoptions" \
-H "Authorization: Bearer $COLISWIFT_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"productId": "3d4e5f6a-7b8c-4d9e-a0f1-b2c3d4e5f6a7",
"prices": [
{
"countryCode": "MA",
"salePrice": "149.00"
}
],
"sellerSku": "MY-LAMP"
}'const res = await fetch('https://coliswift.com/api/partner/v1/cod-drop/adoptions', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.COLISWIFT_ACCESS_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"productId": "3d4e5f6a-7b8c-4d9e-a0f1-b2c3d4e5f6a7",
"prices": [
{
"countryCode": "MA",
"salePrice": "149.00"
}
],
"sellerSku": "MY-LAMP"
}),
});
const data = await res.json();$ch = curl_init('https://coliswift.com/api/partner/v1/cod-drop/adoptions');
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'
{
"productId": "3d4e5f6a-7b8c-4d9e-a0f1-b2c3d4e5f6a7",
"prices": [
{
"countryCode": "MA",
"salePrice": "149.00"
}
],
"sellerSku": "MY-LAMP"
}
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/cod-drop/adoptions",
headers={"Authorization": f"Bearer {os.environ['COLISWIFT_ACCESS_TOKEN']}"},
json={
"productId": "3d4e5f6a-7b8c-4d9e-a0f1-b2c3d4e5f6a7",
"prices": [
{
"countryCode": "MA",
"salePrice": "149.00",
},
],
"sellerSku": "MY-LAMP",
},
)
data = res.json(){
"id": "3d4e5f6a-7b8c-4d9e-a0f1-b2c3d4e5f6a7",
"reference": "CRE-LAMP-02",
"label": "Sunset lamp",
"description": "Warm sunset light, USB powered.",
"category": "electronics",
"imageUrl": "https://cdn.example.com/lamp.jpg",
"imageUrls": [
"https://cdn.example.com/lamp.jpg"
],
"countryCodes": [
"MA"
],
"pricesByCountry": [
{
"countryCode": "MA",
"price": "6.0000",
"currency": "USD"
}
],
"salePricesByCountry": [
{
"countryCode": "MA",
"price": "149.0000"
}
],
"variants": [
{
"id": "2b3c4d5e-6f7a-4b8c-9d0e-1f2a3b4c5d6e",
"label": "White",
"sku": "CRE-LAMP-02-W"
}
],
"adopted": true,
"createdAt": "2026-10-28T12:00:00.000Z",
"updatedAt": "2026-11-02T09:40:00.000Z"
}201 for a new adoption. A retry for a product already adopted answers 200 with "duplicate": true and applies the prices you sent. An adoption made through the API is shared with apps from the start; a new adoption fires adoption.created (reason adopted).
Errors
| HTTP | Code | Meaning |
|---|---|---|
| 404 | PRODUCT_NOT_FOUND | No such product. |
| 422 | NOT_COD_DROP | Not published to COD Drop. |
| 422 | CANNOT_ADOPT_OWN | The seller is the creator. |
| 422 | COD_DROP_PRICE_MISSING | The creator has not set a COD Drop price. |
| 403 | PRODUCT_PRIVATE_NOT_ALLOWED | Private product, seller not in its audience. |
| 403 | COD_DROP_NO_SHARED_COUNTRY | The creator and the seller have no country in common for this product. |
| 422 | COUNTRY_NOT_OPEN | A prices country is closed to resale for this product. |
| 422 | SALE_BELOW_CESSION | A sale price is lower than the COD Drop price. |
| 409 | SKU_CONFLICT | sellerSku already used by another adoption of the seller. |
| 403 | RESELLER_BLOCKED | The creator blocked this seller. |
| 403 | COD_DROP_ACCESS_CLOSED | The seller’s COD Drop access is closed (access). |
| 400 | VALIDATION_ERROR | Body shape, a number instead of a money string, a country twice in prices, neither salePrice nor prices. |
Update an adoption
/cod-drop/adoptions/{productId}Any of prices[], salePrice, sellerSku. A country not sent keeps its price. Answers 200 with the adopted product. 404 ADOPTION_NOT_FOUND when the seller has no adoption of this product or only a removed one (re-adopt with POST). Same price and SKU errors as adopting; 403 RESELLER_BLOCKED on a blocked adoption; 403 COD_DROP_ACCESS_CLOSED when the seller’s access is closed. A real change fires adoption.updated (price_changed, sku_changed).
curl -X PUT "https://coliswift.com/api/partner/v1/cod-drop/adoptions/3d4e5f6a-7b8c-4d9e-a0f1-b2c3d4e5f6a7" \
-H "Authorization: Bearer $COLISWIFT_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"prices": [
{
"countryCode": "MA",
"salePrice": "159.00"
}
]
}'const res = await fetch('https://coliswift.com/api/partner/v1/cod-drop/adoptions/3d4e5f6a-7b8c-4d9e-a0f1-b2c3d4e5f6a7', {
method: 'PUT',
headers: {
Authorization: `Bearer ${process.env.COLISWIFT_ACCESS_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"prices": [
{
"countryCode": "MA",
"salePrice": "159.00"
}
]
}),
});
const data = await res.json();$ch = curl_init('https://coliswift.com/api/partner/v1/cod-drop/adoptions/3d4e5f6a-7b8c-4d9e-a0f1-b2c3d4e5f6a7');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'PUT',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('COLISWIFT_ACCESS_TOKEN'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => <<<'JSON'
{
"prices": [
{
"countryCode": "MA",
"salePrice": "159.00"
}
]
}
JSON,
]);
$data = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);import os, requests
res = requests.put(
"https://coliswift.com/api/partner/v1/cod-drop/adoptions/3d4e5f6a-7b8c-4d9e-a0f1-b2c3d4e5f6a7",
headers={"Authorization": f"Bearer {os.environ['COLISWIFT_ACCESS_TOKEN']}"},
json={
"prices": [
{
"countryCode": "MA",
"salePrice": "159.00",
},
],
},
)
data = res.json()Give a product back
/cod-drop/adoptions/{productId}204 No Content. 404 NOT_ADOPTED when there is nothing to give back. The adoption is marked removed (orders already taken keep pointing at it) and you receive adoption.removed (reason removed, status: "removed"). The product leaves GET /products.
curl -X DELETE "https://coliswift.com/api/partner/v1/cod-drop/adoptions/3d4e5f6a-7b8c-4d9e-a0f1-b2c3d4e5f6a7" \
-H "Authorization: Bearer $COLISWIFT_ACCESS_TOKEN"const res = await fetch('https://coliswift.com/api/partner/v1/cod-drop/adoptions/3d4e5f6a-7b8c-4d9e-a0f1-b2c3d4e5f6a7', {
method: 'DELETE',
headers: {
Authorization: `Bearer ${process.env.COLISWIFT_ACCESS_TOKEN}`,
},
});
// 204 No Content on success$ch = curl_init('https://coliswift.com/api/partner/v1/cod-drop/adoptions/3d4e5f6a-7b8c-4d9e-a0f1-b2c3d4e5f6a7');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'DELETE',
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.delete(
"https://coliswift.com/api/partner/v1/cod-drop/adoptions/3d4e5f6a-7b8c-4d9e-a0f1-b2c3d4e5f6a7",
headers={"Authorization": f"Bearer {os.environ['COLISWIFT_ACCESS_TOKEN']}"},
)
# 204 No Content on successThe adopted product
In GET /products, GET /products/{id} and the adoption answers, an adopted product is the COD Drop product above (the creator’s id and reference — the ids resale orders name) with the seller’s own sale price:
{
"id": "3d4e5f6a-7b8c-4d9e-a0f1-b2c3d4e5f6a7",
"reference": "CRE-LAMP-02",
"label": "Sunset lamp",
"description": "Warm sunset light, USB powered.",
"category": "electronics",
"imageUrl": "https://cdn.example.com/lamp.jpg",
"imageUrls": [
"https://cdn.example.com/lamp.jpg"
],
"countryCodes": [
"MA"
],
"pricesByCountry": [
{
"countryCode": "MA",
"price": "6.0000",
"currency": "USD"
}
],
"salePricesByCountry": [
{
"countryCode": "MA",
"price": "149.0000"
}
],
"variants": [
{
"id": "2b3c4d5e-6f7a-4b8c-9d0e-1f2a3b4c5d6e",
"label": "White",
"sku": "CRE-LAMP-02-W"
}
],
"adopted": true,
"createdAt": "2026-10-28T12:00:00.000Z",
"updatedAt": "2026-11-02T09:40:00.000Z"
}pricesByCountry[]object[]The COD Drop price per country (
countryCode,price,currency: "USD"), for each country where the seller can sell it.salePricesByCountry[]object[]countryCode,price— the seller’s own sale price there (local currency): the per-country price set on the adoption, else its singlesalePrice.adoptedtruePresent only on adopted products — absent on the seller’s own products.

