Shield

Send transactions

Send every transaction, including small ones: velocity and AML rules only see what they are sent.

PilotShield is in pilot and enabled per account on request. Without it every Shield endpoint answers 404.

Send a transaction

POST /api/Transaction/ExecuteTransaction takes SanctionScanner's transaction model and answers with the decision in the same call.

curl -X POST https://api.verifex.dev/api/Transaction/ExecuteTransaction \
  -u "key_id:vfx_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
  "transactionID": "TXN-1001",
  "transactionDate": "2026-10-01T09:30:00Z",
  "amount": "6000.00",
  "amountCurrencyCode": 944,
  "direction": 2,
  "source": 1,
  "channel": 1,
  "triggeredRuleSetKey": "your-ruleset-key",
  "originatorNumber": "CUST-1001",
  "originator": "Aysel Mammadova",
  "originatorAccountCurrencyCode": 944,
  "beneficiary": "Kamran Aliyev",
  "beneficiaryAccountNumber": "AZ21NABZ00000000137010001944",
  "beneficiaryAccountCurrencyCode": 944
}'

Required fields

  • transactionID (your id; also the idempotency key), transactionDate (UTC, ending in Z), amount, amountCurrencyCode, originatorAccountCurrencyCode, beneficiaryAccountCurrencyCode, source, channel, direction, triggeredRuleSetKey, and originatorNumber (without it no per-customer rule can work).
  • Currencies are ISO 4217 numeric codes (944 AZN, 840 USD); the letter code is accepted too.
  • direction: 1 Inbound, 2 Outbound, 3 both. It decides which side is your customer: inbound → the beneficiary, otherwise the originator. The other side is screened for sanctions and PEP.
  • amount may be a number or a decimal string and is parsed exactly; more decimals than the currency has is a 400, never rounded. Send numbers over 15 significant digits as strings.
  • A non-AZN amount needs baseMultiply (the rate to AZN). Without it no amount rule can run, so the transaction is held for review with reason BASE_AMOUNT_UNKNOWN.
  • Unknown top-level fields are refused (UNKNOWN_FIELDS). Shield-only inputs (device signals, SIMA profile, behaviour) go in an optional shield object.

Fields specific checks need

  • Counterparty name: beneficiary on an outbound transfer, originator on an inbound one. It is what Shield screens for sanctions and PEP. Without it the transaction is allowed and marked not screened (COUNTERPARTY_NOT_SCREENED). Add beneficiaryTypeId / originatorTypeId (1 individual, 2 entity) when you know it.
  • customerIdentity: the sender's identity document number. The monthly AML checks (S2 activity, S3 beneficiaries) group a sender's transfers by it; without it they fall back to originatorNumber.
  • optionalParameters → dailyLimit: the sender's daily transfer limit in AZN, as a plain decimal ({ "key": "dailyLimit", "value": "5000.00" }). S1 counts the days the sender reached it; Shield works out the limit hits itself.
  • beneficiaryAccountNumber (card hash or IBAN): S3 and S4 count distinct accounts by it. Never a full card number.

Reading the answer

Every response uses the SanctionScanner envelope, with the HTTP status set to the same code. Act on result.shield.outcome; totalScore and triggeredAlarm keep SanctionScanner's meaning. The outcome is Shield's recommendation; your system carries it out:

  • clear: let it through.
  • review: let it through; a case is opened for a person to look at afterwards.
  • delay: hold it briefly, then review.
  • escalate: hold it until a senior reviewer decides.
  • block: stop it.

If the sanctions check could not complete, compliance.degraded is true and the outcome is never clear.

// Abridged: the fields to act on. revision / supersedesCapsuleId appear after a ChangeTransaction.
{
  "httpStatusCode": 200, "isSuccess": true, "errorCode": null, "errorMessage": null, "extraInfo": null,
  "result": {
    "transactionId": "TXN-1001",
    "totalScore": 70,
    "triggeredAlarm": "Low",
    "triggeredRulesList": [{ "ruleKey": "…", "score": 70 }],
    "shield": {
      "outcome": "review",
      "riskScore": 70,
      "humanReviewRequired": true,
      "rulesTriggered": [{ "ruleId": "TXN_01", "name": "High-Value Transaction", "mode": "active",
                           "riskContribution": 70, "reason": "Amount … at or above …" }],
      "compliance": { "screened": true, "sanctionsMatch": false, "pepMatch": false,
                      "degraded": false, "incomplete": false },
      "capsuleId": "…",
      "caseId": "…"
    }
  }
}

Retries and idempotency

transactionID is the idempotency key per account. Re-sending the same body returns the stored answer unchanged (header X-Idempotent-Replay: true) and changes no counter, so retrying after a timeout is safe. The same id with a different body is 409 IDEMPOTENCY_KEY_REUSED — to change a transaction, use ChangeTransaction.

Card numbers are refused

A full card number anywhere in a request — any field, key, note, metadata, the path or the query string, with any separator — is refused with PAN_NOT_ALLOWED, on every Shield endpoint. Send masked numbers (416973******1234). A real IBAN in an IBAN or account-number field is accepted however it is spaced.

Late transactions

AML months follow transactionDate in your account's time zone (default Asia/Baku). A transaction may be dated in the current month, or in the previous month until day 5 of the current one; anything older is 400 VALIDATION_FAILED. A late transaction counts in its own month and is flagged late.

Changing a transaction

POST /api/Transaction/ChangeTransaction/{transactionId} (also Resend/{id} with a body) replaces the transaction and decides it again. The earlier decision is kept as evidence and marked superseded; the AML month figures drop the old version before counting the new one, so a transfer changed to declined, refunded or another amount leaves exact S1–S4 figures. A rule that already fired is not retracted. The transaction keeps its case — unless that case was closed, in which case a change that needs review opens a new one. A late retry of an earlier change gets the current answer and does not undo a newer change.

Warning

A transaction in a month already closed for reporting cannot be changed (409 TRANSACTION_PERIOD_CLOSED).