> ## Documentation Index
> Fetch the complete documentation index at: https://docs.didit.me/llms.txt
> Use this file to discover all available pages before exploring further.

# API Buat Aturan Pemantauan Transaksi - Aturan KYT

> Buat aturan KYT kustom via API: kondisi, jendela velocity, cakupan, dan tindakan dengan skema lengkap. Buat dalam mode TEST, backtest, lalu aktifkan di Didit.



Prompt API untuk Membuat Aturan
        Salin prompt ke papan klip



      
      

\<pre>

\`Create a custom transaction-monitoring rule on my Didit application.

Endpoint:
POST https://verification.didit.me/v3/transactions/rules/

Authentication:
Use the x-api-key header with my Didit API key.

Request body (application/json):
\{
"title": "Structuring - inbound (custom)",   // required, unique per application - duplicate -> 400
"description": "20+ inbound EUR transfers, all under 10,000 EUR, 30 days",
"category": "finance",                        // required: finance, aml_ctf, anomaly_detection, fatf, device_intelligence, crypto_monitoring, travel_rule, responsible_gaming, e_commerce, ...
"mode": "TEST",                               // required: TEST (recommended start - evaluates, never affects transactions), ACTIVE, DISABLED
"evaluation_mode": "ALL",                     // ALL = every condition must match, ANY = at least one
"scope": {"transaction_types": ["finance"], "directions": ["INBOUND"]},  // constrains the transaction being evaluated; optional keys: transaction_types, directions (INBOUND/OUTBOUND), action_types
"conditions": [                               // read the transaction being evaluated, never the history window
\{"field": "currency", "operator": "eq", "value": "EUR"},
\{"field": "amount", "operator": "lt", "value": 10000}
],
"aggregation": [                              // velocity over the history window: ALL entries must match
\{"metric": "count", "operator": "gte", "value": 20, "window": "30d",
 "filters": {"direction": "INBOUND", "transaction_type": "finance", "currency": "EUR", "subject_vendor_data": "__current__"}},
\{"metric": "max", "field": "amount", "operator": "lt", "value": 10000, "window": "30d",
 "filters": {"direction": "INBOUND", "transaction_type": "finance", "currency": "EUR", "subject_vendor_data": "__current__"}}
],
"actions": [{"type": "add_score", "value": 35}]
}

Schema essentials:
\- Condition operators: eq, ne, gt, gte, lt, lte, in, not_in, contains, not_contains, contains_any (list of strings), regex, fuzzy_match (needs "score" 0-100), exists/is_not_empty/is_not_null, not_exists/is_empty/is_null.
\- Condition fields include amount, preferred_currency_amount, direction, action_type, payment_details, subject_vendor_data, counterparty_country, subject_device_fingerprint, subject_payment_method_*, travel_rule_status, tags, and custom_values.<key> for your own custom_properties.
\- value_type turns "value" into a List UUID ("list"), another field path ("field"), or a relative date ("relative_date").
\- Aggregation windows: <N>m (MINUTES), <N>h, <N>d. A filter value of "__current__" means same-as-the-evaluated-transaction. Records without the grouped value are never grouped together: when the evaluated transaction has no value for a "__current__" field (no counterparty, no device fingerprint), that aggregation does not match, whatever its operator.
\- Conditions and aggregation filters are NOT interchangeable. A condition constrains only the transaction being evaluated; an aggregation filter constrains only the historical window, and it compares by equality or list membership - there is no lt/gte filter. Express a range over the window as a max/min aggregation (e.g. max amount lt 10000 with currency pinned to EUR keeps every transaction in that window under 10,000 EUR), and repeat direction/currency/transaction_type on BOTH halves when the rule promises them - otherwise the rule fires on transactions it never meant to cover.
\- Actions: add_score {value}, change_status {value, workflow_id (REQUIRED for AWAITING_USER)}, add_tags {tag_uuid|tag_name, tag_color}, add_note {note}, add_to_list {list_id}, open_case {blueprint, grouping, attach_matched_transaction}.

Recommended workflow:
1\. Create in mode TEST.
2\. POST /v3/transactions/rules/backtest/ with the SAME conditions, aggregation, evaluation_mode and scope to see matches over your history. Omitted conditions, aggregation and scope add no constraints of their own; dropping scope can include directions or transaction types the saved rule skips. Omitted evaluation_mode defaults to ALL (which can reduce matches for an ANY rule), and omitted period_days defaults to 90 days, not unlimited history.
3\. PATCH the rule to mode ACTIVE once the numbers look right.

Sandbox fixtures for this example: at least 20 inbound EUR finance transactions for the same subject within 30 days, each with raw amount below 10000. No normalized amount is required. Sandbox ingestion does not evaluate rules; call backtest explicitly.

Failure modes:
\- 400 - duplicate title, unknown operator/metric, malformed window, invalid scope direction, contains_any without a list, fuzzy_match without a score, or AWAITING_USER without workflow_id. The body names the exact index and problem.
\- 401 - missing or malformed x-api-key.

Full guide: /transaction-monitoring/rules-api.`

\</pre>



      
      

Tempel ke



## OpenAPI

