FyscalTech
/ AML Solution / Developer Portal
← Back to AML Solution

FT AML Platform
Developer Portal

Everything a customer, partner, or implementation team needs to integrate with FT AML — quick start, architecture, data models, integration methods, webhooks, and best practices, explained step by step.

13 modules covered
Step-by-step integration guidance
Built for implementation teams
Explore FT AML → Using the platform? See the User Guide →

Introduction

This Developer Portal is the integration reference for the FT AML Platform. It's written for three audiences: customers connecting their own core banking or onboarding systems to FT AML, partners building on top of the platform on a customer's behalf, and Fyscaltech implementation teams delivering a go-live. Wherever a detail depends on your specific deployment — credentials, exact payload schemas, rate limits — this guide says so explicitly rather than guessing, and points you to the Fyscaltech integration team who confirms it during onboarding.

What FT AML does

FT AML is an Anti-Money Laundering (AML) platform that helps financial institutions detect suspicious activity, screen customers against regulatory watchlists, monitor transactions, manage investigations, and comply with AML/CTF regulations. The Developer Portal covers the integration surface of that platform — getting your data in, and getting screening results and alerts back out — rather than the compliance-analyst console itself.

There are three ways data moves between your systems and FT AML

  • Bulk CSV via S3 — for loading or refreshing large volumes of Customer, Customer Account, and Customer Transaction records.
  • Customer Ingestion API — for pushing or updating individual customer records from your own systems as they change.
  • Screening API — for screening a specific customer record on demand, by full name.
Document status. 

The CSV file format for Customer and Account records, and the Customer Ingestion API and Screening API request/response reference, are now fully documented in Integration Methods. Still pending: webhook payload format and signature verification guidelines, a Postman collection, and an OpenAPI specification — will be published soon once received from technical team.

Who does what

Customers

Own the source data (customers, accounts, transactions) and decide which integration method(s) fit their volume and architecture.

Partners

Build and operate an integration on a customer's behalf, typically under the same credentials and onboarding process as a direct customer.

Implementation teams

Fyscaltech's own team, engaged during onboarding to provision credentials, confirm schemas, and support go-live.

This portal

The shared reference all three groups work from — one source of truth for how integration works, updated as details are confirmed.

Quick Start

If you're an external developer integrating FT AML into your own systems for the first time, this is the one section to read start to finish — everything else in this portal is reference material you'll come back to as you go.

The fastest path from zero to a working integration follows the same six steps regardless of which integration method you end up using day to day.

  1. Request API credentials — contact the Fyscaltech integration team (see Support) to start onboarding. They'll confirm which integration method(s) fit your use case.
  2. Receive sandbox access — where a sandbox/test environment applies to your chosen method, credentials and connection details are issued as part of onboarding (see Testing & Sandbox).
  3. Upload a sample customer — load a small test file via Bulk CSV (50–100 rows is plenty), or a single record via the Customer Ingestion API, to confirm your data format is accepted.
  4. Call the Screening API — submit a customer's full name to /screen and confirm a result comes back in the response.
  5. Check the delivery mechanism for ingestion-triggered screening — if you plan to rely on name_screening_enabled during ingestion instead of calling the Screening API directly, confirm with Fyscaltech how that result reaches you before building against it.
  6. View the screening result — check the FT AML console (Alert Manager, or Name Screening) to see the same result reflected on the platform side.
Where to start. 

If you're not sure which integration method fits your volume and timeline, read Integration Methods and the "Which one should I use?" table first — then bring that shortlist to the Fyscaltech integration team.

Platform & Architecture

FT AML sits alongside your core banking and customer-facing systems, receiving data through the integration methods in this portal and returning screening results and alerts.

Will be published soon once received from technical team. 

Confirmed architecture detail — service topology, network/deployment diagrams, data residency options — hasn't been provided yet. What's documented today (the real request/response shape for each service) lives under Integration Methods.

Core Concepts & Data Models

A few ideas come up across all three integration methods. Understanding these up front makes the rest of this portal easier to follow.

Customer Record

The core profile of an individual or organization — the same record whether it arrives via bulk CSV or the Customer Ingestion API.

Customer Account Record

An account belonging to a customer, linked back to its Customer Record.

Customer Transaction Record

