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
{
"texts": ["Hello—world"]
}{
"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"]) # 2Node.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); // 2Error Codes
| Status | Meaning |
|---|---|
| 200 | Success. Results array returned. Individual items may include a text_too_long error if that item exceeded 50,000 characters, but the overall request succeeded. |
| 400 | Invalid 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. |
| 401 | Missing or invalid API key. Check that your Authorization header uses the Bearer zt_live_... format and that the key has not been revoked. |
| 402 | Plan 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. |
| 429 | IP rate limit exceeded. Your IP has sent more than 60 requests in the last minute. Wait and retry. |
| 500 | Server 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.
| Plan | Monthly cleanings | Max batch size | Per-minute limit (per IP) |
|---|---|---|---|
| Free | No API access | No API access | 60 |
| Starter | 1,000 | 1,000 | 60 |
| Pro | 10,000 | 1,000 | 60 |