Bulk Amazon DE Listing Localization Tutorial

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.

Who this tutorial is for

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.

API contract: 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.

Request body fields

Response shape

{ "localized": { "title": "Akku-Bohrschrauber AB-1200 mit 8,5 kg Akku und 2 m Kabel", "description": "Akku-Bohrschrauber AB-1200 mit einem 8,5 kg Akku und einem 2 m Kabel.", "brand": "Bosch", "material": "Metall", "size": "M", "color": "blau", "quantity": 1 }, "gates": { "titleLength": { "pass": true, "violations": [] }, "bannedWords": { "pass": true, "violations": [] }, "requiredAttributes": { "pass": true, "violations": [] }, "preservation": { "pass": true, "violations": [] }, "backTranslation": { "pass": true, "score": 0.04, "threshold": 0.3, "enforced": true } }, "violations": [], "pass": true }

Python bulk example (CSV input)

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.

Python
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()

Node.js bulk example (array / CSV input)

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.

Node.js
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();

Free tier quota and upgrading

Free tier: 100 listings per month

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:

{ "error": "Monthly listing quota exceeded.", "code": "QUOTA_EXCEEDED", "upgrade_url": "https://rapidapi.com/sakaiwork259601/api/listloco", "docs": "https://listloco.hayasaka.app/examples#error-quota-exceeded" }

Both 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.

Tip: To avoid quota surprises mid-run, process a small batch (5–10 SKUs) first to confirm your listings pass the quality gates, then run the full catalog in one sweep on a paid plan.

Sample CSV format

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
Not affiliated with or endorsed by Amazon. "Amazon" and "Amazon.de" are trademarks of Amazon.com, Inc. or its affiliates. ListLoco is an independent localization tool and is not sponsored, endorsed, authorized by, or otherwise affiliated with Amazon.