````yaml id/openapi-25.json POST /v3/transactions/rules/
openapi: 3.0.0
info:
  version: 3.0.0
  title: Didit Verification API
  description: API Verifikasi Identitas. Lakukan autentikasi dengan header x-api-key.
servers:
  - url: https://verification.didit.me
security: []
tags: []
paths:
  /v3/transactions/rules/:
    post:
      tags:
        - Transactions
      summary: Buat aturan
      description: >-
        Buat aturan pemantauan transaksi CUSTOM. Judul unik per aplikasi
        (duplikat -> 400). Tindakan `change_status` yang menargetkan
        `AWAITING_USER` harus menyertakan `workflow_id`. Aturan yang dibuat
        dalam mode ACTIVE langsung berlaku untuk transaksi baru - alur kerja
        yang disarankan adalah membuat dalam mode TEST, lakukan backtest, lalu
        alihkan mode ke ACTIVE. Untuk mengubah aturan pustaka, buat sebagai
        salinan: kirim definisi aturan pustaka dengan `metadata.based_on` (kunci
        pustakanya) dan `metadata.based_on_rule_uuid`.
      operationId: createTransactionRule
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TransactionRuleCreateRequest'
            example:
              title: Structuring - inbound (custom)
              description: 20+ inbound EUR transfers, all under 10,000 EUR, 30 days
              category: finance
              mode: TEST
              evaluation_mode: ALL
              scope:
                transaction_types:
                  - finance
                directions:
                  - INBOUND
              conditions:
                - field: currency
                  operator: eq
                  value: EUR
                - field: amount
                  operator: lt
                  value: 10000
              aggregation:
                - metric: count
                  operator: gte
                  value: 20
                  window: 30d
                  filters:
                    direction: INBOUND
                    transaction_type: finance
                    subject_vendor_data: __current__
                    currency: EUR
                - metric: max
                  field: amount
                  operator: lt
                  value: 10000
                  window: 30d
                  filters:
                    direction: INBOUND
                    transaction_type: finance
                    subject_vendor_data: __current__
                    currency: EUR
              actions:
                - type: add_score
                  value: 35
      responses:
        '201':
          description: Aturan yang dibuat.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TransactionRuleDetail'
        '400':
          description: >-
            Kesalahan validasi - judul duplikat, operator/metrik tidak dikenal,
            window salah format, arah cakupan tidak valid, atau AWAITING_USER
            tanpa workflow_id.
          content:
            application/json:
              schema:
                type: object
              example:
                title:
                  - A rule with this name already exists.
      security:
        - ApiKeyAuth: []
      x-codeSamples:
        - lang: curl
          label: curl
          source: >-
            curl -X POST 'https://verification.didit.me/v3/transactions/rules/'
            \
              -H 'x-api-key: YOUR_API_KEY' \
              -H 'Content-Type: application/json' \
              -d '{"title": "Structuring - inbound (custom)", "description": "20+ inbound EUR transfers, all under 10,000 EUR, 30 days", "category": "finance", "mode": "TEST", "evaluation_mode": "ALL", "scope": {"transaction_types": ["finance"], "directions": ["INBOUND"]}, "conditions": [{"field": "currency", "operator": "eq", "value": "EUR"}, {"field": "amount", "operator": "lt", "value": 10000}], "aggregation": [{"metric": "count", "operator": "gte", "value": 20, "window": "30d", "filters": {"direction": "INBOUND", "transaction_type": "finance", "subject_vendor_data": "__current__", "currency": "EUR"}}, {"metric": "max", "field": "amount", "operator": "lt", "value": 10000, "window": "30d", "filters": {"direction": "INBOUND", "transaction_type": "finance", "subject_vendor_data": "__current__", "currency": "EUR"}}], "actions": [{"type": "add_score", "value": 35}]}'
        - lang: python
          label: Python
          source: |-
            from didit import Didit

            # Reads DIDIT_API_KEY.
            client = Didit()

            result = client.transactions.rules.create(
                title="Structuring - inbound (custom)",
                description="20+ inbound EUR transfers, all under 10,000 EUR, 30 days",
                category="finance",
                mode="TEST",
                evaluation_mode="ALL",
                scope={
                    "transaction_types": ["finance"],
                    "directions": ["INBOUND"],
                },
                conditions=[{
                    "field": "currency",
                    "operator": "eq",
                    "value": "EUR",
                }, {
                    "field": "amount",
                    "operator": "lt",
                    "value": 10000,
                }],
                aggregation=[{
                    "metric": "count",
                    "operator": "gte",
                    "value": 20.0,
                    "window": "30d",
                    "filters": {"direction": "INBOUND", "transaction_type": "finance", "subject_vendor_data": "__current__", "currency": "EUR"},
                }, {
                    "metric": "max",
                    "field": "amount",
                    "operator": "lt",
                    "value": 10000.0,
                    "window": "30d",
                    "filters": {"direction": "INBOUND", "transaction_type": "finance", "subject_vendor_data": "__current__", "currency": "EUR"},
                }],
                actions=[{
                    "type": "add_score",
                    "value": 35,
                }],
            )
            print(result)
        - lang: javascript
          label: Node.js
          source: |-
            import Didit from "@didit-protocol/sdk-node";

            // Reads DIDIT_API_KEY.
            const didit = new Didit();

            const result = await didit.transactions.rules.create({
              title: "Structuring - inbound (custom)",
              description: "20+ inbound EUR transfers, all under 10,000 EUR, 30 days",
              category: "finance",
              mode: "TEST",
              evaluation_mode: "ALL",
              scope: {
                transaction_types: ["finance"],
                directions: ["INBOUND"],
              },
              conditions: [{
                field: "currency",
                operator: "eq",
                value: "EUR",
              }, {
                field: "amount",
                operator: "lt",
                value: 10000,
              }],
              aggregation: [{
                metric: "count",
                operator: "gte",
                value: 20.0,
                window: "30d",
                filters: { direction: "INBOUND", transaction_type: "finance", subject_vendor_data: "__current__", currency: "EUR" },
              }, {
                metric: "max",
                field: "amount",
                operator: "lt",
                value: 10000.0,
                window: "30d",
                filters: { direction: "INBOUND", transaction_type: "finance", subject_vendor_data: "__current__", currency: "EUR" },
              }],
              actions: [{
                type: "add_score",
                value: 35,
              }],
            });
            console.log(result);
        - lang: go
          label: Go
          source: "ctx := context.Background()\n// Reads DIDIT_API_KEY.\nclient := didit.NewClient()\n\nresult, err := client.Transactions.Rules.Create(ctx, didit.TransactionRuleCreateRequest{\n\tTitle:          \"Structuring - inbound (custom)\",\n\tDescription:    didit.String(\"20+ inbound EUR transfers, all under 10,000 EUR, 30 days\"),\n\tCategory:       \"finance\",\n\tMode:           \"TEST\",\n\tEvaluationMode: didit.Some(didit.TransactionRuleCreateRequestEvaluationMode(\"ALL\")),\n\tScope: didit.Some(didit.TransactionRuleScopeParam{\n\t\tTransactionTypes: didit.Some([]string{\"finance\"}),\n\t\tDirections:       didit.Some([]didit.TransactionRuleScopeDirections{\"INBOUND\"}),\n\t}),\n\tConditions: didit.Some([]didit.TransactionRuleConditionParam{{\n\t\tField:    \"currency\",\n\t\tOperator: \"eq\",\n\t\tValue:    didit.Some[any](\"EUR\"),\n\t}, {\n\t\tField:    \"amount\",\n\t\tOperator: \"lt\",\n\t\tValue:    didit.Some[any](10000),\n\t}}),\n\tAggregation: didit.Some([]didit.TransactionRuleAggregationParam{{\n\t\tMetric:   didit.Some(didit.TransactionRuleAggregationMetric(\"count\")),\n\t\tOperator: didit.Some(didit.TransactionRuleAggregationOperator(\"gte\")),\n\t\tValue:    20.0,\n\t\tWindow:   didit.String(\"30d\"),\n\t\tFilters:  didit.Some(map[string]any{\"direction\": \"INBOUND\", \"transaction_type\": \"finance\", \"subject_vendor_data\": \"__current__\", \"currency\": \"EUR\"}),\n\t}, {\n\t\tMetric:   didit.Some(didit.TransactionRuleAggregationMetric(\"max\")),\n\t\tField:    didit.String(\"amount\"),\n\t\tOperator: didit.Some(didit.TransactionRuleAggregationOperator(\"lt\")),\n\t\tValue:    10000.0,\n\t\tWindow:   didit.String(\"30d\"),\n\t\tFilters:  didit.Some(map[string]any{\"direction\": \"INBOUND\", \"transaction_type\": \"finance\", \"subject_vendor_data\": \"__current__\", \"currency\": \"EUR\"}),\n\t}}),\n\tActions: didit.Some([]didit.TransactionRuleActionParam{{\n\t\tType:  \"add_score\",\n\t\tValue: didit.Some[any](35),\n\t}}),\n})\nif err != nil {\n\tlog.Fatal(err)\n}\nfmt.Printf(\"%+v\\n\", result)"
        - lang: java
          label: Java
          source: >-
            import java.util.List;

            import java.util.Map;

            import me.didit.Didit;

            import me.didit.types.TransactionRuleAction;

            import me.didit.types.TransactionRuleActionAddScore;

            import me.didit.types.TransactionRuleAggregation;

            import me.didit.types.TransactionRuleCondition;

            import me.didit.types.TransactionRuleCreateRequest;

            import me.didit.types.TransactionRuleScope;


            // Reads DIDIT_API_KEY.

            Didit client = new Didit();


            var result =
            client.transactions().rules().create(TransactionRuleCreateRequest.builder()
                    .title("Structuring - inbound (custom)")
                    .description("20+ inbound EUR transfers, all under 10,000 EUR, 30 days")
                    .category("finance")
                    .mode(TransactionRuleCreateRequest.Mode.of("TEST"))
                    .evaluationMode(TransactionRuleCreateRequest.EvaluationMode.of("ALL"))
                    .scope(TransactionRuleScope.builder()
                            .transactionTypes(List.of("finance"))
                            .directions(List.of(TransactionRuleScope.Directions.of("INBOUND")))
                            .build())
                    .conditions(List.of(
                            TransactionRuleCondition.builder()
                                    .field("currency")
                                    .operator(TransactionRuleCondition.Operator.of("eq"))
                                    .value("EUR")
                                    .build(),
                            TransactionRuleCondition.builder()
                                    .field("amount")
                                    .operator(TransactionRuleCondition.Operator.of("lt"))
                                    .value(10000)
                                    .build()))
                    .aggregation(List.of(
                            TransactionRuleAggregation.builder()
                                    .metric(TransactionRuleAggregation.Metric.of("count"))
                                    .operator(TransactionRuleAggregation.Operator.of("gte"))
                                    .value(20.0)
                                    .window("30d")
                                    .filters(Map.of("direction", "INBOUND", "transaction_type", "finance", "subject_vendor_data", "__current__", "currency", "EUR"))
                                    .build(),
                            TransactionRuleAggregation.builder()
                                    .metric(TransactionRuleAggregation.Metric.of("max"))
                                    .field("amount")
                                    .operator(TransactionRuleAggregation.Operator.of("lt"))
                                    .value(10000.0)
                                    .window("30d")
                                    .filters(Map.of("direction", "INBOUND", "transaction_type", "finance", "subject_vendor_data", "__current__", "currency", "EUR"))
                                    .build()))
                    .actions(List.of(TransactionRuleAction.ofAddScore(TransactionRuleActionAddScore.builder()
                            .type(TransactionRuleActionAddScore.Type.of("add_score"))
                            .value(35L)
                            .build())))
                    .build());
            System.out.println(result);
        - lang: php
          label: PHP
          source: |-
            <?php

            require 'vendor/autoload.php';

            use Didit\DiditClient;

            // Reads DIDIT_API_KEY.
            $didit = new DiditClient();

            $result = $didit->transactions->rules->create([
                'title' => 'Structuring - inbound (custom)',
                'description' => '20+ inbound EUR transfers, all under 10,000 EUR, 30 days',
                'category' => 'finance',
                'mode' => 'TEST',
                'evaluation_mode' => 'ALL',
                'scope' => [
                    'transaction_types' => ['finance'],
                    'directions' => ['INBOUND'],
                ],
                'conditions' => [[
                    'field' => 'currency',
                    'operator' => 'eq',
                    'value' => 'EUR',
                ], [
                    'field' => 'amount',
                    'operator' => 'lt',
                    'value' => 10000,
                ]],
                'aggregation' => [[
                    'metric' => 'count',
                    'operator' => 'gte',
                    'value' => 20.0,
                    'window' => '30d',
                    'filters' => ['direction' => 'INBOUND', 'transaction_type' => 'finance', 'subject_vendor_data' => '__current__', 'currency' => 'EUR'],
                ], [
                    'metric' => 'max',
                    'field' => 'amount',
                    'operator' => 'lt',
                    'value' => 10000.0,
                    'window' => '30d',
                    'filters' => ['direction' => 'INBOUND', 'transaction_type' => 'finance', 'subject_vendor_data' => '__current__', 'currency' => 'EUR'],
                ]],
                'actions' => [[
                    'type' => 'add_score',
                    'value' => 35,
                ]],
            ]);
            print_r($result->toArray());
        - lang: ruby
          label: Ruby
          source: |-
            require "didit"

            # Reads DIDIT_API_KEY.
            didit = Didit::Client.new

            result = didit.transactions.rules.create(
              title: "Structuring - inbound (custom)",
              description: "20+ inbound EUR transfers, all under 10,000 EUR, 30 days",
              category: "finance",
              mode: "TEST",
              evaluation_mode: "ALL",
              scope: {
                transaction_types: ["finance"],
                directions: ["INBOUND"],
              },
              conditions: [{
                field: "currency",
                operator: "eq",
                value: "EUR",
              }, {
                field: "amount",
                operator: "lt",
                value: 10000,
              }],
              aggregation: [{
                metric: "count",
                operator: "gte",
                value: 20.0,
                window: "30d",
                filters: { direction: "INBOUND", transaction_type: "finance", subject_vendor_data: "__current__", currency: "EUR" },
              }, {
                metric: "max",
                field: "amount",
                operator: "lt",
                value: 10000.0,
                window: "30d",
                filters: { direction: "INBOUND", transaction_type: "finance", subject_vendor_data: "__current__", currency: "EUR" },
              }],
              actions: [{
                type: "add_score",
                value: 35,
              }]
            )
            puts result.to_h
        - lang: csharp
          label: .NET
          source: >-
            using System;

            using System.Collections.Generic;

            using System.Text.Json;

            using Didit;


            // Reads DIDIT_API_KEY.

            using var client = new DiditClient();


            var result = await client.Transactions.Rules.CreateAsync(new
            TransactionRuleCreateRequest

            {
                Title = "Structuring - inbound (custom)",
                Description = "20+ inbound EUR transfers, all under 10,000 EUR, 30 days",
                Category = "finance",
                Mode = "TEST",
                EvaluationMode = new TransactionRuleCreateRequestEvaluationMode("ALL"),
                Scope = new TransactionRuleScope
                {
                    TransactionTypes = new string[] { "finance" },
                    Directions = new TransactionRuleScopeDirections[] { "INBOUND" },
                },
                Conditions = new TransactionRuleCondition[]
                {
                    new()
                    {
                        Field = "currency",
                        Operator = "eq",
                        Value = "EUR",
                    },
                    new()
                    {
                        Field = "amount",
                        Operator = "lt",
                        Value = 10000,
                    },
                },
                Aggregation = new TransactionRuleAggregation[]
                {
                    new()
                    {
                        Metric = new TransactionRuleAggregationMetric("count"),
                        Operator = new TransactionRuleAggregationOperator("gte"),
                        Value = 20.0,
                        Window = "30d",
                        Filters = new Dictionary<string, object> { ["direction"] = "INBOUND", ["transaction_type"] = "finance", ["subject_vendor_data"] = "__current__", ["currency"] = "EUR" },
                    },
                    new()
                    {
                        Metric = new TransactionRuleAggregationMetric("max"),
                        Field = "amount",
                        Operator = new TransactionRuleAggregationOperator("lt"),
                        Value = 10000.0,
                        Window = "30d",
                        Filters = new Dictionary<string, object> { ["direction"] = "INBOUND", ["transaction_type"] = "finance", ["subject_vendor_data"] = "__current__", ["currency"] = "EUR" },
                    },
                },
                Actions = new TransactionRuleAction[]
                {
                    new()
                    {
                        Type = new TransactionRuleActionType("add_score"),
                        Value = 35,
                    },
                },
            });

            Console.WriteLine(JsonSerializer.Serialize(result));