A transaction on a customer account, used by Transaction Monitoring once it's in the platform.

Ingestion

The general term for getting any of the three record types into the platform — either as a bulk CSV upload, or one at a time via the Customer Ingestion API.

Screening

Checking a customer against watchlists. Today this is done by full name, via the Screening API or triggered as part of ingestion.

Webhook

An endpoint you host, which the platform calls to deliver a screening result — only relevant if you're using the Customer Ingestion API to trigger screening rather than calling the Screening API directly.

Data models

Confirmed field names below come directly from the Customer Ingestion API and CSV bulk-upload formats — where a model isn't backed by data received from the technical team yet, that's noted rather than guessed at.

Customer

customer_id · customer_name
  • customer_id, customer_name — the only two required fields on ingestion
  • customer_typeIndividual or Corporate (API) / INDIVIDUAL, CORPORATE, BUSINESS (CSV)
  • risk_level, risk_score, pep_flag, sanctions_status — KYC/risk fields set on ingestion
  • date_of_birth_or_incorporation, citizenship_country, street/city — optional, improve screening match accuracy

Account

ACCOUNT_NUMBER · CUSTOMER_ID
  • ACCOUNT_NUMBER — unique across all your accounts, not just per-customer
  • CUSTOMER_ID — links back to the owning Customer; unmatched accounts are skipped
  • ACCOUNT_TYPESAVINGS, CURRENT, WALLET, FIXED_DEPOSIT, LOAN
  • ACCOUNT_HOLDING_TYPESOLE, JOINT, TRUST, CUSTODIAL

Transaction

will be published soon once received from technical team

Alert

will be published soon once received from technical team

Case

will be published soon once received from technical team

Integration Methods

The three ways data moves between your systems and the FT AML Platform, in detail.

Which one should I use?

MethodBest for
Bulk CSV via S3Initial data loads, and large-volume periodic refreshes of your customer and account population
Customer Ingestion APIKeeping individual customer records in sync as they're created or changed in your own system
Screening APIChecking one specific customer by full name at a specific moment — e.g. during onboarding

Bulk data ingestion (CSV via S3)

For loading or refreshing data in volume, the platform reads CSV files you upload to a dedicated Amazon S3 location. Fyscaltech provisions this bucket for you during onboarding — you'll receive the bucket name and a client id (a short code, e.g. acme-bank) that scopes every path below to your own data.

Getting access

Two access options — tell your Fyscaltech contact which fits your team:

  • Browser (AWS Console) — best if a person uploads files manually, a few times a month. No setup beyond a sign-in.
  • Command line / automation — an access key and secret key for the AWS CLI or any S3 library, best if a scheduled job on your side produces the files without a person involved.
aws configure          # one-time setup, using the access key and secret key we send you
aws s3 cp customers_20260729.csv s3://<bucket>/<client-id>/inbox/customer/
Note. 

Your credentials only ever grant access to your own <client-id> folder within the shared bucket — not the whole bucket. Send data files only to the paths below; never by email or shared drive, since they contain personal data.

Where to upload

What you're sendingUpload to
Customers<client-id>/inbox/customer/
Accounts<client-id>/inbox/account/
  • Name files with a sortable datecustomers_20260729.csv, not 29-07-2026 — since if more than one file is waiting, the platform processes whichever name sorts first, and only one file per run.
  • Upload customers before accounts. An account belongs to a customer, so if you're sending both at once, the customer file needs to land first — accounts referencing a customer we haven't seen yet are skipped and reported back to you.

Once a file is read, it's moved out of the inbox — an empty inbox means processing is done, not that something went wrong:

FolderWhat's in it
processed/customer/, processed/account/Files accepted and read
rejected/customer/, rejected/account/Files that couldn't be read at all — almost always a wrong or missing header row
jobs/<run>/errors/Individual rows that couldn't be accepted, with the line number, column, and reason for each

Choosing your ingestion schedule

You control when the platform looks for your files, from the back-office application — no ticket or code change needed. Set a Frequency (every day, or every N days) and one or more Run times (e.g. 02:00 and 14:00); at each of those times the inbox is checked, and an empty inbox simply means nothing runs until the next check. The schedule can also be paused while you're making changes.

Best practice. 

