A practical developer guide for processing hundreds of SKUs — reading
from a CSV, looping over a product array, and calling the ListLoco
POST /localize endpoint for each one to produce
Amazon-Germany-compliant German copy with quality gates applied.
If you have a catalog of English-language Amazon listings that you want
to publish on Amazon.de, translating them one at a time
in a web form does not scale. This guide shows you how to drive
the ListLoco API in a bulk loop — reading SKUs from a
CSV file (or any in-memory array), calling
POST /localize for each listing, and writing the
structured JSON responses back for import into your catalog system.
Each API call applies the full Amazon DE compliance pipeline in a single request: title character-limit enforcement, banned keyword detection, required-attribute checking, model-number and unit preservation, and a back-translation quality gate. You get pass/fail status per listing alongside the localized copy, so failed SKUs can be flagged for review before they reach Amazon.
POST /localize
Every call to the ListLoco API goes through the RapidAPI gateway at
listloco.p.rapidapi.com. The request body is a JSON object
with the fields below. The same structure applies whether you are
processing one SKU or a thousand in a loop.
marketplace — always "amazon" for Amazon DE.sourceLang — source language code, e.g. "en".targetLang — target language code, e.g. "de".listing — object with the product fields:
title — product title (string, required).description — product description (string, optional).brand — brand name (string, optional).material, size, color, quantity — additional attributes (optional).dictionary — key/value translation hints for domain-specific terms (optional).glossary — { preserve: [] } to protect brand names or model numbers from translation (optional).
This script reads a CSV file where each row is one
product, calls the ListLoco API for every row, and prints the result.
Swap <YOUR_RAPIDAPI_KEY> with the key from your
RapidAPI dashboard.
import csv
import json
import requests
RAPIDAPI_KEY = "<YOUR_RAPIDAPI_KEY>"
API_URL = "https://listloco.p.rapidapi.com/localize"
HEADERS = {
"Content-Type": "application/json",
"X-RapidAPI-Key": RAPIDAPI_KEY,
"X-RapidAPI-Host": "listloco.p.rapidapi.com",
}
# CSV columns: sku, title, description, brand, material, size, color, quantity
def load_skus(csv_path):
with open(csv_path, newline="", encoding="utf-8") as f:
return list(csv.DictReader(f))
def localize_sku(row):
payload = {
"marketplace": "amazon",
"sourceLang": "en",
"targetLang": "de",
"listing": {
"title": row.get("title", ""),
"description": row.get("description", ""),
"brand": row.get("brand", ""),
"material": row.get("material", ""),
"size": row.get("size", ""),
"color": row.get("color", ""),
"quantity": int(row.get("quantity", 1)),
},
"dictionary": {},
}
response = requests.post(API_URL, json=payload, headers=HEADERS)
if response.status_code == 402:
data = response.json()
# Free tier quota exceeded — HTTP 402 QUOTA_EXCEEDED
raise RuntimeError(
f"Quota exceeded: {data.get('code')} — upgrade at {data.get('upgrade_url')}"
)
response.raise_for_status()
return response.json()
def main():
skus = load_skus("products.csv")
results = []
for row in skus:
try:
result = localize_sku(row)
entry = {
"sku": row.get("sku"),
"pass": result["pass"],
"violations": result["violations"],
"localized_title": result["localized"].get("title"),
}
results.append(entry)
status = "PASS" if result["pass"] else "FAIL"
print(f"[{status}] {row['sku']}: {result['localized'].get('title')}")
except RuntimeError as e:
print(f"[ERROR] {row.get('sku')}: {e}")
break # stop on quota error; upgrade and resume
# Write results to JSON for catalog import
with open("localized_output.json", "w", encoding="utf-8") as f:
json.dump(results, f, ensure_ascii=False, indent=2)
print(f"Done. {len(results)} SKU(s) processed.")
if __name__ == "__main__":
main()
The same pattern in Node.js using the native fetch API
(Node 18+) and the built-in fs/promises module for reading
a CSV file. Replace <YOUR_RAPIDAPI_KEY>
with your RapidAPI key.
import { readFile, writeFile } from "node:fs/promises";
const RAPIDAPI_KEY = "<YOUR_RAPIDAPI_KEY>";
const API_URL = "https://listloco.p.rapidapi.com/localize";
const HEADERS = {
"Content-Type": "application/json",
"X-RapidAPI-Key": RAPIDAPI_KEY,
"X-RapidAPI-Host": "listloco.p.rapidapi.com",
};
// Parse a CSV string into an array of objects (assumes first row is header).
function parseCsv(text) {
const [headerLine, ...rows] = text.trim().split("\n");
const keys = headerLine.split(",").map((k) => k.trim());
return rows.map((row) => {
const vals = row.split(",");
return Object.fromEntries(keys.map((k, i) => [k, (vals[i] || "").trim()]));
});
}
async function localizeSku(row) {
const body = {
marketplace: "amazon",
sourceLang: "en",
targetLang: "de",
listing: {
title: row.title || "",
description: row.description || "",
brand: row.brand || "",
material: row.material || "",
size: row.size || "",
color: row.color || "",
quantity: Number(row.quantity) || 1,
},
dictionary: {},
};
const res = await fetch(API_URL, {
method: "POST",
headers: HEADERS,
body: JSON.stringify(body),
});
if (res.status === 402) {
const data = await res.json();
// Free tier quota exceeded — HTTP 402 QUOTA_EXCEEDED
throw new Error(
`Quota exceeded (${data.code}). Upgrade your plan to continue: ${data.upgrade_url}`
);
}
if (!res.ok) {
const text = await res.text();
throw new Error(`API error ${res.status}: ${text}`);
}
return res.json();
}
async function main() {
const csv = await readFile("products.csv", "utf8");
const skus = parseCsv(csv);
const results = [];
for (const row of skus) {
try {
const result = await localizeSku(row);
const entry = {
sku: row.sku,
pass: result.pass,
violations: result.violations,
localizedTitle: result.localized?.title,
};
results.push(entry);
const status = result.pass ? "PASS" : "FAIL";
console.log(`[${status}] ${row.sku}: ${result.localized?.title}`);
} catch (err) {
console.error(`[ERROR] ${row.sku}: ${err.message}`);
if (err.message.includes("QUOTA_EXCEEDED")) break; // stop on quota; upgrade and resume
}
}
await writeFile("localized_output.json", JSON.stringify(results, null, 2), "utf8");
console.log(`Done. ${results.length} SKU(s) processed.`);
}
main();
The ListLoco Free plan includes 100 API calls per month at no cost. For a typical product catalog of even a few hundred SKUs, a single bulk run will exhaust the free quota before completing.
When the monthly quota is reached, the API returns HTTP 402 with a JSON body that includes:
code: "QUOTA_EXCEEDED"upgrade_url — a direct link to upgrade your plan on RapidAPIBoth code samples above already handle this: they catch the 402, print the upgrade URL, and stop the loop so you do not waste calls after the quota is exhausted. Resume from where you stopped after upgrading.
Bulk processing hundreds of SKUs requires a paid plan. See the pricing page for current plan limits and per-listing overage rates.
The code samples above expect a CSV with these column headers. All
fields except sku and title are optional but
recommended — missing required attributes may cause
requiredAttributes gate failures.
sku,title,description,brand,material,size,color,quantity
SKU-001,"Cordless Drill AB-1200 with 8.5 kg battery","Cordless drill AB-1200 with 8.5 kg battery and 2 m cable.",Bosch,Metall,M,blue,1
SKU-002,"Wireless Headphones XM-500 Noise Cancelling","XM-500 wireless headphones with 30 h battery life.",Sony,Plastic,Standard,black,1
SKU-003,"Stainless Steel Water Bottle 750 ml BPA-Free","Reusable 750 ml stainless steel bottle, BPA-free.",ThermoFlask,Stainless steel,750ml,silver,1
Ready to localize your full catalog for Amazon Germany? Subscribe on RapidAPI to get your API key — the free tier lets you test with up to 100 listings per month at no cost.
Subscribe on RapidAPI View pricing plans