Failure download endpoints
| Resource | CSV | JSON |
|---|
| Transactions | GET /batch-import/transaction-jobs/{jobId}/failures.csv | GET β¦/failures |
| User events | GET /batch-import/user-event-jobs/{jobId}/failures.csv | GET β¦/failures |
| Entities | GET /batch-import/entity-jobs/{jobId}/failures.csv | GET β¦/failures |
Legacy entity CSV alias: GET /entities/automatic/bulk/imports/{jobId}/failures.csv.
β¦/failures.csv β CSV file download (Content-Type: text/csv)
β¦/failures β JSON body (Content-Type: application/json)
Overview
Batch imports expose failures at three layers:
| Layer | When | Where to read |
|---|
| Pre-job | Request rejected before jobId is returned (400) | HTTP response body (error.code) |
| Job-level | Whole job aborted (status: failed) | Unified history β workerError, metadata.apiError; JSON failures β jobFailure |
| Row-level | Some rows failed (failed > 0, job may still be completed) | Failures CSV/JSON per kind |
Row-level failures always include a stable code (machine-readable) and message (human detail). Legacy jobs may only have free-text error; the API normalizes them on read.
Entity row outcomes (created / skipped / failed)
| Outcome | In failures.csv? | Where |
|---|
created | No | Job succeeded |
skipped_existing | No β not a failure | Job skipped / skippedExisting, full report CSV, JSON skips[] |
failed | Yes | failures.csv, JSON failures[] |
Duplicate taxId (entities)
Bulk manual default uses duplicateTaxIdPolicy: skip_existing:
- Same
taxId + same type already in org β skipped_existing, skip code SKIPPED_DUPLICATE_TAX_ID
- Does not appear in
failures.csv
Bulk automatic: existing main entity β skipped_existing, SKIPPED_ENTITY_ALREADY_EXISTS
Hard failures:
| Situation | Failure code |
|---|
| Same taxId, different type (person vs company) | TAX_ID_TYPE_MISMATCH |
| Same taxId + type with error policy (unit API; not bulk default) | DUPLICATE_TAX_ID |
Duplicate externalId | DUPLICATE_EXTERNAL_ID |
Row-level failure codes (BATCH_IMPORT_ITEM_FAILURE_CODES)
| Code | Meaning |
|---|
VALIDATION_ERROR | Row failed Zod / schema validation before persistence. |
PROCESSING_ERROR | Unexpected error while processing the row. |
ENTITY_NOT_FOUND | Referenced entity does not exist in the organization. |
INVALID_RISK_MATRIX | Risk matrix id invalid or not in org. |
CREATION_QUOTA_EXCEEDED | Organization creation quota exceeded. |
DATABASE_INSERT_ERROR | Database rejected insert (unclassified). |
DUPLICATE_EXTERNAL_ID | Entity or transaction with same externalId already exists. |
DUPLICATE_TAX_ID | Same taxId + type already exists (hard error path). |
TAX_ID_TYPE_MISMATCH | taxId registered under a different entity type. |
CONSTRAINT_VIOLATION | Other DB constraint (FK, check, unique index). |
MISSING_COUNTRY | Entity row missing valid ISO2 country. |
INVALID_COUNTRY | Country not allowed for import mode (e.g. automatic β AR/BR/CL). |
ENRICHMENT_FAILED | Enrichment provider failed for entity row. |
CREATION_FAILED | Entity could not be created for the row. |
Skip reason codes (BATCH_IMPORT_SKIP_REASON_CODES)
Not failures β used when outcome=skipped_existing:
| Code | Meaning |
|---|
SKIPPED_DUPLICATE_TAX_ID | Manual bulk skipped row: duplicate taxId + type |
SKIPPED_ENTITY_ALREADY_EXISTS | Automatic bulk skipped row: entity already existed |
Risk matrix / business rules: rule execution runs after the row is created. Rule outcomes do not appear in failures.csv / JSON failures[] and do not roll back the row. Use alerts, risk score, and audit timelines for rule results.
Job-level codes (BATCH_IMPORT_JOB_FAILURE_CODES)
| Code | Meaning |
|---|
INVALID_ENTITY_REFERENCES | Transaction batch: validateExistingEntity=true and unresolved origin/destination refs β no rows created. |
TOO_MANY_ITEMS | File exceeds plan row limit. |
CSV_PARSE_ERROR | CSV could not be parsed or mapped. |
MAPPING_VALIDATION_ERROR | Saved mapping or validate-csv preflight failed. |
MISSING_REQUIRED_FIELD | Required multipart / row field missing before queue. |
COOPERATIVE_CANCEL | Job cancelled while processing. |
WORKER_ERROR | Unhandled worker error. |
Scenario matrix (client FAQ)
| Scenario | In row failures? | Typical code / location |
|---|
| Missing CSV column (pre-parse) | No | 400 before job |
| Invalid entity ref (txn batch, default validation) | No | Job INVALID_ENTITY_REFERENCES |
Duplicate txn externalId with skipDuplicates=true | No | Counted as skipped |
Duplicate entity externalId (manual import) | Yes | DUPLICATE_EXTERNAL_ID |
Duplicate entity taxId (same type, bulk default) | No | skipped_existing β SKIPPED_DUPLICATE_TAX_ID in skips[] |
Duplicate entity taxId (type mismatch) | Yes | TAX_ID_TYPE_MISMATCH |
| Enrichment failure (entity automatic) | Yes | ENRICHMENT_FAILED |
| User event invalid field | Yes | VALIDATION_ERROR |
| Rules / matrix evaluation error | No | Row still created |
Reproducible test scenarios
User events (simplest row failures): valid CSV + mapping; one row with empty required field β GET β¦/user-event-jobs/{jobId}/failures.
Entities (manual): create entity with external_id=X, import another row with same external_id β DUPLICATE_EXTERNAL_ID.
Transactions (job-level): validateExistingEntity=true + originExternalId=DOES_NOT_EXIST β job failed, jobFailure.code=INVALID_ENTITY_REFERENCES.
Transactions (row-level): batchErrorHandling=continue_collect_errors + mix valid rows with DB constraint violations β row entries in failures endpoint.
- Max 500 row failures persisted per transaction batch job (CSV + JSON may truncate; JSON exposes
truncated + failuresTotal).
See also: Bulk imports overview.