API Documentation

Programmatically clean AI-generated text from any script, app, or workflow.

Not a developer? Set this up with AI in 5 minutes.

Copy our setup prompt, paste it into ChatGPT or Claude, and the AI will walk you through connecting ZeroTraceAI to your tool step by step. No code knowledge required.

I want to use ZeroTraceAI to clean AI-generated text in my workflow. ZeroTraceAI is an API at https://www.zerotraceai.com that removes hidden Unicode characters, em-dashes, smart quotes, and AI fingerprints from text.

Please help me set this up step by step. Here's what you need to know:
- The API endpoint is: POST https://www.zerotraceai.com/api/v1/clean
- I need to use Bearer token authentication with my API key (I'll get this from zerotraceai.com/dashboard)
- The request body is: { "texts": ["my text here"] } (always an array, even for single texts)
- The response is: { "results": [{ "cleaned_text": "...", "modifications_count": N }], "total_processed": N }
- Each text in my batch counts as 1 against my monthly quota
- Maximum 1000 texts per request, max 500,000 total characters

I want to integrate this with [TELL ME WHICH TOOL: Clay, n8n, Make, Zapier, custom code, or another tool] to clean [TELL ME WHAT: AI-generated cold emails, content articles, social posts, etc.]

Walk me through this one step at a time, ask me questions if you need clarification about my setup, and give me the exact configuration values I need to enter into my tool.

Quick Start

AI-generated text often carries invisible markers that trip spam filters, hurt deliverability, and create artifacts readers find off-putting. The ZeroTraceAI API strips those hidden fingerprints in a single request, no rewriting, no word count changes, no hassle. Whether you're sending cold outreach at scale, powering a writing app, or shipping content that needs to read cleanly, integrate once and every piece of text comes out polished.

The API accepts batches of up to 1,000 texts per request. Send one text or a thousand in the same call. Get your API key at /dashboard.

What Gets Cleaned

The API detects and normalizes three categories of hidden artifacts common in AI-generated text.

  • Invisible Unicode characters. Zero-width spaces, zero-width non-joiners, zero-width joiners, byte order marks, and 16 other hidden codepoints that are invisible in editors but detectable by filters.
  • Lookalike punctuation. Fullwidth periods, fancy curly quotes, and non-standard dash characters (en dashes, em dashes) replaced with their plain ASCII equivalents.
  • Directional formatting marks. Left-to-right and right-to-left markers inserted by some models to control rendering direction.

Before and after example

Request body
{
  "texts": ["Hello—world"]
}
Response (200)
{
  "results": [
    { "cleaned_text": "Hello-world", "modifications_count": 1 }
  ],
  "total_processed": 1
}

Authentication

All requests require a Bearer token in the Authorization header. Generate your key at /dashboard.

Authorization: Bearer zt_live_YOUR_KEY_HERE

POST /api/v1/clean

Base URL: https://www.zerotraceai.com

Request body

{
  "texts": [
    "Hi Sarah, I noticed your company is hiring SDRs...",
    "Hello Marcus, saw your recent post about deliverability..."
  ]
}
  • Content-Type: application/json required
  • texts must be a non-empty array of strings
  • Maximum 1,000 texts per request
  • Maximum 50,000 characters per individual text
  • Maximum 500,000 characters total across all texts
  • Each text counts as 1 against your monthly quota

Response body (200)

{
  "results": [
    {
      "cleaned_text": "Hi Sarah...",
      "modifications_count": 3
    },
    {
      "cleaned_text": "Hello Marcus...",
      "modifications_count": 5
    }
  ],
  "total_processed": 2
}
  • results: array, one item per input text
  • cleaned_text: the normalized text string
  • modifications_count: number of changes made
  • total_processed: number of texts in the batch

Per-item errors

If an individual text exceeds 50,000 characters, that item returns an error object in the results array rather than failing the entire request. Other texts in the same batch are still processed and returned normally.

{
  "results": [
    { "cleaned_text": "OK text", "modifications_count": 1 },
    { "error": "text_too_long", "text_index": 1 }
  ],
  "total_processed": 2
}

Code Examples

curl

curl -X POST https://www.zerotraceai.com/api/v1/clean \
  -H "Authorization: Bearer zt_live_YOUR_KEY_HERE" \
  -H "Content-Type: application/json" \
  -d '{
    "texts": [
      "Hi Sarah, I noticed your company is hiring SDRs. Wanted to reach out because we help teams like yours scale outbound without burning their reputation.",
      "Hello Marcus, saw your recent post about cold email deliverability. We built a tool that strips the hidden AI markers that tank inbox placement."
    ]
  }'

Python

import requests

response = requests.post(
    "https://www.zerotraceai.com/api/v1/clean",
    headers={"Authorization": "Bearer zt_live_YOUR_KEY_HERE"},
    json={
        "texts": [
            "Hi Sarah, I noticed your company is hiring SDRs. Wanted to reach out because we help teams like yours scale outbound without burning their reputation.",
            "Hello Marcus, saw your recent post about cold email deliverability. We built a tool that strips the hidden AI markers that tank inbox placement.",
        ]
    },
)

data = response.json()
for item in data["results"]:
    print(item["cleaned_text"])        # cleaned email text
    print(item["modifications_count"]) # 3 / 5
print(data["total_processed"])         # 2

Node.js

const response = await fetch("https://www.zerotraceai.com/api/v1/clean", {
  method: "POST",
  headers: {
    "Authorization": "Bearer zt_live_YOUR_KEY_HERE",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    texts: [
      "Hi Sarah, I noticed your company is hiring SDRs. Wanted to reach out because we help teams like yours scale outbound without burning their reputation.",
      "Hello Marcus, saw your recent post about cold email deliverability. We built a tool that strips the hidden AI markers that tank inbox placement.",
    ],
  }),
});

const data = await response.json();
data.results.forEach((item) => {
  console.log(item.cleaned_text);        // cleaned email text
  console.log(item.modifications_count); // 3 / 5
});
console.log(data.total_processed);       // 2

Error Codes

StatusMeaning
200Success. Results array returned. Individual items may include a text_too_long error if that item exceeded 50,000 characters, but the overall request succeeded.
400Invalid request. Check that texts is a non-empty array of strings. Arrays over 1,000 items or totalling over 500,000 characters also return 400. Sending the old { text } format returns 400 with a migration guide.
401Missing or invalid API key. Check that your Authorization header uses the Bearer zt_live_... format and that the key has not been revoked.
402Plan limit reached. Either the free plan has no API access, the free trial has expired or been exhausted, or the batch size exceeds your remaining quota. Upgrade at /pricing.
429IP rate limit exceeded. Your IP has sent more than 60 requests in the last minute. Wait and retry.
500Server error. The request was received but could not be completed. Try again shortly.

Rate Limits

All endpoints enforce a limit of 60 requests per minute per IP address. Requests that exceed this threshold receive a 429 response and are not counted against your monthly quota.

In addition to the per-minute IP limit, each plan carries a monthly cleaning allowance. Each text in a batch counts as 1 against your quota: a single request with 50 texts consumes 50 quota units. The Starter plan includes 1,000 cleanings per month. The Pro plan includes 10,000 cleanings per month. Monthly quotas reset on the 1st of each calendar month. Free plan accounts do not have API access and will receive a 402 response on every request.

PlanMonthly cleaningsMax batch sizePer-minute limit (per IP)
FreeNo API accessNo API access60
Starter1,0001,00060
Pro10,0001,00060