Set the run time comfortably after your own export job finishes — if a nightly export finishes around 01:30, schedule 02:30 rather than 01:45.

File format rules (both files)

  • CSV, UTF-8 encoded, with a header row first
  • The header row must match exactly — same column names, spelling, order, all capitals. This is the one thing that gets the whole file rejected rather than individual rows.
  • Every row must have the same number of columns as the header, even when values are empty (A,,C)
  • Leave optional columns blank rather than writing NULL, N/A, or - — those are treated as real values and usually rejected
  • Wrap a value in double quotes if it contains a comma: "Smith, John"
  • Dates: 2026-07-29, 2026/07/29, 29-07-2026, 29/07/2026, or 20260729 — pick one form and stay consistent
  • Timestamps (date + time columns): 2026-07-29T14:30:00Z is recommended (UTC)
  • Yes/no columns accept true/false/1/0/Y/N/yes/no, any case
  • Country and currency columns use short codes (IN, SG, AE; INR, USD) — some columns are too narrow for full names

Customer file — 52 columns

Copy this header line exactly:

CUSTOMER_ID,CUSTOMER_TYPE,CUSTOMER_NAME,STATUS_CODE,CUSTOMER_SEGMENT_CODE,CUSTOMER_SEGMENT_NAME,RISK_LEVEL,RISK_SCORE,KYC_LEVEL,KYC_LEVEL_DESCRIPTION,PEP_FLAG,SANCTIONS_STATUS,SOURCE_OF_FUNDS,KYC_AUTHORIZED_SIGNATORY_NAME,ONBOARDING_DATE,ONBOARDING_CHANNEL,STREET,CITY,PROVINCE_REGION,ADDRESS_COUNTRY,POSTAL_CODE,CITIZENSHIP_COUNTRY,RESIDENCE_OPERATION_COUNTRY,BIRTH_INCORPORATION_COUNTRY,CUSTOMER_CONTACT_NO,ACCOUNT_TYPE,ACCOUNT_OPEN_DATE,ACCOUNT_AGE_DAYS,EXPECTED_MONTHLY_SPEND,EXPECTED_MONTHLY_SPEND_CURRENCY,EXPECTED_TXN_FREQUENCY,PURPOSE_OF_ACCOUNT,FIRST_NAME,MIDDLE_NAME,LAST_NAME,GENDER,DATE_OF_BIRTH_OR_INCORPORATION,CUSTOMER_AGE,CUSTOMER_ALIASES,CUSTOMER_ID_NO,CUSTOMER_ID_TYPE,CUSTOMER_ID_EXPIRY_DATE,CUSTOMER_ID_ISSUE_DATE,CUSTOMER_ID_COUNTRY,DESIGNATION,EMPLOYER_NAME,DECLARED_INCOME,INCOME_CURRENCY,NATURE_OF_BUSINESS,COUNTRY_OF_OPERATIONS,CREATED_AT,UPDATED_AT

These six must always have a value — a row missing any of them is rejected:

ColumnWhat it is
CUSTOMER_IDYour own identifier, unique in the file and stable across files for the same customer (max 64 chars) — this is how an update is recognized rather than a new customer
CUSTOMER_TYPEOne of INDIVIDUAL, CORPORATE, BUSINESS
STATUS_CODEYour own status, e.g. ACTIVE, DORMANT, SUSPENDED
ONBOARDING_DATEDate the customer was onboarded
ONBOARDING_CHANNELe.g. BRANCH, MOBILE_APP, ONLINE, AGENT
UPDATED_ATTimestamp. Used to decide which version is newer — a record with an older UPDATED_AT will not overwrite a newer one already held

Fixed-value columns (anything else is rejected): CUSTOMER_TYPE (INDIVIDUAL/CORPORATE/BUSINESS), RISK_LEVEL (LOW/MEDIUM/HIGH), GENDER (MALE/FEMALE/OTHER).

Four cross-field rules worth knowing, since these catch inconsistent records: an INDIVIDUAL requires FIRST_NAME and DATE_OF_BIRTH_OR_INCORPORATION; a CORPORATE requires NATURE_OF_BUSINESS; if DECLARED_INCOME is set, INCOME_CURRENCY must be too; and if both CUSTOMER_AGE and a date of birth are given, they must agree within one year.

