API Reference v1.0.0
api.tdfortza.com OpenAPI YAML

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.

Base URL
https://api.tdfortza.com
Content Type
application/json
Records per Job
1 — 1,000
Result Retention
24 hours after first fetch

Authentication

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.

Required Header

X-Fortza-Key: <YOUR_API_KEY>

Example Request
curl https://api.tdfortza.com/health \
  -H "X-Fortza-Key: YOUR_API_KEY"

Health Check

GET /health

Returns service health status. Used by monitoring systems and load balancer target group health checks.

Example Request
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

POST /jobs

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

ParameterTypeDescription
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.
Example Request
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

GET /jobs/{job_id}

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

ParameterTypeDescription
job_id required string (uuid) Job UUID returned by POST /jobs
Example Request
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

GET /jobs/{job_id}/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

ParameterTypeDescription
job_id required string (uuid) Job UUID returned by POST /jobs

Query Parameters

ParameterTypeDescription
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.
Example Request
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.

HTTPError CodeDescription
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

StatusDescription
PENDINGJob created, items being queued
PROCESSINGAt least one item is currently running
COMPLETEDAll items finished processing
FAILEDJob-level failure

Item Status

StatusDescription
QUEUEDWaiting for a worker
RUNNINGCurrently being processed
SUCCEEDEDCompleted successfully with results
FAILEDPermanently failed
RETRYABLE_FAILEDFailed but eligible for automatic retry