components:
  schemas:
    TransactionRuleCreateRequest:
      type: object
      required:
        - title
        - category
        - mode
      properties:
        title:
          type: string
          description: >-
            Nama aturan. Unik per aplikasi di antara aturan yang tidak dihapus;
            duplikat menghasilkan 400.
        description:
          type: string
          nullable: true
        category:
          type: string
          description: >-
            Tema risiko yang digunakan untuk pengelompokan dan pelaporan, mis.
            finance, aml_ctf, anomaly_detection, fatf, device_intelligence,
            crypto_monitoring, travel_rule, responsible_gaming, e_commerce.
        mode:
          type: string
          enum:
            - ACTIVE
            - DISABLED
            - TEST
          description: >-
            ACTIVE mengevaluasi secara langsung. TEST mengevaluasi dan mencatat
            eksekusi aturan tetapi tidak pernah memengaruhi skor atau status -
            mode awal yang disarankan. DISABLED dilewati.
        evaluation_mode:
          type: string
          enum:
            - ALL
            - ANY
          default: ALL
          description: >-
            Menentukan apakah setiap kondisi harus cocok (ALL) atau setidaknya
            satu (ANY). Diabaikan jika kondisi menggunakan group_index.
        scope:
          $ref: '#/components/schemas/TransactionRuleScope'
        conditions:
          type: array
          items:
            $ref: '#/components/schemas/TransactionRuleCondition'
        aggregation:
          type: array
          items:
            $ref: '#/components/schemas/TransactionRuleAggregation'
        actions:
          type: array
          items:
            $ref: '#/components/schemas/TransactionRuleAction'
        metadata:
          type: object
          description: Metadata bentuk bebas yang disimpan pada aturan.
      description: >-
        Membuat aturan CUSTOM. Aturan dalam mode ACTIVE langsung berlaku untuk
        transaksi baru - buat dalam mode TEST dan lakukan backtest terlebih
        dahulu.
    TransactionRuleDetail:
      type: object
      properties:
        uuid:
          type: string
          format: uuid
        title:
          type: string
          description: >-
            Nama aturan. Unik per aplikasi di antara aturan yang tidak dihapus;
            duplikat menghasilkan 400.
        description:
          type: string
          nullable: true
        category:
          type: string
          description: >-
            Tema risiko yang digunakan untuk pengelompokan dan pelaporan, mis.
            finance, aml_ctf, anomaly_detection, fatf, device_intelligence,
            crypto_monitoring, travel_rule, responsible_gaming, e_commerce.
        mode:
          type: string
          enum:
            - ACTIVE
            - DISABLED
            - TEST
          description: >-
            ACTIVE mengevaluasi secara langsung. TEST mengevaluasi dan mencatat
            eksekusi aturan tetapi tidak pernah memengaruhi skor atau status -
            mode awal yang disarankan. DISABLED dilewati.
        evaluation_mode:
          type: string
          enum:
            - ALL
            - ANY
          default: ALL
          description: >-
            Menentukan apakah setiap kondisi harus cocok (ALL) atau setidaknya
            satu (ANY). Diabaikan jika kondisi menggunakan group_index.
        scope:
          $ref: '#/components/schemas/TransactionRuleScope'
        conditions:
          type: array
          items:
            $ref: '#/components/schemas/TransactionRuleCondition'
        aggregation:
          type: array
          items:
            $ref: '#/components/schemas/TransactionRuleAggregation'
        actions:
          type: array
          items:
            $ref: '#/components/schemas/TransactionRuleAction'
        metadata:
          type: object
          description: Metadata bentuk bebas yang disimpan pada aturan.
        severity:
          type: string
          enum:
            - UNKNOWN
            - LOW
            - MEDIUM
            - HIGH
            - CRITICAL
          nullable: true
          description: >-
            Tingkat keparahan informasional yang dibawa oleh aturan pustaka;
            tidak dapat diatur pada aturan kustom.
        source:
          type: string
          enum:
            - PRESET
            - CUSTOM
          description: >-
            Aturan PRESET berasal dari pustaka (instalasi/pencopotan, pengeditan
            khusus mode); aturan CUSTOM sepenuhnya milik Anda.
        library_key:
          type: string
          nullable: true
          description: Pengidentifikasi pustaka yang stabil; null untuk aturan kustom.
        latest_triggered_at:
          type: string
          format: date-time
          nullable: true
        run_count:
          type: integer
          description: Berapa banyak transaksi yang cocok dengan aturan ini.
        approved_count:
          type: integer
        reviewed_count:
          type: integer
        declined_count:
          type: integer
        awaiting_user_count:
          type: integer
        approved_pct:
          type: number
        reviewed_pct:
          type: number
        declined_pct:
          type: number
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
    TransactionRuleScope:
      type: object
      properties:
        transaction_types:
          type: array
          items:
            type: string
          description: >-
            Batasi ke jenis transaksi, mis. finance, kyc, travel_rule,
            user_event. Kosong atau tidak ada = tanpa pembatasan.
        directions:
          type: array
          items:
            type: string
            enum:
              - INBOUND
              - OUTBOUND
          description: >-
            Batasi ke arah transaksi (tidak peka huruf besar/kecil saat
            penulisan).
        action_types:
          type: array
          items:
            type: string
          description: Batasi ke nilai action_type Anda, mis. withdrawal, deposit.
      description: >-
        Transaksi mana yang dikenai aturan ini. Hanya ketiga kunci ini yang
        diterima.
    TransactionRuleCondition:
      type: object
      required:
        - field
        - operator
      properties:
        field:
          type: string
          description: >-
            Jalur kolom transaksi yang akan dievaluasi. Kolom inti: amount,
            currency, direction, action_type, score, severity, transaction_type,
            payment_details, preferred_currency_amount (beralih ke
            amount_in_default_currency jika tidak tersedia),
            default_currency_code, subject_country, counterparty_country,
            subject_vendor_data, counterparty_vendor_data,
            subject_device_fingerprint, counterparty_device_fingerprint,
            subject_browser_family, subject_browser_version, subject_platform,
            subject_accept_language, subject_session_age_ms, subject_ip_country,
            counterparty_ip_country, subject_ip_address,
            counterparty_ip_address, subject_payment_method_type,
            subject_payment_method_country, subject_payment_method_fingerprint,
            subject_payment_method_account_id (dan padanan
            counterparty_payment_method_*), travel_rule_status,
            travel_rule_required, travel_rule_obligations_count,
            counterparty_dd_status (keputusan Anda tentang pihak lawan Travel
            Rule: APPROVED, RESTRICTED, atau BLOCKED, suatu entitas yang
            mengikuti keputusan mereknya), counterparty_risk_level (LOW, MEDIUM,
            atau HIGH; HIGH saat skrining pihak lawan Anda sendiri ditandai),
            counterparty_jurisdiction (negara VASP pihak lawan),
            counterparty_responsiveness (RESPONSIVE, UNRESPONSIVE, atau
            UNKNOWN), subject_days_since_previous_transaction, tags, dan
            custom_values.<key> untuk kunci apa pun yang dikirimkan dalam
            custom_properties saat pembuatan transaksi. Kolom kode negara
            menerima ISO-2 atau ISO-3; kedua sisi dinormalisasi ke ISO-3 sebelum
            dibandingkan.
        operator:
          type: string
          enum:
            - eq
            - ne
            - gt
            - gte
            - lt
            - lte
            - in
            - not_in
            - contains
            - not_contains
            - contains_any
            - regex
            - fuzzy_match
            - exists
            - is_not_empty
            - is_not_null
            - not_exists
            - is_empty
            - is_null
          description: >-
            Operator perbandingan. in/not_in menguji keanggotaan (nilai dapat
            berupa daftar atau skalar tunggal). contains/not_contains adalah
            pemeriksaan substring tanpa membedakan huruf besar/kecil terhadap
            nilai string. contains_any menerima daftar string dan cocok jika
            salah satunya merupakan substring tanpa membedakan huruf besar/kecil
            dari nilai kolom. regex mencocokkan pola nilai terhadap kolom.
            fuzzy_match membandingkan terhadap string nilai dengan ambang batas
            `score` yang diperlukan (0-100). gt/gte/lt/lte tidak pernah cocok
            jika salah satu sisi tidak ada. exists/is_not_empty/is_not_null
            (alias) dan not_exists/is_empty/is_null (alias) adalah pemeriksaan
            keberadaan yang mengabaikan `value`.
        value:
          description: >-
            Nilai perbandingan. Bentuknya bergantung pada operator dan
            value_type; jangan sertakan untuk operator pemeriksaan keberadaan.
            Setiap operator lainnya memerlukan nilai yang bukan `null` atau
            daftar kosong, jika tidak, aturan akan ditolak dengan `400`.
            `contains_any` memerlukan daftar string, dan `contains`,
            `not_contains`, serta `regex` memerlukan string tunggal.
        value_type:
          type: string
          enum:
            - list
            - field
            - relative_date
          description: >-
            Interpretasi nilai opsional. `list`: nilai adalah UUID Daftar dan
            entri daftar menjadi nilai perbandingan. `field`: nilai adalah jalur
            kolom lain, dibandingkan antarkolom. `relative_date`: nilai adalah
            objek tanggal relatif, mis. {"direction": "past", "unit": "days",
            "amount": 30}.
        score:
          type: number
          minimum: 0
          maximum: 100
          description: >-
            Wajib jika operator adalah fuzzy_match: ambang batas kemiripan
            0-100.
        group_index:
          type: integer
          description: >-
            Logika terkelompok opsional. Ketika kondisi apa pun membawa
            group_index, kondisi yang berbagi indeks membentuk sebuah grup dan
            evaluasi terkelompok menggantikan evaluation_mode.
        group_logic:
          type: string
          enum:
            - AND
            - OR
          default: AND
          description: Cara kondisi digabungkan DI DALAM grup.
        groups_logic:
          type: string
          enum:
            - AND
            - OR
          default: OR
          description: >-
            Cara hasil grup digabungkan DI SELURUH grup. Dibaca dari kondisi
            pertama.
      description: >-
        Kondisi hanya membaca transaksi yang sedang dievaluasi - kondisi ini
        tidak pernah memfilter jendela agregasi.
    TransactionRuleAggregation:
      type: object
      required:
        - value
      properties:
        metric:
          type: string
          enum:
            - count
            - sum
            - max
            - min
            - avg
            - distinct_count
          default: count
          description: >-
            Bagaimana transaksi historis yang cocok diagregasikan. unique_count
            diterima sebagai alias dari distinct_count.
        field:
          type: string
          default: amount
          description: >-
            Kolom yang diagregasikan berdasarkan sum/max/min/avg/distinct_count.
            Diabaikan untuk count.
        operator:
          type: string
          enum:
            - eq
            - ne
            - gt
            - gte
            - lt
            - lte
          default: eq
          description: Perbandingan yang diterapkan pada metrik yang dihitung.
        value:
          type: number
          description: Ambang batas yang dibandingkan dengan metrik terhitung.
        window:
          type: string
          pattern: ^\d+(m|h|d)$
          default: 1d
          description: >-
            Periode penelusuran mundur yang berakhir pada txn_date transaksi:
            <N>m (MENIT, bukan bulan), <N>h (jam), atau <N>d (hari), misalnya
            30m, 24h, 7d, 30d.
        filters:
          type: object
          additionalProperties: true
          description: >-
            Mempersempit transaksi historis mana yang diagregasi. Kunci berupa
            jalur kolom dari katalog kolom kondisi; nilai "__current__"
            diselesaikan ke nilai kolom yang sama pada transaksi yang sedang
            dievaluasi (misalnya {"subject_vendor_data": "__current__"}
            membatasi rentang waktu pada subjek yang sama), dan nilai daftar
            berarti keanggotaan. Catatan tanpa nilai yang dikelompokkan tidak
            akan pernah dikelompokkan bersama: ketika transaksi yang dievaluasi
            tidak memiliki nilai untuk kolom "__current__" (tidak ada pihak
            lawan, tidak ada sidik jari perangkat), agregasi tidak cocok, apa
            pun operatornya. Filter HANYA membandingkan berdasarkan kesetaraan
            atau keanggotaan - tidak ada filter lt/gte, sehingga rentang seperti
            "transaksi historis di bawah 10.000" tidak dapat dinyatakan di sini.
            Tempatkan rentang pada metrik sebagai gantinya (metrik max dengan
            operator lt mempertahankan setiap transaksi di dalam rentang waktu
            di bawah ambang batas).
      description: >-
        Pemeriksaan kecepatan (velocity check) terhadap riwayat transaksi
        aplikasi di dalam jendela waktu. Setiap entri agregasi harus cocok agar
        aturan cocok, terlepas dari evaluation_mode. Agregasi hanya membatasi
        jendela waktu; transaksi yang sedang dievaluasi dibatasi oleh cakupan
        dan kondisi, jadi ulangi direction, currency, atau transaction_type di
        kedua bagian saat aturan memerlukannya.
    TransactionRuleAction:
      oneOf:
        - $ref: '#/components/schemas/TransactionRuleActionAddScore'
        - $ref: '#/components/schemas/TransactionRuleActionChangeStatus'
        - $ref: '#/components/schemas/TransactionRuleActionAddTags'
        - $ref: '#/components/schemas/TransactionRuleActionAddNote'
        - $ref: '#/components/schemas/TransactionRuleActionAddToList'
        - $ref: '#/components/schemas/TransactionRuleActionOpenCase'
      discriminator:
        propertyName: type
        mapping:
          add_score: '#/components/schemas/TransactionRuleActionAddScore'
          change_status: '#/components/schemas/TransactionRuleActionChangeStatus'
          add_tags: '#/components/schemas/TransactionRuleActionAddTags'
          add_note: '#/components/schemas/TransactionRuleActionAddNote'
          add_to_list: '#/components/schemas/TransactionRuleActionAddToList'
          open_case: '#/components/schemas/TransactionRuleActionOpenCase'
      description: >-
        Satu tindakan aturan. Suatu aturan dapat memuat beberapa tindakan;
        semuanya diterapkan bersamaan saat cocok. Aturan dalam mode TEST
        mencatat apa yang seharusnya dilakukan tanpa menerapkan tindakan apa
        pun.
    TransactionRuleActionAddScore:
      type: object
      required:
        - type
        - value
      properties:
        type:
          type: string
          enum:
            - add_score
        value:
          type: integer
          description: >-
            Poin yang ditambahkan ke skor risiko transaksi. Dapat bernilai
            negatif.
      description: >-
        Tambahkan poin ke skor risiko kumulatif transaksi; totalnya menentukan
        status melalui ambang batas peninjauan/penolakan aplikasi.
    TransactionRuleActionChangeStatus:
      type: object
      required:
        - type
        - value
      properties:
        type:
          type: string
          enum:
            - change_status
        value:
          type: string
          enum:
            - APPROVED
            - IN_REVIEW
            - DECLINED
            - AWAITING_USER
          description: >-
            Status yang akan langsung ditetapkan, terlepas dari skor. Kunci
            alias: status.
        workflow_id:
          type: string
          format: uuid
          description: >-
            DIBUTUHKAN saat nilai adalah AWAITING_USER: alur kerja verifikasi
            yang diminta untuk diselesaikan oleh subjek. Kunci alias:
            remediation_workflow_id. Didit membuat sesi remediasi yang
            di-hosting untuk subjek saat aturan terpicu.
      description: >-
        Tetapkan status transaksi secara langsung. DECLINED selalu
        diprioritaskan di antara aturan yang cocok.
    TransactionRuleActionAddTags:
      type: object
      required:
        - type
      properties:
        type:
          type: string
          enum:
            - add_tags
        tag_uuid:
          type: string
          format: uuid
          description: Tag aplikasi yang ada untuk dilampirkan.
        tag_name:
          type: string
          description: >-
            Nama tag yang akan dilampirkan; dibuat saat pertama kali digunakan
            (disimpan dalam huruf besar). Berikan tag_uuid atau tag_name.
        tag_color:
          type: string
          description: >-
            Warna hex yang digunakan saat tag_name membuat tag baru, misalnya
            #007AFE.
      description: Lampirkan tag aplikasi ke transaksi yang cocok.
    TransactionRuleActionAddNote:
      type: object
      required:
        - type
        - note
      properties:
        type:
          type: string
          enum:
            - add_note
        note:
          type: string
          description: >-
            Teks catatan yang dilampirkan ke transaksi (penulis: Rule Engine).
            Kunci alias: nilai.
      description: Lampirkan catatan analis otomatis ke transaksi yang cocok.
    TransactionRuleActionAddToList:
      type: object
      required:
        - type
        - list_id
      properties:
        type:
          type: string
          enum:
            - add_to_list
        list_id:
          type: string
          format: uuid
          description: Daftar untuk menambahkan vendor_data subjek.
      description: >-
        Tambahkan vendor_data subjek ke daftar blokir, daftar izin, atau daftar
        kustom.
    TransactionRuleActionOpenCase:
      type: object
      required:
        - type
      properties:
        type:
          type: string
          enum:
            - open_case
        blueprint:
          type: string
          format: uuid
          description: UUID blueprint kasus; default ke blueprint default aplikasi.
        grouping:
          type: string
          enum:
            - by_applicant
            - by_rule_and_applicant
          description: >-
            Menentukan apakah kecocokan berulang digabungkan ke dalam satu kasus
            per pemohon atau satu kasus per aturan+pemohon.
        attach_matched_transaction:
          type: boolean
          description: Lampirkan transaksi yang cocok ke kasus.
      description: >-
        Buka (atau tambahkan ke) kasus investigasi. Hanya tindakan open_case
        pertama pada aturan yang diterapkan.
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: x-api-key
      description: >-
        Kunci API aplikasi Anda, dari Developers -> API keys di Business
        Console. Kunci utama memiliki akses penuh. Kunci bernama dapat diberi
        cakupan: none, read, atau write per sumber daya, dibatasi pada beberapa
        alur kerja atau pada sesi yang disetujui, pada daftar alamat IP, dan
        pada tanggal kedaluwarsa. 401 berarti kuncinya salah, dicabut, atau
        kedaluwarsa; 403 berarti tidak ada kunci yang dikirimkan, kunci tidak
        memiliki akses ke sumber daya atau tindakan ini, atau permintaan datang
        dari alamat di luar daftar IP-nya; 404 pada rute sesi berarti sesi
        berada di luar alur kerja atau status kunci tersebut. Kunci tanpa akses
        media menerima URL gambar, video, dan PDF sebagai null, dan kunci tanpa
        izin tulis sesi menerima tautan sesi dan token sebagai null. Lihat
        https://docs.didit.me/console/api-keys.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.