Account file — 13 columns

ACCOUNT_NUMBER,CUSTOMER_ID,ACCOUNT_TYPE,ACCOUNT_NAME,ACCOUNT_CURRENCY_CODE,ACCOUNT_BANK_NAME,ACCOUNT_BANK_COUNTRY,ACCOUNT_STATUS,ACCOUNT_HOLDING_TYPE,SIGNATORY_CUSTOMER_ID,SIGNATORY_NAME,CREATED_AT,UPDATED_AT

Seven required: ACCOUNT_NUMBER (unique across all your accounts, not just per-customer, max 128 chars), CUSTOMER_ID (must match a customer already received, or the account is skipped), ACCOUNT_TYPE (SAVINGS/CURRENT/WALLET/FIXED_DEPOSIT/LOAN), ACCOUNT_STATUS (ACTIVE/INACTIVE/CLOSED/FROZEN), ACCOUNT_HOLDING_TYPE (SOLE/JOINT/TRUST/CUSTODIAL), CREATED_AT, and UPDATED_AT timestamps.

If ACCOUNT_HOLDING_TYPE is JOINT, TRUST, or CUSTODIAL, SIGNATORY_CUSTOMER_ID becomes required too — a shared account needs a second party. UPDATED_AT can never be earlier than CREATED_AT.

