Batch Operations¶
Submit and manage batch translation jobs for files and structured data.
POST /v1/jobs/batch-file¶
Upload multiple files for translation in a single request. Each file becomes a separate job grouped under a shared batch_id.
Authentication
Header: X-API-Key: your_api_key
Content-Type: multipart/form-data
Status: 202 Accepted
Form Fields¶
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
files |
file[] |
yes | -- | One or more files to translate. |
source_lang |
string |
yes | -- | BCP-47 source language code. |
target_lang |
string |
yes | -- | BCP-47 target language code. |
briefing_json |
string (JSON) |
no | null |
JSON-encoded translation options (shared across all files). |
Response (202)¶
{
"batch_id": "batch_550e8400-...",
"job_ids": [
"550e8400-e29b-41d4-a716-446655440001",
"550e8400-e29b-41d4-a716-446655440002",
"550e8400-e29b-41d4-a716-446655440003"
],
"total_jobs": 3,
"status": "queued"
}
Examples¶
import requests
files = [
("files", ("brochure_de.docx", open("brochure_de.docx", "rb"))),
("files", ("datasheet_de.xlsx", open("datasheet_de.xlsx", "rb"))),
("files", ("manual_de.pdf", open("manual_de.pdf", "rb"))),
]
response = requests.post(
"https://app.falara.io/v1/jobs/batch-file",
headers={"X-API-Key": FALARA_API_KEY},
files=files,
data={
"source_lang": "de",
"target_lang": "en",
"briefing_json": '{"domain":"technical","project_name":"Product Launch"}',
},
)
print(response.json())
const formData = new FormData();
formData.append("files", brochureBlob, "brochure_de.docx");
formData.append("files", datasheetBlob, "datasheet_de.xlsx");
formData.append("files", manualBlob, "manual_de.pdf");
formData.append("source_lang", "de");
formData.append("target_lang", "en");
formData.append(
"briefing_json",
JSON.stringify({ domain: "technical", project_name: "Product Launch" })
);
const response = await fetch("https://app.falara.io/v1/jobs/batch-file", {
method: "POST",
headers: { "X-API-Key": FALARA_API_KEY },
body: formData,
});
const data = await response.json();
console.log(data);
Errors¶
| Status | Description |
|---|---|
401 |
Invalid or missing API key. |
422 |
Validation error (unsupported format, missing fields). |
429 |
Rate limit or word quota exceeded. |
GET /v1/jobs/batch/{batch_id}¶
Get the aggregated status of all jobs in a batch.
Authentication
Header: X-API-Key: your_api_key
Status: 200 OK
Query Parameters¶
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
limit |
int |
no | 20 |
Number of jobs to return per page. |
cursor |
string |
no | null |
Pagination cursor from a previous response. |
Response¶
{
"batch_id": "b1c2d3e4-...",
"status": "processing",
"source_language": "de",
"target_languages": ["en", "fr"],
"completed": 1,
"total": 4,
"total_cost_eur": 0.14,
"data": [
{
"job_id": "550e8400-...",
"filename": "brochure.docx",
"status": "completed",
"target_language": "en",
"qa_score": 94.5
}
],
"pagination": {
"cursor": "eyJ...",
"has_more": true
}
}
Batch Status Values¶
| Status | Description |
|---|---|
processing |
At least one job is still running. |
completed |
All jobs reached completed or completed_with_blocks. |
partial |
All jobs are terminal, but some failed or need review. |
Examples¶
Errors¶
| Status | Description |
|---|---|
401 |
Invalid or missing API key. |
404 |
Batch not found. |
GET /v1/jobs/batch/{batch_id}/download¶
Download all completed translations from a batch as a ZIP archive.
Authentication
Header: X-API-Key: your_api_key
Status: 200 OK
Content-Type: application/zip
Query Parameters¶
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
structure |
"folders" | "suffix" |
no | "folders" |
ZIP layout for multi-language batches. |
ZIP Layouts¶
folders (default): Files organized by target language in subdirectories.
batch_b1c2.zip
├── manifest.json
├── en/
│ └── translated_brochure.docx
└── fr/
└── translated_brochure.docx
suffix: Files placed flat with a language suffix appended to the filename.
Every ZIP includes a manifest.json with job metadata.
Partial Batches
If some jobs in the batch are still processing, only completed files are included. The response header X-Falara-Batch-Complete indicates whether all jobs are done (true / false).
Examples¶
import requests
response = requests.get(
f"https://app.falara.io/v1/jobs/batch/{batch_id}/download",
headers={"X-API-Key": FALARA_API_KEY},
params={"structure": "folders"},
)
with open("translations.zip", "wb") as f:
f.write(response.content)
batch_complete = response.headers.get("X-Falara-Batch-Complete")
print(f"All jobs complete: {batch_complete}")
const response = await fetch(
`https://app.falara.io/v1/jobs/batch/${batchId}/download?structure=folders`,
{ headers: { "X-API-Key": FALARA_API_KEY } }
);
const blob = await response.blob();
const batchComplete = response.headers.get("X-Falara-Batch-Complete");
console.log(`All jobs complete: ${batchComplete}`);
Errors¶
| Status | Description |
|---|---|
401 |
Invalid or missing API key. |
404 |
Batch not found. |
409 |
No completed file jobs in this batch yet. |
POST /v1/jobs/batch-csv¶
Submit a CSV file for batch processing using a Structure Template (Creation Mode).
Authentication
Header: X-API-Key: your_api_key
Content-Type: multipart/form-data
Status: 202 Accepted (or 200 OK with dry_run=true)
Form Fields¶
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
file |
file |
yes | -- | CSV file (UTF-8 encoded). |
structure_template_id |
string |
yes | -- | Template ID or slug defining the output structure. |
source_lang |
string |
yes | -- | BCP-47 source language code. |
target_lang |
string |
yes | -- | BCP-47 target language code. |
mapping_id |
string |
no | null |
CSV column mapping ID. If omitted, columns are auto-detected. |
Query Parameters¶
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
dry_run |
boolean |
no | false |
Set to true to preview without creating jobs. |
Response (202 -- Creation)¶
{
"batch_id": "batch_550e8400-...",
"total_rows": 50,
"jobs_created": 50,
"job_ids": [
"550e8400-e29b-41d4-a716-446655440001",
"550e8400-e29b-41d4-a716-446655440002"
]
}
Response (200 -- Dry Run)¶
{
"total_rows": 50,
"sample_products": [
{
"row": 1,
"source_fields": {
"title": "Ergonomischer Bürostuhl",
"description": "Höhenverstellbar mit Lendenwirbelstütze."
}
}
],
"template_fields": [
{ "field": "title", "max_length": 150, "required": true },
{ "field": "description", "max_length": 5000, "required": true }
]
}
Examples¶
# Dry run (preview)
curl -X POST "https://app.falara.io/v1/jobs/batch-csv?dry_run=true" \
-H "X-API-Key: $FALARA_API_KEY" \
-F "file=@products.csv" \
-F "structure_template_id=amazon-listing" \
-F "source_lang=de" \
-F "target_lang=en"
# Create jobs
curl -X POST https://app.falara.io/v1/jobs/batch-csv \
-H "X-API-Key: $FALARA_API_KEY" \
-F "file=@products.csv" \
-F "structure_template_id=amazon-listing" \
-F "source_lang=de" \
-F "target_lang=en" \
-F "mapping_id=map_abc123"
import requests
# Dry run
with open("products.csv", "rb") as f:
response = requests.post(
"https://app.falara.io/v1/jobs/batch-csv",
params={"dry_run": "true"},
headers={"X-API-Key": FALARA_API_KEY},
files={"file": ("products.csv", f)},
data={
"structure_template_id": "amazon-listing",
"source_lang": "de",
"target_lang": "en",
},
)
preview = response.json()
print(f"Rows: {preview['total_rows']}")
# Create jobs
with open("products.csv", "rb") as f:
response = requests.post(
"https://app.falara.io/v1/jobs/batch-csv",
headers={"X-API-Key": FALARA_API_KEY},
files={"file": ("products.csv", f)},
data={
"structure_template_id": "amazon-listing",
"source_lang": "de",
"target_lang": "en",
"mapping_id": "map_abc123",
},
)
print(response.json())
// Dry run
const formData = new FormData();
formData.append("file", csvBlob, "products.csv");
formData.append("structure_template_id", "amazon-listing");
formData.append("source_lang", "de");
formData.append("target_lang", "en");
const preview = await fetch(
"https://app.falara.io/v1/jobs/batch-csv?dry_run=true",
{
method: "POST",
headers: { "X-API-Key": FALARA_API_KEY },
body: formData,
}
);
console.log(await preview.json());
// Create jobs
formData.append("mapping_id", "map_abc123");
const response = await fetch("https://app.falara.io/v1/jobs/batch-csv", {
method: "POST",
headers: { "X-API-Key": FALARA_API_KEY },
body: formData,
});
console.log(await response.json());
Errors¶
| Status | Description |
|---|---|
401 |
Invalid or missing API key. |
404 |
Structure template not found. |
422 |
Validation error (invalid CSV, missing required columns). |
429 |
Rate limit or word quota exceeded. |
POST /v1/jobs/batch-content¶
Submit structured JSON data for batch content creation using a Structure Template. Ideal for API integrations, Shopify apps, and other connectors that send structured product data.
Authentication
Header: X-API-Key: your_api_key
Content-Type: application/json
Status: 202 Accepted
Request Body¶
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
structure_template_id |
string |
yes | -- | Template ID or slug defining the output structure. |
source_lang |
string |
yes | -- | BCP-47 source language code. |
items |
array |
yes | -- | 1–5,000 items to process. |
items[].data |
object |
yes | -- | Key-value pairs (like a CSV row). Must not be empty. |
items[].metadata |
object |
no | null |
Arbitrary JSON (max 4 KB). Stored on the job and returned unchanged in the result. |
smart_mode |
boolean |
no | false |
Auto-map all columns as product data. Requires Starter plan or higher. |
column_map |
object |
no | null |
Manual mapping {data_key: target_field}. Ignored when smart_mode is true. |
project_name |
string |
no | null |
Project label (max 100 characters). |
glossary_id |
string |
no | null |
Glossary ID to apply to all items in the batch. |
glossary_ids |
string[] |
no | null |
Multiple glossary IDs to apply (combined). |
Request Example¶
{
"structure_template_id": "product_short",
"source_lang": "de-DE",
"smart_mode": true,
"project_name": "Shopify Import March",
"items": [
{
"data": { "title": "Taucheruhr", "sku": "SKU-123", "material": "Edelstahl" },
"metadata": { "resource_id": "gid://shopify/Product/123", "shop": "myshop" }
},
{
"data": { "title": "Lederuhr", "sku": "SKU-456" },
"metadata": { "resource_id": "gid://shopify/Product/456" }
}
]
}
Response (202)¶
{
"batch_id": "c9c851ae-03f3-4748-af1d-6859d9c5c79c",
"total_items": 2,
"jobs_created": 2,
"job_ids": [
"c118d515-944a-49c7-991e-761a43b4b97c",
"9567d0d5-5846-4067-971a-9b0a3aeda629"
]
}
Metadata Passthrough
The metadata object for each item is stored on the job and returned in GET /v1/jobs/{job_id}/result as the item_metadata field. Use this to store external IDs (e.g., Shopify product GIDs) so you can map results back to source records.
Validation¶
All items are validated before any jobs are created. If validation fails, the entire request is rejected with all errors listed (up to 100):
{
"detail": "Validation failed for 2 items",
"errors": [
{ "index": 3, "field": "item[3].data", "message": "must be a non-empty object" },
{ "index": 7, "field": "item[7].metadata", "message": "exceeds 4KB limit" }
]
}
Examples¶
curl -X POST https://app.falara.io/api/v1/jobs/batch-content \
-H "X-API-Key: $FALARA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"structure_template_id": "product_short",
"source_lang": "de-DE",
"smart_mode": true,
"items": [
{"data": {"title": "Taucheruhr", "sku": "SKU-1", "material": "Edelstahl"}},
{"data": {"title": "Lederuhr", "sku": "SKU-2", "material": "Leder"}}
]
}'
import requests
response = requests.post(
"https://app.falara.io/api/v1/jobs/batch-content",
headers={
"X-API-Key": FALARA_API_KEY,
"Content-Type": "application/json",
},
json={
"structure_template_id": "product_short",
"source_lang": "de-DE",
"smart_mode": True,
"items": [
{"data": {"title": "Taucheruhr", "sku": "SKU-1"}, "metadata": {"id": "123"}},
{"data": {"title": "Lederuhr", "sku": "SKU-2"}, "metadata": {"id": "456"}},
],
},
)
batch = response.json()
print(f"Batch {batch['batch_id']}: {batch['jobs_created']} jobs created")
const response = await fetch("https://app.falara.io/api/v1/jobs/batch-content", {
method: "POST",
headers: {
"X-API-Key": FALARA_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
structure_template_id: "product_short",
source_lang: "de-DE",
smart_mode: true,
items: [
{ data: { title: "Taucheruhr", sku: "SKU-1" }, metadata: { id: "123" } },
{ data: { title: "Lederuhr", sku: "SKU-2" }, metadata: { id: "456" } },
],
}),
});
const batch = await response.json();
console.log(`Batch ${batch.batch_id}: ${batch.jobs_created} jobs created`);
Errors¶
| Status | Description |
|---|---|
400 |
Validation error (empty items, invalid data, metadata too large). |
401 |
Invalid or missing API key. |
403 |
Smart Mode requires a Starter plan or higher. |
404 |
Structure template not found. |
429 |
Rate limit or concurrent job limit reached. |
GET /v1/jobs/batch/{batch_id}/export¶
Export all jobs in a batch as a CSV file. Useful for downloading results in bulk or importing into spreadsheets.
Authentication
Header: X-API-Key: your_api_key
Status: 200 OK
Content-Type: text/csv; charset=utf-8
Query Parameters¶
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
format |
string |
no | csv |
Export format. Currently only csv is supported. |
CSV Columns¶
| Group | Columns | Source |
|---|---|---|
| Meta | _job_id, _status, _smart_mode, _error |
Job record |
| Input | Superset of all input keys across jobs | briefing.input_material |
| Output | out:<field> for each template field (alphabetical) |
segments[].text |
- Completed jobs: Output columns contain generated text.
- Failed/queued jobs: Output columns are empty;
_errorcontains the first error message. - Empty batch: Returns a CSV with headers only (no 404).
CSV Injection Protection
All cell values starting with =, +, -, or @ are prefixed with a single quote (') to prevent formula injection in Excel and Google Sheets.
Examples¶
Errors¶
| Status | Description |
|---|---|
400 |
Unsupported format (only csv is supported). |
401 |
Invalid or missing API key. |
POST /v1/jobs/batch-text¶
Submit a text for translation into multiple target languages in a single request. One job is created per target language, all sharing a batch_id.
Authentication
Header: X-API-Key: your_api_key
Content-Type: application/json
Status: 202 Accepted
Request Body¶
The request body is the same as POST /v1/jobs (text translation), but target_lang must be a list of language codes instead of a single string.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
source_lang |
string |
yes | -- | BCP-47 source language code. |
target_lang |
string[] |
yes | -- | List of BCP-47 target language codes (max 10). |
text |
string |
yes* | -- | Text to translate. *Either text or texts is required. |
texts |
array |
yes* | -- | Array of strings or {text, metadata} objects (max 500). |
domain |
string |
no | null |
Domain hint (e.g., "legal", "medical", "ecommerce"). |
tone |
string |
no | null |
Desired tone (e.g., "formal", "casual"). |
instructions |
string |
no | null |
Custom instructions for the translator. |
glossary_id |
string |
no | null |
Glossary ID to apply. |
quality |
string |
no | "standard" |
"standard" or "premium" (Starter+ required). |
project_name |
string |
no | null |
Project label (max 100 characters). |
glossary_id |
string |
no | null |
Glossary ID to apply to all items in the batch. |
glossary_ids |
string[] |
no | null |
Multiple glossary IDs to apply (combined). |
Request Example¶
{
"source_lang": "de",
"target_lang": ["en", "fr", "es"],
"text": "Unsere Produkte stehen für höchste Qualität.",
"domain": "ecommerce",
"tone": "formal",
"project_name": "Product Launch Q2"
}
Response (202)¶
{
"batch_id": "b1c2d3e4-...",
"jobs": [
{ "job_id": "550e8400-...", "target_lang": "en", "status": "queued" },
{ "job_id": "550e8401-...", "target_lang": "fr", "status": "queued" },
{ "job_id": "550e8402-...", "target_lang": "es", "status": "queued" }
]
}
Idempotency
Pass an Idempotency-Key header (max 64 characters) to safely retry requests. If the same key is used with the same request body within 24 hours, the original response is replayed.
Examples¶
curl -X POST https://app.falara.io/api/v1/jobs/batch-text \
-H "X-API-Key: $FALARA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: my-unique-key-123" \
-d '{
"source_lang": "de",
"target_lang": ["en", "fr", "es"],
"text": "Unsere Produkte stehen für höchste Qualität.",
"domain": "ecommerce"
}'
import requests
response = requests.post(
"https://app.falara.io/api/v1/jobs/batch-text",
headers={
"X-API-Key": FALARA_API_KEY,
"Content-Type": "application/json",
},
json={
"source_lang": "de",
"target_lang": ["en", "fr", "es"],
"text": "Unsere Produkte stehen für höchste Qualität.",
"domain": "ecommerce",
},
)
batch = response.json()
for job in batch["jobs"]:
print(f"{job['target_lang']}: {job['job_id']} ({job['status']})")
const response = await fetch("https://app.falara.io/api/v1/jobs/batch-text", {
method: "POST",
headers: {
"X-API-Key": FALARA_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
source_lang: "de",
target_lang: ["en", "fr", "es"],
text: "Unsere Produkte stehen für höchste Qualität.",
domain: "ecommerce",
}),
});
const batch = await response.json();
batch.jobs.forEach((job) =>
console.log(`${job.target_lang}: ${job.job_id} (${job.status})`)
);
Errors¶
| Status | Description |
|---|---|
401 |
Invalid or missing API key. |
403 |
Premium quality requires a paid plan. |
422 |
target_lang must be a list, is empty, contains duplicates, or includes source_lang. |
422 |
Too many target languages (max 10). |
429 |
Rate limit or concurrent job limit reached. |