List Existing Country Sales
const options = {method: 'GET', headers: {'x-organization-id': '<x-organization-id>'}};
fetch('https://api.dcycle.io/v1/sold-products/existing-country-sales', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.dcycle.io/v1/sold-products/existing-country-sales"
headers = {"x-organization-id": "<x-organization-id>"}
response = requests.get(url, headers=headers)
print(response.text)curl --request GET \
--url https://api.dcycle.io/v1/sold-products/existing-country-sales \
--header 'x-organization-id: <x-organization-id>'{
"items": {
"organization_id": "<string>",
"items": {
"product_name": "<string>",
"country_name": "<string>",
"period_start_date": "<string>",
"period_end_date": "<string>"
}
}
}List Existing Country Sales
The product-country combinations already recorded for a period, so a CSV upload can skip duplicates instead of creating them
GET
/
v1
/
sold-products
/
existing-country-sales
List Existing Country Sales
const options = {method: 'GET', headers: {'x-organization-id': '<x-organization-id>'}};
fetch('https://api.dcycle.io/v1/sold-products/existing-country-sales', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.dcycle.io/v1/sold-products/existing-country-sales"
headers = {"x-organization-id": "<x-organization-id>"}
response = requests.get(url, headers=headers)
print(response.text)curl --request GET \
--url https://api.dcycle.io/v1/sold-products/existing-country-sales \
--header 'x-organization-id: <x-organization-id>'{
"items": {
"organization_id": "<string>",
"items": {
"product_name": "<string>",
"country_name": "<string>",
"period_start_date": "<string>",
"period_end_date": "<string>"
}
}
}← Sold Products API
List the product-and-country combinations that already have sales recorded in a date range. This exists for deduplication: before uploading a CSV of country sales, call it to find out which rows would land on top of data that is already there.
An organization with no matching sales simply does not appear in
This endpoint descends into child organizations; Check Period Overlap does not. Two endpoints in the same group, opposite scopes.The response covers the organization in the header and every child organization below it, which is why results come grouped by
organization_id. A combination reported here may belong to a subsidiary, not to the organization you queried.Request
Headers
string
required
UUID of the organization to start from. Its children are included automatically.Format: UUID
string
Your API key.
Query Parameters
string
required
Start of the range. Periods overlapping this range are returned — a period is not required to sit entirely inside it.Format:
YYYY-MM-DDstring
required
End of the range.Format:
YYYY-MM-DDResponse
The response is nested two levels deep: an outeritems grouped by organization, each holding its own items of combinations.
array[object]
One entry per organization that has matching sales.
Show Organization Group
Show Organization Group
string
UUID of the organization these combinations belong to — the one from your header, or one of its children.
Combinations are named, not identified. Rows come back as
product_name and country_name strings rather than ids, because the point is to compare them against the text in a CSV about to be uploaded. Match on the same casing and spelling your file uses.Example
curl -X GET "https://api.dcycle.io/v1/sold-products/existing-country-sales?start_date=2026-01-01&end_date=2026-12-31" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-organization-id: YOUR_ORGANIZATION_ID"
import requests
HEADERS = {
"x-api-key": "YOUR_API_KEY",
"x-organization-id": "YOUR_ORGANIZATION_ID",
}
data = requests.get(
"https://api.dcycle.io/v1/sold-products/existing-country-sales",
headers=HEADERS,
params={"start_date": "2026-01-01", "end_date": "2026-12-31"},
timeout=30,
).json()
# Flatten the two levels into a set you can test rows against
already = {
(item["product_name"], item["country_name"])
for group in data["items"]
for item in group["items"]
}
rows_to_upload = [r for r in csv_rows if (r["product"], r["country"]) not in already]
const params = new URLSearchParams({
start_date: "2026-01-01",
end_date: "2026-12-31",
});
const response = await fetch(
`https://api.dcycle.io/v1/sold-products/existing-country-sales?${params}`,
{
headers: {
"x-api-key": "YOUR_API_KEY",
"x-organization-id": "YOUR_ORGANIZATION_ID",
},
},
);
const data = await response.json();
const already = new Set(
data.items.flatMap((group) =>
group.items.map((i) => `${i.product_name}|${i.country_name}`),
),
);
Successful Response
Returns200 OK.
{
"items": [
{
"organization_id": "a8315ef3-dd50-43f8-b7ce-d839e68d51fa",
"items": [
{
"product_name": "Recycled paper ream",
"country_name": "Spain",
"period_start_date": "2026-01-01",
"period_end_date": "2026-06-30"
}
]
}
]
}
items — there is no empty group for it.
Common Errors
422 Unprocessable Entity
Cause:start_date or end_date is missing. Both are required.
{
"detail": [
{
"loc": ["query", "start_date"],
"msg": "field required",
"type": "value_error.missing"
}
]
}
Use Cases
Skip duplicate rows instead of creating them
Before uploading country sales in bulk, fetch the combinations that already exist for the period and filter your file against them. Uploading a combination that is already recorded adds sales on top of sales, and the resulting total looks plausible — which is what makes it hard to notice later.Understand a holding before loading into it
Because the response descends into children, it also answers “has any subsidiary already reported this product for this country?”. That is worth checking before a parent-level upload, since the duplicate would otherwise land in a different organization from the one you are working in.Related Endpoints
Check Period Overlap
The other pre-upload check — single organization only
Country Sales
Record the sales themselves
List Periods
The periods these combinations sit in
Sold Products API
Everything the Sold Products API covers
Was this page helpful?