The remaining six columns are optional: ACCOUNT_NAME and ACCOUNT_BANK_NAME (free text, max 255 chars), ACCOUNT_CURRENCY_CODE and ACCOUNT_BANK_COUNTRY (short codes only — max 16 characters, so a full name like "United Arab Emirates" won't fit and is rejected; use AE instead), and SIGNATORY_CUSTOMER_ID/SIGNATORY_NAME for an additional signatory.

Common problems

What you seeCauseFix
File in rejected/, nothing loadedHeader row doesn't match exactlyCopy the header from this page exactly — check spelling, order, extra spaces, case
Rows rejected: REQUIREDA mandatory column is blankFill every required column listed above
Rows rejected: INVALID_ENUMA fixed-value column has something else in itUse only the allowed values
Rows rejected: INVALID_DATEDate/timestamp in an unsupported formUse one of the accepted forms; watch for DD/MM vs MM/DD mix-ups
Rows rejected: DUPLICATESame CUSTOMER_ID/ACCOUNT_NUMBER twice in one fileSend each record once per file — the first occurrence is kept
Rows rejected: MAX_LENGTH_EXCEEDEDA value is longer than the column allowsUsually a full country name in a code column, or an over-long id — see the character limits below
Rows rejected: COLUMN_COUNT_MISMATCHThe row has more or fewer commas than the headerUsually an unquoted comma inside a value — wrap that value in double quotes
Accounts silently not loadedTheir customer hasn't reached us yetUpload the customer file first; confirm that customer row wasn't itself rejected

Customer Ingestion API

Service: datahub (Go / Gin)

Ingests or updates a single customer's information from your own system — the API equivalent of a bulk Customer Record upload, but for one record at a time and in near real time as your data changes. Ingestion is asynchronous: the endpoint validates the payload and publishes an event, then returns immediately — persistence happens moments later via a background consumer, not within the request itself.

Method / PathPOST /datahub/ingestion/v1/customer
Success status202 Accepted
HeadersContent-Type: application/json

Request payload

All fields are flat — no nesting. Only customer_id and customer_name are required; every other field is optional (omit it and it's treated as null). The field set mirrors the CSV Customer Record columns above, just in snake_case JSON:

{
  "customer_id": "CUST-1001",              // REQUIRED, string
  "customer_name": "Jane Doe",             // REQUIRED, string
  "customer_type": "Individual",          // "Individual" | "Corporate"; blank defaults to "Individual"

  // KYC / status
  "status_code": "ACTIVE",
  "customer_segment_code": "RETAIL",
  "risk_level": "LOW",
  "risk_score": 12.5,                     // float
  "pep_flag": false,                      // bool
  "sanctions_status": "CLEAR",

  // Onboarding
  "onboarding_date": "2025-01-15",        // YYYY-MM-DD or RFC3339
  "onboarding_channel": "BRANCH",

  // Address
  "street": "...", "city": "...", "address_country": "AE",

  // Personal
  "first_name": "Jane", "last_name": "Doe",
  "gender": "F",
  "date_of_birth_or_incorporation": "1990-05-01",

  // Identity document
  "customer_id_no": "...", "customer_id_type": "PASSPORT",

  // Screening control — omitted defaults to true
  "name_screening_enabled": true                // bool
}
Note. 

customer_type is the only accepted enum-ish field, with no strict validation — anything other than the two accepted values is simply not recognized, blank defaults to Individual. Date fields accept YYYY-MM-DD or RFC3339; anything unparseable or empty is stored as null. name_screening_enabled omitted is treated as true — a new customer is screened by default unless you explicitly opt out.

Response

{ "code": "00000", "message": "success" }

Returned with 202 Accepted. There's no result field — nothing is persisted synchronously, so there's nothing to hand back yet.

Validation rules

  • Request body is required and must be valid JSON
  • customer_id and customer_name — trimmed, must be non-empty
  • customer_type — blank defaults to Individual; any other value is accepted as-is
  • No format, length, or enum checks are enforced on the remaining fields

Error responses

Shape: { "code": "<code>", "message": "<message>" }

TriggerCodeHTTPMessage
Malformed JSON bodyBR001400invalid request payload
Empty bodyBR001400request body is required
Missing customer_idBR001400customer_id is required
Missing customer_nameBR001400customer_name is required
Internal queue/publish failureSWW01500something went wrong

Flow

POST /customer → controller (bind → validate → map) → PublishCustomerIngestionEvent publishes to SNS/SQS → returns 202. Consumers later upsert the record into Postgres and ClickHouse — neither database is written to synchronously within the request.

Note. 

There is no batch HTTP ingestion endpoint. CSV/batch ingestion runs on a Temporal workflow/queue pipeline (see Bulk CSV via S3), not this API — don't loop this endpoint per record for a bulk load.

Screening API

Service: be-aml-name-screening (Python / FastAPI)

Screens a customer against watchlists and returns matches, synchronously — the result comes back in the same response. Two endpoints exist:

MainBack-office
Method / PathPOST /riskradar/core/api/v1/screenPOST /riskradar/core/api/v1/bo/screen
Side effectsCreates alerts, publishes events, writes a screening ledger entryRead-only — no alert, no publish
Success status200200
HeadersContent-Type: application/json

Use the main /screen endpoint for real onboarding/monitoring checks that should raise alerts when warranted. Use /bo/screen when you want to see what a screening result would look like — e.g. previewing a match — without it creating an alert.

Note. 

A scope framework (an x-scope bitmask header) exists in the service, but is not wired to either of these two routes — sending it currently has no effect.

Request payload

/screen accepts a free-form JSON object — extra fields are allowed and preserved. customer_name is required; customer_type must be "Individual" or "Entity" (defaults to Individual); everything else is optional. The field set mirrors the Customer Ingestion API payload — status_code, risk_level, risk_score, pep_flag, address fields, personal/identity/employment fields, and so on — so a record you've already ingested can largely be re-sent as-is to screen it. Only a subset actually drives matching: customer_name, date_of_birth_or_incorporation, street, city, province_region, citizenship_country, customer_type, gender. If customer_id is omitted, a temporary TMP<uuid> is generated for that request.

{
  "customer_name": "Jane Doe",                    // REQUIRED
  "customer_id": "CUST-1001",
  "customer_type": "Individual",
  "gender": "F",
  "date_of_birth_or_incorporation": "1990-05-01",
  "citizenship_country": "IN",
  "street": "...", "city": "...", "address_country": "AE"
}

/bo/screen takes the same shape, but only customer_name is accepted/required — everything else is ignored for matching purposes on this read-only endpoint.

Response envelope

{ "code": "00000", "message": "Success", "data": { /* result */ } }

Exactly three fields — code, message, data. There's no result or pagination field. Success code is 00000.

/screen result — trimmed, public

{
  "data": {
    "meta": { "entity_key": "...", "screening_id": "...", "timestamp": "..." },
    "screening_result": { "alert_score": 87.5, "alert_category": "HIGH" },  // score 0–100
    "alert_details": { "alert_code": "...", "alert_status": "..." },
    "watchlist_records_matched": [   // top 10, or null
      { "UID": 12345, "full_name": "Jane Doe", "match_score": 91.2 }
    ]
  }
}

/bo/screen result — richer, raw

Same meta/score/category fields, but alert_code and alert_status are always null (no alerting on this endpoint), plus a full raw_matches array (up to 50) with per-attribute detail — each matched attribute (name, country, date of birth, entity type, address) carries its own weight and contribution score, so you can see exactly why a match scored the way it did rather than just the final number.

Each entry in raw_matches also carries record-level detail beyond the scored attributes: match_id, watchlist_mongo_id (the underlying watchlist record's own id), risk_level, record_version, updated_date, and a soft-delete pair — is_deleted / deleted_at — showing whether the matched watchlist record has since been retired at the source.

Validation rules

  • /screencustomer_name required, customer_type must be Individual/Entity, numeric fields are coerced, unknown fields are allowed and preserved
  • /bo/screen — additionally rejects an empty customer_name with entity name required

Error responses

Shape: { "code": "<code>", "message": "<message>", "data": <optional> }

TriggerCodeHTTPMessage
Bad/missing customer_name, invalid customer_typeVALIDATION_ERROR400Invalid request payload
Empty customer_name on /bo/screenVALIDATION_ERROR400entity name required
Duplicate recordCONFLICT409Duplicate record
Redis config-load connection failureREDIS_CONNECTION_ERROR503as raised
Redis config-load operation failureREDIS_OPERATION_ERROR500as raised
Postgres ledger write fails (/screen only)DATABASE_QUERY_FAILED500as raised
Any unmapped errorINTERNAL_SERVER_ERROR500underlying error message (str(exc))

Flow

POST /screen → handler validates → service loads config from Redis/Mongo → FuzzySearchEngine.screen_user matches against sanctions/watchlist data → maps to response. On /screen it also records the screening run in Postgres and, when the result scores as an alert, creates alerts and publishes events. /bo/screen skips all of that alerting — it's read-only end to end.

Authentication

Access is confirmed for one of the three integration methods so far:

  • Bulk CSV via S3 — Fyscaltech provisions the S3 bucket location your files are uploaded to, along with the AWS access credentials needed to write to it. Keep these credentials on your backend or automation only, never in client-side code, and store them in a secrets manager rather than source control.
Will be published soon once received from technical team. 

Credential/access-control setup for the Customer Ingestion API, Screening API, and any webhook delivery hasn't been confirmed yet.

Note. 

Application-level request authentication (e.g. a bearer token or signed-request scheme) for the Customer Ingestion and Screening APIs is still being finalized. Until it's in place, do not assume these endpoints enforce caller identity on their own — confirm the current access-control setup for your environment (network restriction, IP allowlisting, etc.) with your Fyscaltech integration contact before relying on them being reachable only by authorized callers. This page will be updated once the mechanism is finalized.

Integration Workflows

There are two distinct request patterns depending on which APIs you use — a synchronous flow where the screening result comes back in the same response, and an asynchronous flow where it's delivered later to your webhook.

Flow A — synchronous (Screening API called directly)

Customer Record
(already ingested)
Screening API request
(full name)
Screening result returned
in the response

Flow B — asynchronous (ingestion-triggered screening)

The Customer Ingestion API accepts a name_screening_enabled field (defaulting to true when omitted), so ingesting a customer can trigger screening as a side effect rather than requiring a separate call to the Screening API. What isn't yet confirmed in this documentation is the exact delivery mechanism for that result back to your system — likely a webhook, but confirm the specifics with your Fyscaltech integration contact before building against it.

Customer Record
Customer Ingestion API
(name_screening_enabled: true)
Screening runs
as a side effect
Result delivery mechanism
— confirm with Fyscaltech

Bulk CSV — batch (sits outside both flows)

Bulk CSV uploads are for getting Customer, Customer Account, and Customer Transaction data into the platform in volume, rather than triggering an immediate screening result back to your system. Screening or monitoring against that data happens on the platform's own schedule (see Name Screening's Batch and Delta Screening, and Transaction Monitoring's execution intervals) rather than as a direct response to the upload.

Choosing sync vs. async

PatternUse it when
Synchronous (Flow A)You need the result immediately in your own onboarding flow — e.g. blocking account opening until screening completes
Asynchronous (Flow B)You're already pushing customer records via the Ingestion API and prefer not to poll — results land on your webhook as they complete
Batch (Bulk CSV)You're loading or refreshing large populations, and don't need a per-record result back in real time
Note. 

Full request/response detail for both APIs is now documented under Integration Methods. Visual sequence-timing diagrams aren't available yet, but the endpoint paths, payload shapes, and response envelopes above are enough to build against.

Webhooks & Events

A webhook would only be relevant if you're using the Customer Ingestion API's name_screening_enabled flag to trigger screening as part of ingesting a customer record, rather than calling the Screening API directly. Whether delivery actually happens via webhook — versus some other mechanism — isn't confirmed yet; the pattern below is the expected shape, not a confirmed spec.

How it works (expected pattern, not yet confirmed)

  • Unlike Bulk CSV, a webhook endpoint would be hosted and owned by you, not Fyscaltech
  • Fyscaltech would provide the request format and signature-verification guidelines once finalized
Will be published soon once received from technical team. 

Confirmed event names and payload structures for webhook deliveries haven't been provided yet. What is confirmed: ingestion accepts a name_screening_enabled flag (see Customer Ingestion API), so screening can run as a side effect of ingestion — the exact event/delivery format for that result is what's pending here.

Note. 

This webhook is only needed for the ingest-then-screen flow through the Customer Ingestion API. If you only use bulk CSV ingestion, or call the Screening API directly for each check, you don't need to set up a webhook at all.

Errors, Limits & Best Practices

Both the Customer Ingestion API and Screening API return the business error codes below alongside their HTTP status.

Business error codes

Business-level error codes sit alongside the HTTP status and identify the specific validation or business rule that failed. Confirmed codes so far, from Customer Ingestion API and Screening API:

CodeAPIHTTPMeaning
BR001Customer Ingestion400Malformed body, empty body, or a required field missing
SWW01Customer Ingestion500Internal queue/publish failure
VALIDATION_ERRORScreening400Bad or missing customer_name, invalid customer_type, or wrong field types
CONFLICTScreening409Mongo duplicate key
REDIS_CONNECTION_ERRORScreening503Redis config-load connection failure
REDIS_OPERATION_ERRORScreening500Redis config-load operation failure
DATABASE_QUERY_FAILEDScreening500Postgres ledger write fails (/screen only)
INTERNAL_SERVER_ERRORScreening500Any unmapped internal error — the underlying message is passed through

Both APIs share a similar response envelope shape (code + message, with Screening additionally carrying a data field) — check code first for programmatic handling, and treat message as human-readable detail rather than something to match against in logic.

Best practices

Will be published soon once received from technical team. 

Specific guidance (idempotency behavior, retry/backoff recommendations, rate limits) for the Customer Ingestion and Screening APIs hasn't been confirmed yet. The one thing already confirmed: for bulk CSV, check the FT AML console under Data Ingestion to confirm a file was picked up and processed successfully — a successful S3 upload only means the file arrived, not that every row passed validation.

Note. 

Rate limit thresholds aren't documented yet — confirm current limits with your Fyscaltech integration contact before load-testing against these endpoints.

Testing & Sandbox

For bulk CSV ingestion, the same S3 location and console feedback (Data Ingestion job status) apply regardless of whether you're testing or in production, so start with a small file to confirm your CSV format is accepted before uploading your full population.

Will be published soon once received from technical team. 

Whether a separate sandbox/test environment exists for the Customer Ingestion and Screening APIs, and what test data it ships with, hasn't been confirmed yet.

Troubleshooting & FAQ

Common issues

IssueLikely cause & resolution
Bulk CSV file stuck in ProcessingCheck the source file for encoding or column issues; confirm in the console under Data Ingestion, and escalate to Fyscaltech if it doesn't clear
Screening API returns no matches for a known nameConfirm the name is being submitted exactly as registered; remember the API currently matches on full name only, not date of birth, address, or citizenship
Customer Ingestion call succeeds but no screening result appearsConfirm name_screening_enabled was set (it defaults to true if omitted), then check Alert Manager directly — the result-delivery mechanism back to your system isn't confirmed yet, see Webhooks & Events

Frequently asked questions

Can we use more than one integration method at once?

Yes — most institutions use Bulk CSV for the initial customer population, then the Customer Ingestion API and/or Screening API for ongoing, real-time updates.

Do we need a webhook if we only use the Screening API?

No. Calling the Screening API directly returns the result in the same response — a webhook is only needed for the ingest-then-screen flow via the Customer Ingestion API.

Is there a sandbox we can test against before going live?

Not confirmed yet — see Testing & Sandbox.

Can the Screening API match on more than full name?

Not currently — it supports full name matching only. Additional matching fields (date of birth, address, citizenship) are available through Manual Screening in the console today.

Where do we find upcoming API changes before they land?

Keep a point of contact with the Fyscaltech integration team, and check Resources & Changelog once a public changelog is published.

Glossary

Terms and field names used throughout this Developer Portal, defined for anyone integrating for the first time.

TermMeaning
AML / CTFAnti-Money Laundering / Counter-Terrorist Financing
KYCKnow Your Customer — the due-diligence fields carried on a Customer Record (kyc_level, kyc_level_description, kyc_authorized_signatory_name)
PEPPolitically Exposed Person — surfaced on a Customer Record as pep_flag
customer_typeWhether a record is Individual or Corporate (Customer Ingestion API) / Individual or Entity (Screening API) — the two APIs use slightly different values for this field
risk_level / risk_scoreThe customer's assessed AML risk, as a category (LOW/MEDIUM/HIGH) and a numeric score
sanctions_statusWhether a customer has a known sanctions hit on file, independent of a live Screening API call
WatchlistThe sanctions/PEP/adverse-media data source the Screening API matches against
Full name screeningMatching based on the customer's full name — currently the only field the Screening API supports
alert_score / alert_categoryThe Screening API's match confidence (0–100) and its banded severity (e.g. HIGH)
entity_key / screening_idIdentifiers in a Screening API response used to trace a specific screening run
Bulk ingestionLoading data via CSV file upload to S3, as opposed to the record-by-record Customer Ingestion API
MLROMoney Laundering Reporting Officer — approves SAR/STR filings
SAR / STRSuspicious Activity / Transaction Report filed with regulators
Will be published soon once received from technical team. 

Additional terms will be added here as more of the platform's API surface is confirmed.

Developer Community

A space for developers integrating with FT AML to ask questions, share patterns, and hear from each other — not just from Fyscaltech directly.

Will be published soon once received from technical team. 

This section is a placeholder — content, links, and setup for a developer community (forum, Slack/Discord, discussion board, or similar) will be added here once provided.

Resources & Changelog

Downloadable and reference materials to speed up integration work. Anything not yet available will be published soon once received from technical team.

Postman Collection

A ready-to-import collection covering the Customer Ingestion and Screening APIs. Will be published soon once received from technical team.

Pending

OpenAPI Specification

Machine-readable spec for generating clients or importing into your own API tooling. Will be published soon once received from technical team.

Pending

CSV Templates

The exact Customer and Account file headers are already documented in full under Bulk CSV via S3 — copy them directly from there.

Available

Release Notes

A running log of platform and API changes. Will be published soon once received from technical team.

Pending

SDKs

Official client libraries for common languages, planned for a future release.

Future

Fyscaltech Integration Team

The most reliable resource today — see Support for contact details.

Changelog & versioning

As the Customer Ingestion and Screening APIs move from onboarding-provided specifications toward a stable published reference, changes will be communicated directly by the Fyscaltech integration team. If you're integrated against either API, keeping a point of contact with the team (see Support) is the most reliable way to hear about upcoming changes before they land.

Note. 

A formal versioning policy and public changelog will be published here once the API reference itself is finalized.

Support

  • In-app: Homepage > Help & Support
  • Email: hello@fyscaltech.com
  • Phone: +65 8080 5424
  • Headquarters: Singapore · 68 Circular Road
  • Account-level issues (API key provisioning, permissions) — contact your organization's Admin

What to include when you contact us

To help us resolve integration issues quickly, please include: the environment (sandbox/production), the endpoint and HTTP method, the X-Request-Id from the response headers if available, and a timestamp of when the issue occurred.

Thank you for building on FT AML.