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