Sandbox environment · Use your sandbox account, model, and API key. Requests go to https://sandbox-api.fortza.ai.
THE FORTZA API

Fortza API Guide

Learn how to authenticate, send records to your model, read anomaly results, and connect Salesforce Flow.

JSON in and out100 records per requestBearer authentication
01

GET STARTED

Your first API call

About 15 min

You’ll need a Fortza account, a live model, and an API key from the same organization.

1 Create an API key

In Fortza, open Connect a system and find Generate key. Give your key a recognizable name, such as salesforce-test, then generate it.

Copy it before you leave. The full key is shown only once. Store it securely and keep it out of emails, shared documents, and source code.

2 Find your model and fields

Open Models. Copy a live model’s full name and the field names listed on its card. Use the types and formats from the data you trained it with.

This guide uses fortza-acme-ops-demo. Replace the example model, fields, and values with your own.

Example model fields
FieldExample typeExample value
recorded_atDate and time2026-10-22T09:15:00Z
source_idTextSRC-104
categoryTextstandard
amountNumber1250
quantityNumber12
duration_secondsNumber48.5

3 Build and send your request

Replace YOUR_API_KEY, the model name, and the record fields. Use a key and model from the environment selected above.

POST /api/v1/inference
curl -X POST "https://sandbox-api.fortza.ai/api/v1/inference" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model_name": "fortza-acme-ops-demo",
    "records": [
      {
        "recorded_at": "2026-10-22T09:15:00Z",
        "source_id": "SRC-104",
        "category": "standard",
        "amount": 1250,
        "quantity": 12,
        "duration_seconds": 48.5
      },
      {
        "recorded_at": "2026-10-22T09:16:00Z",
        "source_id": "SRC-104",
        "category": "standard",
        "amount": 98400,
        "quantity": 1,
        "duration_seconds": 2.1
      }
    ]
  }'

Run this in Bash (macOS, Linux, or Git Bash on Windows). For a visual option, import the cURL example into Postman and select Send. This multiline command uses Bash syntax, not PowerShell syntax.

Each record counts toward your row allowance. Whether a record is flagged depends on your trained model and organization’s threshold.
02

READ THE RESULTS

Understand the response

A successful request returns one result per record. Here is an example response; your scores and explanations depend on your model and the records you send.

200 application/json
{
  "run_id": "00000000-0000-4000-8000-000000000001",
  "record_count": 2,
  "anomaly_count": 1,
  "not_anomaly_count": 1,
  "model_artifact_id": "00000000-0000-4000-8000-000000000002",
  "model_name": "fortza-acme-ops-demo",
  "applied_threshold_percentile": 90,
  "applied_decision_threshold": 0.85,
  "results": [
    {
      "index": 0,
      "result": "Not Anomaly",
      "anomaly_score": 0.28,
      "anomaly_percentile": 0.42,
      "evidence": {
        "schema_version": 1,
        "model": "Fortza Detection Engine",
        "reasons": []
      }
    },
    {
      "index": 1,
      "result": "Anomaly",
      "anomaly_score": 0.94,
      "anomaly_percentile": 0.99,
      "evidence": {
        "schema_version": 1,
        "model": "Fortza Detection Engine",
        "reasons": [
          { "message": "Amount is higher than usual." }
        ]
      }
    }
  ]
}
result
"Anomaly" or "Not Anomaly". Use this value for the verdict.
index
Zero-based position in your request. Match results back to the records you sent; a per-record ID is not returned.
anomaly_percentile
Relative unusualness from 0 to 1. A value of 0.99 means approximately the 99th percentile of the model’s reference scores. This is not confidence or probability of a problem. It can be null for models trained without a reference score distribution.
anomaly_score
The model’s raw score. Use the returned verdict instead of applying a fixed cutoff across models.
evidence
Explanation details, returned for normal and anomalous records alike. Readable explanations appear in reasons[].message; a reason can include extra fields, and reasons can be empty. evidence is null if no explanation could be produced. Show reasons only when result is "Anomaly".
03

CONNECT YOUR TOOLS

Call Fortza from Salesforce Flow

Send a record after it saves, then write Fortza’s verdict back to Salesforce. Test the flow before activating it, using a Fortza key and model from the selected environment.

Record savedAsync calloutFortza checksWrite result

1 Store the key in credentials

In Salesforce Setup, create an External Credential using custom authentication and a named principal. Store your Fortza key as an authentication parameter named ApiKey.

Configure the Authorization header to send Bearer followed by that parameter. Create a Named Credential, Fortza_API, pointing to your environment’s API host and linked to the External Credential. Grant the flow’s running user access to the principal through a permission set.

Keep the key in credentials, rather than a flow variable or formula. Follow Salesforce’s Named Credentials documentation ↗ for the settings available in your org.

2 Create fields for the result

