{
  "components": {
    "schemas": {
      "PaginationMeta": {
        "properties": {
          "has_more": {
            "type": "boolean"
          },
          "next_cursor": {
            "type": "string"
          }
        },
        "required": [
          "has_more"
        ],
        "type": "object"
      }
    },
    "securitySchemes": {
      "bearerAuth": {
        "description": "API key authentication",
        "scheme": "bearer",
        "type": "http"
      }
    }
  },
  "info": {
    "description": "Self-hosted AML/CFT compliance platform for Japanese non-bank financial institutions",
    "title": "Merlon AML/CFT API",
    "version": "1.0.0"
  },
  "openapi": "3.0.3",
  "paths": {
    "/api/v1/admin/apikeys": {
      "get": {
        "responses": {
          "200": {
            "description": "Success"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not Found"
          },
          "429": {
            "description": "Too Many Requests"
          }
        },
        "summary": "List API Keys"
      },
      "post": {
        "responses": {
          "200": {
            "description": "Success"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not Found"
          },
          "429": {
            "description": "Too Many Requests"
          }
        },
        "summary": "Create API Key"
      }
    },
    "/api/v1/admin/apikeys/{id}": {
      "delete": {
        "responses": {
          "200": {
            "description": "Success"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not Found"
          },
          "429": {
            "description": "Too Many Requests"
          }
        },
        "summary": "Revoke API key"
      }
    },
    "/api/v1/alerts": {
      "get": {
        "parameters": [
          {
            "description": "Max items per page (default 50, max 200)",
            "in": "query",
            "name": "limit",
            "schema": {
              "default": 50,
              "maximum": 200,
              "type": "integer"
            }
          },
          {
            "description": "Opaque pagination cursor from a previous response's pagination.next_cursor",
            "in": "query",
            "name": "cursor",
            "schema": {
              "type": "string"
            }
          },
          {
            "deprecated": true,
            "description": "Deprecated: use cursor instead",
            "in": "query",
            "name": "offset",
            "schema": {
              "default": 0,
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "data": {
                      "items": {
                        "type": "object"
                      },
                      "type": "array"
                    },
                    "pagination": {
                      "$ref": "#/components/schemas/PaginationMeta"
                    }
                  },
                  "required": [
                    "data",
                    "pagination"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Success"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not Found"
          },
          "429": {
            "description": "Too Many Requests"
          }
        },
        "summary": "List alerts"
      }
    },
    "/api/v1/alerts/{id}": {
      "get": {
        "responses": {
          "200": {
            "description": "Success"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not Found"
          },
          "429": {
            "description": "Too Many Requests"
          }
        },
        "summary": "Get Alert"
      },
      "patch": {
        "responses": {
          "200": {
            "description": "Success"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not Found"
          },
          "429": {
            "description": "Too Many Requests"
          }
        },
        "summary": "Update Alert"
      }
    },
    "/api/v1/audit": {
      "get": {
        "responses": {
          "200": {
            "description": "Success"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not Found"
          },
          "429": {
            "description": "Too Many Requests"
          }
        },
        "summary": "List audit logs"
      }
    },
    "/api/v1/audit/export": {
      "get": {
        "responses": {
          "200": {
            "description": "Success"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not Found"
          },
          "429": {
            "description": "Too Many Requests"
          }
        },
        "summary": "Export audit logs (CSV/JSON)"
      }
    },
    "/api/v1/backtest": {
      "post": {
        "responses": {
          "200": {
            "description": "Success"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not Found"
          },
          "429": {
            "description": "Too Many Requests"
          }
        },
        "summary": "Run backtest"
      }
    },
    "/api/v1/batch/monitor": {
      "post": {
        "responses": {
          "200": {
            "description": "Success"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not Found"
          },
          "429": {
            "description": "Too Many Requests"
          }
        },
        "summary": "Batch monitor transactions"
      }
    },
    "/api/v1/batch/score": {
      "post": {
        "responses": {
          "200": {
            "description": "Success"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not Found"
          },
          "429": {
            "description": "Too Many Requests"
          }
        },
        "summary": "Batch score customers"
      }
    },
    "/api/v1/cases": {
      "get": {
        "parameters": [
          {
            "description": "Max items per page (default 50, max 200)",
            "in": "query",
            "name": "limit",
            "schema": {
              "default": 50,
              "maximum": 200,
              "type": "integer"
            }
          },
          {
            "description": "Opaque pagination cursor from a previous response's pagination.next_cursor",
            "in": "query",
            "name": "cursor",
            "schema": {
              "type": "string"
            }
          },
          {
            "deprecated": true,
            "description": "Deprecated: use cursor instead",
            "in": "query",
            "name": "offset",
            "schema": {
              "default": 0,
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "data": {
                      "items": {
                        "type": "object"
                      },
                      "type": "array"
                    },
                    "pagination": {
                      "$ref": "#/components/schemas/PaginationMeta"
                    }
                  },
                  "required": [
                    "data",
                    "pagination"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Success"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not Found"
          },
          "429": {
            "description": "Too Many Requests"
          }
        },
        "summary": "List Cases"
      },
      "post": {
        "responses": {
          "200": {
            "description": "Success"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not Found"
          },
          "429": {
            "description": "Too Many Requests"
          }
        },
        "summary": "Create Case"
      }
    },
    "/api/v1/cases/{id}": {
      "get": {
        "responses": {
          "200": {
            "description": "Success"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not Found"
          },
          "429": {
            "description": "Too Many Requests"
          }
        },
        "summary": "Get Case"
      },
      "patch": {
        "responses": {
          "200": {
            "description": "Success"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not Found"
          },
          "429": {
            "description": "Too Many Requests"
          }
        },
        "summary": "Update Case"
      }
    },
    "/api/v1/cases/{id}/notes": {
      "post": {
        "responses": {
          "200": {
            "description": "Success"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not Found"
          },
          "429": {
            "description": "Too Many Requests"
          }
        },
        "summary": "Add case note"
      }
    },
    "/api/v1/cases/{id}/related": {
      "get": {
        "responses": {
          "200": {
            "description": "Success"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not Found"
          },
          "429": {
            "description": "Too Many Requests"
          }
        },
        "summary": "List related cases"
      },
      "post": {
        "responses": {
          "200": {
            "description": "Success"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not Found"
          },
          "429": {
            "description": "Too Many Requests"
          }
        },
        "summary": "Add manual related case link"
      }
    },
    "/api/v1/customers": {
      "get": {
        "parameters": [
          {
            "description": "Max items per page (default 50, max 200)",
            "in": "query",
            "name": "limit",
            "schema": {
              "default": 50,
              "maximum": 200,
              "type": "integer"
            }
          },
          {
            "description": "Opaque pagination cursor from a previous response's pagination.next_cursor",
            "in": "query",
            "name": "cursor",
            "schema": {
              "type": "string"
            }
          },
          {
            "deprecated": true,
            "description": "Deprecated: use cursor instead",
            "in": "query",
            "name": "offset",
            "schema": {
              "default": 0,
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "data": {
                      "items": {
                        "type": "object"
                      },
                      "type": "array"
                    },
                    "pagination": {
                      "$ref": "#/components/schemas/PaginationMeta"
                    }
                  },
                  "required": [
                    "data",
                    "pagination"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Success"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not Found"
          },
          "429": {
            "description": "Too Many Requests"
          }
        },
        "summary": "List Customers"
      },
      "post": {
        "responses": {
          "200": {
            "description": "Success"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not Found"
          },
          "429": {
            "description": "Too Many Requests"
          }
        },
        "summary": "Create Customer"
      }
    },
    "/api/v1/customers/{id}": {
      "get": {
        "responses": {
          "200": {
            "description": "Success"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not Found"
          },
          "429": {
            "description": "Too Many Requests"
          }
        },
        "summary": "Get Customer"
      },
      "put": {
        "responses": {
          "200": {
            "description": "Success"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not Found"
          },
          "429": {
            "description": "Too Many Requests"
          }
        },
        "summary": "Update Customer"
      }
    },
    "/api/v1/customers/{id}/score": {
      "post": {
        "responses": {
          "200": {
            "description": "Success"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not Found"
          },
          "429": {
            "description": "Too Many Requests"
          }
        },
        "summary": "Score customer risk"
      }
    },
    "/api/v1/customers/{id}/scores": {
      "get": {
        "responses": {
          "200": {
            "description": "Success"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not Found"
          },
          "429": {
            "description": "Too Many Requests"
          }
        },
        "summary": "Get customer score history"
      }
    },
    "/api/v1/customers/{id}/screen": {
      "post": {
        "responses": {
          "200": {
            "description": "Success"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not Found"
          },
          "429": {
            "description": "Too Many Requests"
          }
        },
        "summary": "Screen customer against sanctions lists"
      }
    },
    "/api/v1/dashboard": {
      "get": {
        "responses": {
          "200": {
            "description": "Success"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not Found"
          },
          "429": {
            "description": "Too Many Requests"
          }
        },
        "summary": "Dashboard statistics"
      }
    },
    "/api/v1/reports/str": {
      "post": {
        "responses": {
          "200": {
            "description": "Success"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not Found"
          },
          "429": {
            "description": "Too Many Requests"
          }
        },
        "summary": "Create STR report"
      }
    },
    "/api/v1/reports/str/export": {
      "get": {
        "responses": {
          "200": {
            "description": "Success"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not Found"
          },
          "429": {
            "description": "Too Many Requests"
          }
        },
        "summary": "Export STR report"
      }
    },
    "/api/v1/transactions": {
      "get": {
        "parameters": [
          {
            "description": "Max items per page (default 50, max 200)",
            "in": "query",
            "name": "limit",
            "schema": {
              "default": 50,
              "maximum": 200,
              "type": "integer"
            }
          },
          {
            "description": "Opaque pagination cursor from a previous response's pagination.next_cursor",
            "in": "query",
            "name": "cursor",
            "schema": {
              "type": "string"
            }
          },
          {
            "deprecated": true,
            "description": "Deprecated: use cursor instead",
            "in": "query",
            "name": "offset",
            "schema": {
              "default": 0,
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "data": {
                      "items": {
                        "type": "object"
                      },
                      "type": "array"
                    },
                    "pagination": {
                      "$ref": "#/components/schemas/PaginationMeta"
                    }
                  },
                  "required": [
                    "data",
                    "pagination"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Success"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not Found"
          },
          "429": {
            "description": "Too Many Requests"
          }
        },
        "summary": "List Transactions"
      },
      "post": {
        "responses": {
          "200": {
            "description": "Success"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not Found"
          },
          "429": {
            "description": "Too Many Requests"
          }
        },
        "summary": "Create Transaction"
      }
    },
    "/api/v1/transactions/{id}": {
      "get": {
        "responses": {
          "200": {
            "description": "Success"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not Found"
          },
          "429": {
            "description": "Too Many Requests"
          }
        },
        "summary": "Get transaction"
      }
    },
    "/api/v1/webhooks": {
      "get": {
        "responses": {
          "200": {
            "description": "Success"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not Found"
          },
          "429": {
            "description": "Too Many Requests"
          }
        },
        "summary": "List Webhooks"
      },
      "post": {
        "responses": {
          "200": {
            "description": "Success"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not Found"
          },
          "429": {
            "description": "Too Many Requests"
          }
        },
        "summary": "Create Webhook"
      }
    },
    "/api/v1/webhooks/dlq": {
      "get": {
        "responses": {
          "200": {
            "description": "Success"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not Found"
          },
          "429": {
            "description": "Too Many Requests"
          }
        },
        "summary": "List undelivered DLQ entries"
      }
    },
    "/api/v1/webhooks/dlq/{id}/reprocess": {
      "post": {
        "responses": {
          "200": {
            "description": "Success"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not Found"
          },
          "429": {
            "description": "Too Many Requests"
          }
        },
        "summary": "Reprocess a DLQ entry"
      }
    },
    "/api/v1/webhooks/{id}": {
      "delete": {
        "responses": {
          "200": {
            "description": "Success"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not Found"
          },
          "429": {
            "description": "Too Many Requests"
          }
        },
        "summary": "Delete Webhook"
      },
      "get": {
        "responses": {
          "200": {
            "description": "Success"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not Found"
          },
          "429": {
            "description": "Too Many Requests"
          }
        },
        "summary": "Get Webhook"
      }
    },
    "/api/v1/webhooks/{id}/deliveries": {
      "get": {
        "responses": {
          "200": {
            "description": "Success"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not Found"
          },
          "429": {
            "description": "Too Many Requests"
          }
        },
        "summary": "List webhook deliveries"
      }
    },
    "/healthz": {
      "get": {
        "responses": {
          "200": {
            "description": "Success"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not Found"
          },
          "429": {
            "description": "Too Many Requests"
          }
        },
        "summary": "Health check"
      }
    }
  },
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "servers": [
    {
      "description": "API v1",
      "url": "/api/v1"
    }
  ]
}
