Fortza Bulk API
The Fortza Bulk API enables batch submission of customer records for fraud-detection analysis. Submit records, track job progress, and retrieve per-record fraud scores with layer-level breakdowns.
https://api.tdfortza.comapplication/jsonAuthentication
All API requests require the X-Fortza-Key header.
The key is enforced at the load balancer — requests without a valid key
are rejected before reaching the API.
X-Fortza-Key: <YOUR_API_KEY>
curl https://api.tdfortza.com/health \
-H "X-Fortza-Key: YOUR_API_KEY"
Health Check
Returns service health status. Used by monitoring systems and load balancer target group health checks.
curl https://api.tdfortza.com/health \
-H "X-Fortza-Key: YOUR_API_KEY"
Responses
200 Service is healthy
{
"status": "healthy",
"service": "ingestion_controller"
}
Submit a New Batch Job
Creates a batch job and queues each record for asynchronous fraud-detection processing. Each record is validated for required fields, the build token resolves the scoring configuration, and subscription quotas are verified before acceptance.
Request Body
| Parameter | Type | Description |
|---|---|---|
| build_token required | string | Build token that selects the scoring layer configuration. Provided by Fortza during onboarding. |
| records required | array | 1–1,000 customer records. Each record must include customer_name and email. Include origin_system_record_id for matching results back to your records. |
| tenant_id | string | Optional tenant identifier for multi-tenant tracking. |
| job_metadata | object | Arbitrary metadata stored with the job. Returned in status queries. |
curl -X POST https://api.tdfortza.com/jobs \ -H "Content-Type: application/json" \ -H "X-Fortza-Key: YOUR_API_KEY" \ -d '{ "build_token": "<your-build-token>", "records": [ { "origin_system_record_id": "CRM-10001", "customer_name": "Jane Smith", "email": "jane@example.com", "zip_code": "90210" } ] }'
Responses
201 Job created and records queued
{
"job_id": "7eddfb8d-78ea-4b03-902d-8bc53ff5109f",
"accepted_count": 20,
"queued_count": 20,
"duplicate_count": 0,
"build_name": "Full 14-Layer Build",
"layers_count": 13
}
400 Record validation failed
{
"detail": {
"error": "Record validation failed",
"error_code": "VALIDATION_ERROR",
"record_errors": [
{
"record_index": 2,
"origin_system_record_id": "ABC-123",
"errors": ["Missing required field: email"]
}
],
"valid_count": 9,
"invalid_count": 1
}
}
403 Transaction limit exceeded
{
"detail": {
"error": "Transaction limit would be exceeded",
"error_code": "TRANSACTION_LIMIT_EXCEEDED",
"limit": 3500,
"completed": 3500,
"in_flight": 0,
"total_reserved": 3500,
"requested": 2,
"remaining": 0,
"can_proceed": false,
"scope": "organization",
"would_exceed_by": 2,
"message": "Cannot process 2 records. Limit: 3500, Reserved: 3500 (3500 completed, 0 in-flight), Remaining: 0"
}
}
403 Subscription not found
{
"detail": {
"error": "Subscription details not found for this account.",
"error_code": "SUBSCRIPTION_NOT_FOUND",
"build_name": "Full 14-Layer Build"
}
}
403 Subscription inactive
{
"detail": {
"error": "Subscription is inactive. Please renew your subscription to continue.",
"error_code": "SUBSCRIPTION_INACTIVE",
"build_name": "Full 14-Layer Build"
}
}
403 Subscription expired
{
"detail": {
"error": "Subscription expired on 2026-01-01. Please renew your subscription to continue.",
"error_code": "SUBSCRIPTION_EXPIRED",
"build_name": "Full 14-Layer Build",
"expired_on": "2026-01-01"
}
}
404 Build token not found
{
"detail": {
"error": "Build token not found: <your-build-token>",
"error_code": "BUILD_NOT_FOUND"
}
}
422 Request body schema validation failed
{
"detail": [
{
"loc": ["body", "records"],
"msg": "field required",
"type": "value_error.missing"
}
]
}
500 Internal server error
{
"detail": "Internal server error"
}
Get Job Status
Returns the current status of a job, including overall status, per-status item counts, and completion progress as a percentage. Poll this endpoint after submitting a job. When the status is COMPLETED or FAILED, proceed to fetch results.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
| job_id required | string (uuid) | Job UUID returned by POST /jobs |
curl https://api.tdfortza.com/jobs/7eddfb8d-78ea-4b03-902d-8bc53ff5109f \
-H "X-Fortza-Key: YOUR_API_KEY"
Responses
200 Job status retrieved
{
"job_id": "7eddfb8d-78ea-4b03-902d-8bc53ff5109f",
"tenant_id": "test-tenant",
"status": "PROCESSING",
"metadata": { "source": "client" },
"created_at": "2026-01-29T10:00:00Z",
"updated_at": "2026-01-29T10:05:00Z",
"summary": {
"total": 20,
"queued": 5,
"running": 3,
"succeeded": 10,
"failed": 2,
"retryable_failed": 0
},
"progress": {
"completed": 12,
"total": 20,
"percent": 60.0
}
}
400 Invalid job_id format
{
"detail": "Invalid job_id format"
}
404 Job not found
{
"detail": "Job not found"
}
Get Processed Results
Returns paginated fraud-detection results for a completed or failed job. Results are only available after the job reaches COMPLETED or FAILED status; calling this on an in-progress job returns 409 Conflict. On first fetch, a timestamp is recorded and results are auto-deleted 24 hours later.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
| job_id required | string (uuid) | Job UUID returned by POST /jobs |
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| limit | integer | Page size, 1–1000. Default: 1000 |
| offset | integer | Number of items to skip. Default: 0 |
| status_filter | string | Filter by item status: SUCCEEDED or FAILED. Omit to get both. |
| fetched_by | string | Identifier for who is fetching results. Recorded for audit. |
curl "https://api.tdfortza.com/jobs/7eddfb8d-78ea-4b03-902d-8bc53ff5109f/results?fetched_by=my_system" \
-H "X-Fortza-Key: YOUR_API_KEY"
Responses
200 Results retrieved
{
"job_id": "7eddfb8d-78ea-4b03-902d-8bc53ff5109f",
"tenant_id": "test-tenant",
"status": "COMPLETED",
"results": [
{
"item_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"origin_system_record_id": "CRM-10001",
"status": "SUCCEEDED",
"result": "Low fraud risk score of 0.42...",
"total_score": 0.42,
"status_detail": "complete_success",
"results": {
"FBI": {
"layer": "FBI",
"score": 0.1,
"reason": "No match found",
"Summary": "Clear",
"blocked": false
},
"Anomaly": {
"layer": "Anomaly",
"score": 0.07,
"reason": "No anomalies detected",
"Summary": "Normal",
"blocked": false
}
},
"summary": {
"errors": 0,
"failed": 0,
"blocked": 0,
"successful": 13,
"total_layers": 13
},
"confidence": {
"message": "High confidence: 13/13 layers executed successfully",
"coverage": 1.0,
"confidence_level": "high",
"confidence_percentage": 100.0
},
"error": null,
"completed_at": "2026-01-29T10:06:12Z"
}
],
"fetch_metadata": {
"fetched_at": "2026-01-29T10:07:00Z",
"fetched_by": "my_system",
"items_returned": 1,
"first_fetch": true,
"auto_delete_after": "2026-01-30T10:07:00Z"
},
"pagination": {
"limit": 1000,
"offset": 0,
"count": 1
}
}
400 Invalid job_id or status_filter
// Invalid job_id { "detail": "Invalid job_id format" } // Invalid status_filter { "detail": "Invalid status_filter. Must be one of: ['QUEUED', 'RUNNING', 'SUCCEEDED', 'FAILED', 'RETRYABLE_FAILED']" }
404 Job not found
{
"detail": "Job not found"
}
409 Job still in progress
{
"detail": "Job is still PROCESSING. Results can only be fetched after job is COMPLETED or FAILED."
}
500 Internal server error
{
"detail": "Internal server error"
}
Error Codes
All error responses include a detail field with the specific error code and a human-readable message.
| HTTP | Error Code | Description |
|---|---|---|
| 400 | VALIDATION_ERROR | One or more records failed field validation. Per-record details included. |
| 403 | SUBSCRIPTION_NOT_FOUND | No subscription found for the user or organization. |
| 403 | SUBSCRIPTION_INACTIVE | Subscription is deactivated. |
| 403 | SUBSCRIPTION_EXPIRED | Subscription end date has passed. |
| 403 | TRANSACTION_LIMIT_EXCEEDED | Monthly transaction quota would be exceeded. Full usage breakdown included. |
| 404 | BUILD_NOT_FOUND | Provided build_token does not match any build. |
| 409 | — | Results requested for a job still in progress. |
| 422 | — | Request body failed schema validation. |
| 500 | — | Internal server error. |
Status Values
Job Status
| Status | Description |
|---|---|
| PENDING | Job created, items being queued |
| PROCESSING | At least one item is currently running |
| COMPLETED | All items finished processing |
| FAILED | Job-level failure |
Item Status
| Status | Description |
|---|---|
| QUEUED | Waiting for a worker |
| RUNNING | Currently being processed |
| SUCCEEDED | Completed successfully with results |
| FAILED | Permanently failed |
| RETRYABLE_FAILED | Failed but eligible for automatic retry |