Suggested fieldTypeValue to store
Fortza_Is_Anomaly__cCheckboxresult = "Anomaly"
Fortza_Percentile__cNumber (6, 4)anomaly_percentile, 0–1, may be blank
Fortza_Reason__cLong Text AreaReason messages, only when result = "Anomaly"
Fortza_Scored_At__cDate/TimeTime of successful scoring

3 Map your fields and create a callout

Map each trained Fortza field to a Salesforce field, preserving its training format. For example, your model’s amount might map to Opportunity Amount. This mapping depends on your own model.

In Flow Builder, create an HTTP Callout action using Fortza_API, method POST, and path /api/v1/inference. Use a one-record version of the request example and the response example to define the action. Read the returned results collection, rather than expecting a top-level verdict.

See Salesforce’s HTTP Callout guide ↗. Check that nested evidence and nullable values work with the generated types; a simplified response mapping or custom action may be needed.

4 Run after save and handle failures

Create a record-triggered flow optimized for Actions and Related Records. Put the HTTP callout on its Run Asynchronously path. After success, write the verdict, percentile, and current time back to the record, plus the reasons when the verdict is an anomaly. Branch on the HTTP status listed in Errors.

Only trigger when relevant input fields change. Updating Fortza’s output fields must not trigger another check. Add a fault path and handle unsuccessful HTTP responses so an admin can investigate. An owner review task for an anomaly is optional.

5 Test before activating

Check a successful response, missing-field error, invalid key, unavailable model, and empty evidence. Confirm that writing the results back does not cause repeated callouts. Plan batches and monthly row usage before a mass import; never automatically replay a failed batch without checking whether it was processed.

04

API REFERENCE

One endpoint. Your model.

POST/api/v1/inference
SettingCurrent contract
API hosthttps://sandbox-api.fortza.ai
AuthenticationAuthorization: Bearer YOUR_API_KEY
Content typeapplication/json
Records1–100 objects per request; up to 200 fields per record.
Model nameUse the exact live model name from your organization. Required when multiple live customer models exist; otherwise it can be omitted.
Required fieldsEvery record must include all trained field names, with matching spelling and case. Send a value for every field; blank values may be rejected, depending on the model.
UsageEach record counts as one inference row in the organization’s allowance.
CSV alternativeUse Check a file in the app for CSVs up to 10,000 rows or 10 MB, subject to your allowance.

Find your model name and required field names on the Models page in Fortza.

05

HOW IT WORKS

What makes a record unusual?

Fortza compares a record’s score to the model’s stored reference score distribution. Your organization’s threshold percentile determines the cutoff. The current default is 90; an organization admin can adjust it in Settings → Organization.

A lower percentile produces more flags; a higher percentile produces fewer. The setting does not guarantee a particular fraction of future records will be flagged. Use result for the verdict and the returned applied_threshold_percentile and applied_decision_threshold to see the policy used for that run.

06

TROUBLESHOOTING

Get back to a working request

Expected API errors return a plain-English message and structured details. Read details.code to identify the problem.

400 Missing required field
{
  "message": "Some records are missing fields required by this model.",
  "details": {
    "code": "VALIDATION_FAILED",
    "missing_columns": ["source_id"],
    "record_index": 0,
    "errors": [
      { "record_index": 0, "missing_columns": ["source_id"] }
    ],
    "reason": "Some records failed validation."
  }
}
StatusCodeWhat to check
400VALIDATION_FAILEDInclude every required field. Check missing_columns and the zero-based record index.
400SCHEMA_MISMATCH
INVALID_REQUEST
Send the field names and value formats your model was trained with.
422REQUEST_VALIDATION_FAILEDCheck the JSON structure, model-name format, 1–100 record limit, and 200-field limit.
401API_KEY_MISSING
INVALID_AUTHORIZATION_HEADER
INVALID_API_KEY
Send a valid, unrevoked key with the Bearer authorization header.
404MODEL_NOT_FOUNDUse the exact name of a live model from the same organization as the API key.
409MODEL_NOT_READY
ARTIFACT_NOT_READY
The organization has no ready live model, or the named model isn’t live yet. Wait for training to finish or make a model live.
400MODEL_SELECTION_REQUIREDInclude the full model_name in your request.
403INFERENCE_QUOTA_EXCEEDEDCheck remaining rows and your plan in the app.
403ORGANIZATION_INACTIVE
PLAN_CONFIGURATION_REQUIRED
Contact Fortza support about the organization’s status or plan.
503ML_SERVICE_UNAVAILABLEFortza is temporarily unavailable. Check the request’s outcome before retrying to avoid duplicate runs.
OtherAny other code, such as HTTP_500Read message, then contact support with the request time and code.

Still stuck?

Send the request time, run ID if available, and error code to our team. Leave out your API key and customer records.

Contact support ↗