DocsPipelines: processing data in bulk

Pipelines: processing data in bulk

Use casesAdvanced25 min

You'll end up with a script that runs 10,000 reviews from a CSV through an AI model and writes each one's tone, topic and summary to a new spreadsheet.

You need: a separate fetch_... key (create one), a balance — $1 covers 10,000 reviews on DeepSeek (top up), Python 3.10+, a CSV with the columns id and text.

  1. 1
    Put a limit on the key

    Dashboard → API keys: set a daily spend limit (say, $3) and allow only the models you need. The limit stops the script if it goes in circles.

  2. 2
    Install the library and set the key
    bash
    pip install openai
    export ZUKKO_API_KEY="fetch_your_key"

    Windows (PowerShell): $env:ZUKKO_API_KEY="fetch_your_key".

  3. 3
    Save the script

    File classify_reviews.py, next to reviews.csv:

    classify_reviews.py
    """
    Classify customer reviews from a CSV file through the Zukko API.
    
    Run:
        pip install openai
        export ZUKKO_API_KEY="fetch_..."
        python classify_reviews.py reviews.csv results.csv --limit 50   # a trial run first
        python classify_reviews.py reviews.csv results.csv              # then everything
    
    The input CSV needs the columns id and text. You can stop the script and run it
    again: rows already present in results.csv are skipped.
    """
    import argparse
    import asyncio
  4. 4
    Test on 50 rows
    bash
    python classify_reviews.py reviews.csv results.csv --limit 50

    Check results.csv by eye. Multiply the amount spent by 200 to get the price of all 10,000 rows.

  5. 5
    Run the whole file
    bash
    python classify_reviews.py reviews.csv results.csv

    Finished rows are skipped. If it stops, run the same command again.

1Which model to use

Change the model in MODEL. Pick by trial: the same 50 rows through two candidates.

ModelPrice per 1M tokens, input / outputWhen
deepseek-v4.1-flash$0.03 / $0.10the default
claude-haiku-5-5$0.05 / $0.20DeepSeek failed the trial
claude-sonnet-5-standard$0.2 per any tokenyou need Sonnet's strength; no cache discount, but cheaper than claude-sonnet-5-5 here
claude-sonnet-5-5$0.4 / $2tricky labeling

2No code: n8n and Make

  1. 1
    Set up the HTTP request

    n8n: HTTP Request node, Make: HTTP → Make a request. POST to https://api.zukko.pro/v1/chat/completions. Headers: Authorization: Bearer fetch_your_key, Content-Type: application/json, Idempotency-Key — for example reviews-v1- plus the row id.

  2. 2
    Set the request body
    json
    {
      "model": "deepseek-v4.1-flash",
      "response_format": { "type": "json_object" },
      "max_tokens": 200,
      "messages": [
        { "role": "system", "content": "You classify customer reviews. Reply with JSON only: {\"sentiment\": \"positive|neutral|negative\", \"topic\": \"delivery|quality|price|support|other\", \"summary\": \"gist in up to 15 words\"}" },
        { "role": "user", "content": "REVIEW TEXT" }
      ]
    }

    Replace REVIEW TEXT with the sheet field. In n8n use JSON.stringify(...), or a quote mark in a review breaks the JSON.

  3. 3
    Parse the answer

    choices[0].message.content is a string with JSON. Make: JSON → Parse JSON, n8n: a Code or Edit Fields node.

  4. 4
    Turn on retries

    Retry on error in the node settings, batches of 5–10 rows, a spend limit on the key.

3If it doesn't work

What you seeWhat to do
402 insufficient_balanceTop up and run again — finished rows are skipped
429 key_daily_limit_reachedYour key limit kicked in. Raise it or wait for 00:00 UTC
Many 429 without a key-limit codeLower CONCURRENCY to 5
422 idempotency_conflictYou changed the prompt — bump PROMPT_VERSION
Frequent "bad JSON"Use claude-haiku-5-5 or a strict schema
KeyError: 'id' or 'text'Rename the columns in the first row of the CSV
403 model_not_allowed_for_keyAdd the model in the key settings
Pipelines: processing data in bulk · Zukko Docs