diff --git a/.gitignore b/.gitignore
index 413afe45..613469d1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,4 +3,10 @@
routing-config/venv
routing-config/output.sql
dump.rdb
-.vscode
\ No newline at end of file
+.vscode
+**/node_modules
+cypress/screenshots
+cypress/videos
+cypress/fixtures
+# Added by code-review-graph
+.code-review-graph/
diff --git a/.mintlify-dev.log b/.mintlify-dev.log
new file mode 100644
index 00000000..8f8cc9f1
--- /dev/null
+++ b/.mintlify-dev.log
@@ -0,0 +1,26 @@
+⠋ preparing local preview...
+[2K[1A[2K[G⠙ preparing local preview...
+[2K[1A[2K[Gwarning - Error validating OpenAPI file /mint.json: Error: Failed to validate OpenAPI schema:Unknown path: Can’t find supported Swagger/OpenAPI version in specification, version must be a string.
+⠙ preparing local preview...
+[2K[1A[2K[G⠹ preparing local preview...
+[2K[1A[2K[G⠸ preparing local preview...
+[2K[1A[2K[G⠼ preparing local preview...
+[2K[1A[2K[Gupdate available - run `mint update` to get the latest version
+
+✓ preview ready
+
+ local → http://localhost:3000
+ network → http://192.168.1.4:3000
+
+press ctrl+c to exit the preview
+
+[2K[1A[2K[1A[2K[1A[2K[1A[2K[1A[2K[1A[2K[1A[2K[1A[2K[1A[2K[G
+update available - run `mint update` to get the latest version
+
+✓ preview ready
+
+ local → http://localhost:3000
+ network → http://192.168.1.4:3000
+
+press ctrl+c to exit the preview
+
diff --git a/.typos.toml b/.typos.toml
index 7c107218..3f79ac71 100644
--- a/.typos.toml
+++ b/.typos.toml
@@ -1,2 +1,84 @@
[default]
check-filename = true
+
+# Ignore 2-3 letter all-caps identifiers (likely codes/abbreviations)
+# and 2-3 letter lowercase identifiers (likely variable names)
+extend-ignore-identifiers-re = [
+ "^[A-Z]{2,3}$",
+ "^[a-z]{2,3}$",
+]
+
+# Module/type aliases used throughout the codebase
+[default.extend-identifiers]
+HasTable = "HasTable"
+ETO = "ETO"
+ETCC = "ETCC"
+ETM = "ETM"
+ETD = "ETD"
+ETCa = "ETCa"
+ETTD = "ETTD"
+ETOd = "ETOd"
+ETMo = "ETMo"
+TE = "TE"
+ser = "ser"
+
+# ISO 3166-1 alpha-3 country codes
+CAF = "CAF"
+NAM = "NAM"
+SOM = "SOM"
+THA = "THA"
+FO = "FO"
+
+# ISO 4217 currency codes
+ZAR = "ZAR"
+
+# Common abbreviations in code (e.g., ect = extendedCardType)
+ect = "ect"
+
+# CamelCase identifiers (Mis = Mismatch, etc.)
+Mis = "Mis"
+
+# Time zones (IST = Indian Standard Time)
+IST = "IST"
+Ist = "Ist"
+ist = "ist"
+
+# Order Type abbreviation
+OT = "OT"
+
+# Value Added Services (banking term)
+VAS = "VAS"
+Vas = "Vas"
+
+# JWT library API term
+encrypter = "encrypter"
+
+[default.extend-words]
+# Project-specific terms that are valid
+incase = "incase"
+# Database column name (would require migration to fix)
+penality = "penality"
+# HashiCorp (company name)
+hashi = "hashi"
+# CamelCase function name (Mismatch)
+Mis = "Mis"
+# Time zones (Indian Standard Time)
+IST = "IST"
+Ist = "Ist"
+ist = "ist"
+# Order Type abbreviation
+OT = "OT"
+# Value Added Services (banking term)
+VAS = "VAS"
+Vas = "Vas"
+# JWT library API term
+encrypter = "encrypter"
+
+[files]
+extend-exclude = [
+ # Exclude non-source files
+ "*.groovy",
+ "**/Untitled*",
+ # Exclude build artifacts
+ "website/dist/**",
+]
diff --git a/AGENTS.md b/AGENTS.md
new file mode 100644
index 00000000..e48dd682
--- /dev/null
+++ b/AGENTS.md
@@ -0,0 +1,159 @@
+# Decision Engine Agent Guide
+
+## Purpose
+
+Use this file as the first-stop operating guide for work in `decision-engine`.
+
+- Use docs for orientation, then verify behavior against code, config, and CI before making claims.
+- Prefer the smallest relevant surface first: route -> service -> config -> storage -> deployment.
+- When docs and code disagree, trust code, config, and CI over prose.
+
+## Source of Truth
+
+Use this precedence order when answering questions or planning changes:
+
+1. Runtime code and entrypoints in `src/`
+2. Config files and deployment manifests in `config/`, `docker-compose.yaml`, and `helm-charts/`
+3. `justfile`, `Makefile`, `.github/workflows/`, and `scripts/ci-checks.sh`
+4. Setup and API docs in `docs/`
+5. `README.md` for high-level product context only
+
+Do not treat README claims or marketing language as definitive implementation truth.
+
+## Repo Map
+
+- `src/bin/open_router.rs`: process entrypoint; loads config, fetches secrets, starts app and metrics servers
+- `src/app.rs`: main HTTP server wiring, route registration, middleware, graceful shutdown, TLS handling
+- `src/routes/`: REST handlers and endpoint behavior
+- `src/config.rs`: config structs, config loading, env override behavior, validation hooks
+- `src/tenant.rs`: tenant-aware app state wiring
+- `src/decider/`: routing decision logic
+- `src/euclid/`: routing rules and evaluation engine
+- `src/feedback/`: score updates and routing feedback flows
+- `docs/local-setup.md`: canonical local and on-prem style startup guide
+- `docs/configuration.md`: config-oriented documentation and deployment pointers
+- `docs/api-reference1.md`: human-readable API examples
+- `docs/openapi.json`: machine-readable API contract
+- `docker-compose.yaml`: local topology, compose profiles, supporting services
+- `helm-charts/`: Kubernetes and on-prem deployment assets
+- `justfile`: canonical engineering commands
+- `Makefile`: convenience wrappers around common compose flows
+- `.github/workflows/`: CI expectations and release automation
+- `scripts/ci-checks.sh`: DB feature compile matrix enforced by CI
+- `website/`: dashboard/frontend assets
+- `cypress/`: frontend/end-to-end test area
+
+## Which Docs to Open First
+
+- Local startup or environment bring-up: `docs/local-setup.md` -> `docker-compose.yaml` -> `justfile`
+- Runtime/config questions: `docs/configuration.md` -> `config/*.toml` -> `src/config.rs`
+- API behavior: `docs/openapi.json` -> `docs/api-reference1.md` -> `src/routes/*`
+- Server startup and wiring: `src/bin/open_router.rs` -> `src/app.rs`
+- Deployment or on-prem: `helm-charts/README.md` -> `helm-charts/templates/*` -> `docker-compose.yaml`
+- CI or verification expectations: `justfile` -> `.github/workflows/*` -> `scripts/ci-checks.sh`
+- Routing logic: `src/decider/` -> `src/euclid/` -> `src/routes/decide_gateway.rs` -> `src/routes/rule_configuration.rs` -> `src/routes/update_gateway_score.rs`
+- Tenant behavior: `src/tenant.rs` -> `src/custom_extractors.rs` -> `src/app.rs`
+
+## Canonical Startup Paths
+
+Use `docs/local-setup.md` as the canonical startup guide. Default to PostgreSQL unless the task is explicitly MySQL-specific.
+
+Preferred quick-start paths:
+
+- PostgreSQL with GHCR images:
+ `docker compose --profile postgres-ghcr up -d`
+- PostgreSQL with local build:
+ `docker compose --profile postgres-local up -d --build`
+- Convenience wrappers:
+ `make init-pg-ghcr`
+ `make init-pg-local`
+
+Source-run commands:
+
+- PostgreSQL build:
+ `cargo build --release --no-default-features --features middleware,kms-aws,postgres`
+- PostgreSQL run:
+ `RUSTFLAGS="-Awarnings" cargo run --no-default-features --features postgres`
+- MySQL build:
+ `cargo build --release --features release`
+- MySQL run:
+ `RUSTFLAGS="-Awarnings" cargo run --features release`
+- PostgreSQL migration:
+ `just migrate-pg`
+
+Verification:
+
+- Health:
+ `curl http://localhost:8080/health`
+
+Choose the startup path based on task intent:
+
+- local debugging: compose or source run
+- deployment review: Helm and compose manifests
+- API behavior inspection: route code plus health/startup verification
+
+## Coding Expectations
+
+- Rust edition is 2021; MSRV in `Cargo.toml` is `1.85.0`
+- `unsafe` is forbidden
+- Treat clippy warnings around `unwrap`, `expect`, `panic`, `todo`, and `unimplemented` as meaningful design constraints
+- Verify both DB tracks when changing shared core logic; do not assume only one backend is affected
+- The default feature path is MySQL; PostgreSQL uses `--no-default-features --features postgres`
+- Touch the smallest relevant surface first instead of broad refactors
+- When changing externally visible behavior, update the relevant docs in `docs/`
+- Confirm implementation facts in `src/`, config, and deployment manifests instead of relying on README wording
+
+## Verification Expectations
+
+Before claiming a change is done, choose the smallest sufficient set of checks and state what was run.
+
+Recommended command ladder:
+
+- format check:
+ `cargo +nightly fmt --all --check`
+- lint:
+ `just clippy`
+- broad compile coverage:
+ `just check`
+- unit tests:
+ `cargo test`
+- PostgreSQL migration path when relevant:
+ `just migrate-pg`
+- startup/config smoke check when relevant:
+ `curl http://localhost:8080/health`
+- CI-sensitive Rust changes:
+ inspect `scripts/ci-checks.sh`
+
+Rules:
+
+- If a change touches shared Rust logic in `src/`, validate both MySQL and PostgreSQL compile paths because CI checks both.
+- If a task is docs-only, config-reading only, or frontend-only, say which checks were intentionally skipped.
+- If deployment behavior is in question, inspect manifests and templates directly instead of assuming docs are current.
+
+## Task Playbooks
+
+- Bug fix:
+ reproduce -> identify route/config/storage surface -> patch -> run targeted checks -> run broader compile checks if core logic changed
+- API change:
+ inspect route handler -> inspect request/response types -> inspect `docs/openapi.json` and `docs/api-reference1.md` -> update docs if behavior changed
+- Deployment issue:
+ inspect `docs/local-setup.md` -> inspect `docker-compose.yaml` or `helm-charts/templates/*` -> inspect config loading in `src/config.rs`
+- Prod or on-prem readiness question:
+ verify against Helm, compose, config defaults, secrets handling, probes, CI, and runtime code
+- Routing logic question:
+ inspect `src/routes/decide_gateway.rs`, `src/decider/`, `src/euclid/`, and feedback/update-score flows
+- Tenant question:
+ inspect `src/tenant.rs`, `src/custom_extractors.rs`, route handlers, and config-backed tenant wiring
+
+## Optional Local Tooling
+
+- When available, prefer `code-review-graph` for code navigation, dependency tracing, and change-impact analysis.
+- If unavailable, fall back to normal repository inspection.
+- Do not make task success depend on optional local AI tooling.
+
+## Important Caveats
+
+- Default config files are development-oriented and should not be treated as production-ready defaults.
+- Deployment docs are useful, but readiness claims must be verified against chart templates, compose manifests, runtime config, and code.
+- Use actual route wiring and config structs as the authority for behavior.
+- Some docs overlap or duplicate each other; prefer `docs/local-setup.md`, `docs/configuration.md`, `docs/openapi.json`, and the route code as canonical references.
diff --git a/Cargo.lock b/Cargo.lock
index d7f0734f..3f660f18 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -999,6 +999,12 @@ dependencies = [
"half",
]
+[[package]]
+name = "cityhash-rs"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93a719913643003b84bd13022b4b7e703c09342cd03b679c4641c7d2e50dc34d"
+
[[package]]
name = "clang-sys"
version = "1.8.1"
@@ -1035,6 +1041,45 @@ version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
+[[package]]
+name = "clickhouse"
+version = "0.12.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3093f817c4f81c8bd174ed8dd30eac785821a8a7eef27a7dcb7f8cd0d0f6548"
+dependencies = [
+ "bstr",
+ "bytes",
+ "cityhash-rs",
+ "clickhouse-derive",
+ "futures",
+ "futures-channel",
+ "http-body-util",
+ "hyper 1.6.0",
+ "hyper-util",
+ "lz4_flex",
+ "replace_with",
+ "sealed",
+ "serde",
+ "static_assertions",
+ "thiserror 1.0.69",
+ "time",
+ "tokio",
+ "url",
+ "uuid",
+]
+
+[[package]]
+name = "clickhouse-derive"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d70f3e2893f7d3e017eeacdc9a708fbc29a10488e3ebca21f9df6a5d2b616dbb"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "serde_derive_internals",
+ "syn 2.0.100",
+]
+
[[package]]
name = "cmake"
version = "0.1.54"
@@ -1256,6 +1301,21 @@ dependencies = [
"libc",
]
+[[package]]
+name = "crc"
+version = "3.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675"
+dependencies = [
+ "crc-catalog",
+]
+
+[[package]]
+name = "crc-catalog"
+version = "2.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5"
+
[[package]]
name = "crc16"
version = "0.4.0"
@@ -1646,7 +1706,7 @@ checksum = "139ae9aca7527f85f26dd76483eb38533fd84bd571065da1739656ef71c5ff5b"
dependencies = [
"darling 0.20.10",
"either",
- "heck",
+ "heck 0.5.0",
"proc-macro2",
"quote",
"syn 2.0.100",
@@ -2089,6 +2149,12 @@ dependencies = [
"num-traits",
]
+[[package]]
+name = "heck"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
+
[[package]]
name = "heck"
version = "0.5.0"
@@ -2665,6 +2731,25 @@ dependencies = [
"serde",
]
+[[package]]
+name = "kafka"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2054ba4edcb4dcda4209e138c7e88caf26d4a325b3db76fbdb6ca5eecc23e426"
+dependencies = [
+ "byteorder",
+ "crc",
+ "flate2",
+ "fnv",
+ "openssl",
+ "openssl-sys",
+ "ref_slice",
+ "snap",
+ "thiserror 1.0.69",
+ "tracing",
+ "twox-hash",
+]
+
[[package]]
name = "keyed_priority_queue"
version = "0.4.2"
@@ -2787,6 +2872,12 @@ dependencies = [
"linked-hash-map",
]
+[[package]]
+name = "lz4_flex"
+version = "0.11.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08ab2867e3eeeca90e844d1940eab391c9dc5228783db2ed999acbc0a9ed375a"
+
[[package]]
name = "masking"
version = "0.1.0"
@@ -2955,7 +3046,7 @@ dependencies = [
"subprocess",
"thiserror 1.0.69",
"uuid",
- "zstd",
+ "zstd 0.13.3",
]
[[package]]
@@ -3126,6 +3217,7 @@ dependencies = [
"bytes",
"cargo_metadata",
"chrono",
+ "clickhouse",
"config",
"console-subscriber",
"cpu-time",
@@ -3138,10 +3230,12 @@ dependencies = [
"futures",
"gethostname",
"hex",
+ "http-body-util",
"hyper 1.6.0",
"jemalloc-ctl",
"jemallocator",
"josekit",
+ "kafka",
"lazy_static",
"masking 0.1.0 (git+https://github.com/juspay/hyperswitch?tag=v1.111.1)",
"mysqlclient-sys",
@@ -3151,6 +3245,7 @@ dependencies = [
"rand 0.8.5",
"rand_distr",
"redis_interface",
+ "regex",
"reqwest 0.12.15",
"ring",
"rustc-hash 2.1.1",
@@ -3171,6 +3266,7 @@ dependencies = [
"tracing-subscriber",
"uuid",
"vaultrs",
+ "zstd 0.12.4",
]
[[package]]
@@ -3862,6 +3958,12 @@ dependencies = [
"bitflags 2.9.0",
]
+[[package]]
+name = "ref_slice"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4ed1d73fb92eba9b841ba2aef69533a060ccc0d3ec71c90aeda5996d4afb7a9"
+
[[package]]
name = "regex"
version = "1.11.1"
@@ -3933,6 +4035,12 @@ dependencies = [
"bytecheck",
]
+[[package]]
+name = "replace_with"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "51743d3e274e2b18df81c4dc6caf8a5b8e15dbe799e0dca05c7617380094e884"
+
[[package]]
name = "reqwest"
version = "0.11.27"
@@ -4409,6 +4517,18 @@ version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
+[[package]]
+name = "sealed"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4a8caec23b7800fb97971a1c6ae365b6239aaeddfb934d6265f8505e795699d"
+dependencies = [
+ "heck 0.4.1",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.100",
+]
+
[[package]]
name = "security-framework"
version = "2.11.1"
@@ -4474,6 +4594,17 @@ dependencies = [
"syn 2.0.100",
]
+[[package]]
+name = "serde_derive_internals"
+version = "0.29.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.100",
+]
+
[[package]]
name = "serde_json"
version = "1.0.140"
@@ -4613,6 +4744,12 @@ version = "1.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd"
+[[package]]
+name = "snap"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b6b67fb9a61334225b5b790716f609cd58395f895b3fe8b328786812a40bc3b"
+
[[package]]
name = "socket2"
version = "0.5.8"
@@ -4673,7 +4810,7 @@ version = "0.26.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be"
dependencies = [
- "heck",
+ "heck 0.5.0",
"proc-macro2",
"quote",
"rustversion",
@@ -6129,13 +6266,32 @@ dependencies = [
"syn 2.0.100",
]
+[[package]]
+name = "zstd"
+version = "0.12.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a27595e173641171fc74a1232b7b1c7a7cb6e18222c11e9dfb9888fa424c53c"
+dependencies = [
+ "zstd-safe 6.0.6",
+]
+
[[package]]
name = "zstd"
version = "0.13.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a"
dependencies = [
- "zstd-safe",
+ "zstd-safe 7.2.4",
+]
+
+[[package]]
+name = "zstd-safe"
+version = "6.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee98ffd0b48ee95e6c5168188e44a54550b1564d9d530ee21d5f0eaed1069581"
+dependencies = [
+ "libc",
+ "zstd-sys",
]
[[package]]
diff --git a/Cargo.toml b/Cargo.toml
index 77bf6526..fd0cb962 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -9,7 +9,7 @@ rust-version = "1.85.0"
[features]
default = ["middleware","mysql"]
-release = ["middleware", "kms-aws","mysql"]
+release = ["middleware", "kms-aws","mysql", "redis_compression"]
kms-aws = ["dep:aws-config", "dep:aws-sdk-kms"]
kms-hashicorp-vault = ["dep:vaultrs"]
limit = []
@@ -19,6 +19,7 @@ external_key_manager = []
external_key_manager_mtls = ["external_key_manager", "reqwest/rustls-tls"]
postgres = []
mysql = []
+redis_compression = ["dep:zstd"]
[dependencies]
aws-config = { version = "1.5.5", optional = true }
@@ -36,6 +37,7 @@ jemallocator = "0.5"
jemalloc-ctl = "0.5"
prometheus = "0.13"
lazy_static = "1.4"
+zstd = { version = "0.12", optional = true }
async-bb8-diesel = { git = "https://github.com/jarnura/async-bb8-diesel", rev = "53b4ab901aab7635c8215fd1c2d542c8db443094" }
redis_interface = { git = "https://github.com/juspay/hyperswitch.git", tag = "2024.09.30.0" }
@@ -73,6 +75,9 @@ hex = "0.4.3"
time = { version = "0.3.36", features = ["serde"] }
uuid = { version = "1.10.0", features = ["v4", "v7", "fast-rng"] }
reqwest = { version = "0.12.7", features = ["json", "__rustls"] }
+http-body-util = "0.1.3"
+kafka = "0.10.0"
+clickhouse = { version = "0.12.2", features = ["time", "uuid"] }
nanoid = "0.4.0"
mysqlclient-sys = { version = "0.4.2", features = ["buildtime_bindgen"] }
@@ -93,6 +98,7 @@ rand = "0.8.5"
tower-http = { version = "0.6.2", features = ["trace"] }
bytes = "1.10.1"
strum = { version = "0.26.2", features = ["derive"] }
+regex = "1.10"
# -------------------------------------
[dev-dependencies]
diff --git a/Dockerfile.docs b/Dockerfile.docs
new file mode 100644
index 00000000..afaa64be
--- /dev/null
+++ b/Dockerfile.docs
@@ -0,0 +1,12 @@
+FROM node:20-alpine
+
+ARG MINTLIFY_VERSION=4.2.504
+RUN npm install -g "mintlify@${MINTLIFY_VERSION}"
+
+WORKDIR /docs
+
+COPY docs/ .
+
+EXPOSE 3000
+
+CMD ["mintlify", "dev", "--port", "3000", "--no-browser"]
diff --git a/Makefile b/Makefile
index 43d893c9..57dddd0e 100644
--- a/Makefile
+++ b/Makefile
@@ -1,35 +1,58 @@
COMMIT_HASH := $(shell git rev-parse --short HEAD)
TAG := ghcr.io/juspay/decision-engine:sha_$(COMMIT_HASH)
+DECISION_ENGINE_TAG ?= v1.4
+GROOVY_RUNNER_TAG ?= v1.4
+
docker-build:
- docker build --platform=linux/amd64 -t $(TAG) .
+ docker build --platform=linux/amd64 -t $(TAG) .
docker-run:
- docker run --platform=linux/amd64 -v `pwd`/config/docker-configuration.toml:/local/config/development.toml -p 8080:8080 -d $(TAG)
+ docker run --platform=linux/amd64 -v `pwd`/config/docker-configuration.toml:/local/config/development.toml -p 8080:8080 -d $(TAG)
docker-it-run:
- docker run --platform=linux/amd64 -v `pwd`/config/docker-configuration.toml:/local/config/development.toml -it $(TAG) /bin/bash
+ docker run --platform=linux/amd64 -v `pwd`/config/docker-configuration.toml:/local/config/development.toml -it $(TAG) /bin/bash
+
+init-mysql-ghcr:
+ DECISION_ENGINE_TAG=$(DECISION_ENGINE_TAG) GROOVY_RUNNER_TAG=$(GROOVY_RUNNER_TAG) docker compose --profile mysql-ghcr up -d
+
+init-pg-ghcr:
+ DECISION_ENGINE_TAG=$(DECISION_ENGINE_TAG) GROOVY_RUNNER_TAG=$(GROOVY_RUNNER_TAG) docker compose --profile postgres-ghcr up -d
+
+init-mysql-local:
+ docker compose --profile mysql-local up -d --build
+
+init-pg-local:
+ docker compose --profile postgres-local up -d --build
+
+run-mysql-ghcr:
+ DECISION_ENGINE_TAG=$(DECISION_ENGINE_TAG) GROOVY_RUNNER_TAG=$(GROOVY_RUNNER_TAG) docker compose --profile mysql-ghcr up -d open-router-mysql-ghcr
-init:
- docker-compose run --rm db-migrator && docker-compose up open-router
+run-pg-ghcr:
+ DECISION_ENGINE_TAG=$(DECISION_ENGINE_TAG) GROOVY_RUNNER_TAG=$(GROOVY_RUNNER_TAG) docker compose --profile postgres-ghcr up -d open-router-pg-ghcr
-init-pg:
- docker-compose run --rm db-migrator-postgres && docker-compose up open-router-pg
-
-run:
- docker-compose up open-router
+run-mysql-local:
+ docker compose --profile mysql-local up -d --build open-router-mysql-local
-init-local:
- docker-compose run --rm db-migrator && docker-compose up --build open-router-local
+run-pg-local:
+ docker compose --profile postgres-local up -d --build open-router-pg-local
-init-local-pg:
- docker-compose run --rm db-migrator-postgres && docker-compose up --build open-router-local-pg
+init-pg-monitor:
+ DECISION_ENGINE_TAG=$(DECISION_ENGINE_TAG) GROOVY_RUNNER_TAG=$(GROOVY_RUNNER_TAG) docker compose --profile postgres-ghcr --profile monitoring up -d
-run-local:
- docker-compose up open-router-local
+init-local-pg-monitor:
+ docker compose --profile postgres-local --profile monitoring up -d --build
update-config:
- docker-compose run --rm routing-config
+ docker compose --profile mysql-ghcr run --rm routing-config
stop:
- docker-compose down
\ No newline at end of file
+ docker compose down
+
+# Backward-compatible aliases
+init: init-mysql-ghcr
+init-pg: init-pg-ghcr
+run: run-mysql-ghcr
+init-local: init-mysql-local
+init-local-pg: init-pg-local
+run-local: run-mysql-local
diff --git a/README.md b/README.md
index 8df9c155..cae69670 100644
--- a/README.md
+++ b/README.md
@@ -1,67 +1,123 @@
-# Decision Engine
-## Overview
+# Decision Engine
-The Decision Engine system helps in choosing the most optimal payment gateway in real-time for every transaction based on pre-defined rules, success rate, latency and other business requirements. It is a fully modular service that can work with any orchestrator and any PCI-compliant vaults.
+
-## Vision
+
+
+
+
-Build a reliable, open source payments software for the world \- which is interoperable, collaborative and community-driven.
+
+
-## Features
+
+
+
+
+
-The Decision Engine comes with the following features out-of-the box for your payment routing needs.
-✅ Eligibility Check – Ensures only eligible gateways are used, reducing payment failures and improving transaction success.
+
+
-📌 Rule-Based Ordering – Routes transactions based on predefined merchant rules, ensuring predictable and obligation-driven payment processing.
+Merchant-facing routing control plane for deciding gateways, updating score models, exposing connector analytics, and tracing payment-level audit flows from one product.
-🔄 Dynamic Gateway Ordering – Uses real-time success rates and ML-driven optimization to route transactions to the best-performing gateway.
+
+
-⚠️ Downtime Detection – Monitors gateway health, dynamically reordering or pausing routing to prevent transaction failures during downtime.
+
Quick Start
+·
+
Dashboard
+·
+
Analytics
+·
+
Payment Audit
+·
+
API Reference
-To learn more, refer to this blog: [https://juspay.io/blog/juspay-orchestrator-and-merchant-controlled-routing-engine](https://juspay.io/blog/juspay-orchestrator-and-merchant-controlled-routing-engine)
+
+
-## Architecture
+
-
+## Table of Contents
-### How it can fit into your existing architecture
+- [What You Can Do](#what-you-can-do)
+- [Quickstart](#quickstart)
+- [Dashboard Surfaces](#dashboard-surfaces)
+- [Docs Map](#docs-map)
+- [Development](#development)
+- [License](#license)
-
+## What You Can Do
-## Try it out
-
- Check the [SETUP.md](/docs/setup-guide-mysql.md) for detailed steps to try out the application.
+- **Route with live score context**
+ Use `POST /decide-gateway` and `POST /update-gateway-score` to choose connectors and continuously feed transaction outcomes back into the scoring model.
+- **Mix static and dynamic routing**
+ Combine `priority`, `single`, `volume_split`, and `advanced` rule-based routing under `/routing/*`, while keeping `/rule/*` for runtime routing configuration.
+- **Operate from a real dashboard**
+ The React dashboard ships with routing views, analytics, connector score trends, and payment audit timelines instead of forcing operators into Redis, SQL, or raw logs.
+- **Explain why a payment routed where it did**
+ Payment Audit links decision responses, rule hits, score updates, and connector score context so teams can answer why a connector was selected at that point in time.
+## Quickstart
+```bash
+git clone https://github.com/juspay/decision-engine.git
+cd decision-engine
+docker compose --profile postgres-ghcr up -d
+curl http://localhost:8080/health
+```
-## API Reference :
+Expected response:
-Check the [API_REFERENCE.md](/docs/api-reference1.md) for more details
+```json
+{"message":"Health is good"}
+```
+For the full local setup matrix, source runs, dashboard profiles, and Helm flows, use [docs/local-setup.md](docs/local-setup.md).
-## Support, Feature Requests, Bugs
+## Dashboard Surfaces
-For any support, join the conversation in [Slack](https://join.slack.com/t/hyperswitch-io/shared_invite/zt-2jqxmpsbm-WXUENx022HjNEy~Ark7Orw)
-
-For new product features, enhancements, roadmap discussions, or to share queries and ideas, visit our [GitHub Discussions](https://github.com/juspay/decision-engine/discussions)
+| Surface | Why you open it | Primary doc |
+| --- | --- | --- |
+| `Analytics` | live connector metrics, score snapshots, rule hits, and routing summaries | [docs/analytics.mdx](docs/analytics.mdx) |
+| `Payment Audit` | payment-by-payment request, response, score context, and timeline inspection | [docs/payment-audit.mdx](docs/payment-audit.mdx) |
+| `Routing Hub` | configure rule-based routing, SR-based routing, volume splits, and debit routing | [docs/dashboard.mdx](docs/dashboard.mdx) |
+| `API Reference` | OpenAPI-backed endpoint pages and curl examples | [docs/api-reference.md](docs/api-reference.md) |
-For reporting a bug, please read the issue guidelines and search for [existing and closed issues]. If your problem or idea is not addressed yet, please [open a new issue].
+## Docs Map
-[existing and closed issues]: https://github.com/juspay/decision-engine/issues
-[open a new issue]: https://github.com/juspay/decision-engine/issues/new/choose
-
+- [Introduction](docs/introduction.mdx)
+- [Local Setup](docs/local-setup.md)
+- [Configuration](docs/configuration.md)
+- [Dashboard](docs/dashboard.mdx)
+- [Analytics](docs/analytics.mdx)
+- [Payment Audit](docs/payment-audit.mdx)
+- [API Reference](docs/api-reference.md)
+- [API Examples](docs/api-reference1.md)
+- [OpenAPI Source](docs/openapi.json)
+- [PostgreSQL Setup](docs/setup-guide-postgres.md)
+- [MySQL Setup](docs/setup-guide-mysql.md)
-## Contributing
+## Development
-We welcome contributions from everyone\! Here's how you can help:
+```bash
+# lint
+just clippy
-See [CONTRIBUTING.md](CONTRIBUTING.md) for detailed guidelines.
+# compile matrix
+just check
-## Versioning
+# tests
+cargo test
-Check the [CHANGELOG.md](CHANGELOG.md) file for details.
+# postgres migrations
+just migrate-pg
+```
-## Copyright and License
+The repo also ships a one-command local startup path in [oneclick.sh](oneclick.sh), which brings up the API, dashboard, and docs preview together.
-This product is licensed under the [AGPL V3](LICENSE) License.
+## License
+
+Licensed under [GNU AGPL v3.0](LICENSE).
diff --git a/analytics/README.md b/analytics/README.md
new file mode 100644
index 00000000..966e12c9
--- /dev/null
+++ b/analytics/README.md
@@ -0,0 +1,303 @@
+# Decision Engine Analytics
+
+This directory contains the analytics infrastructure for the Decision Engine project, implementing real-time event tracking and analytics using ClickHouse and Kafka.
+
+## Architecture
+
+The analytics system follows the Hyperswitch analytics pattern with the following components:
+
+```
+┌─────────────────────┐
+│ Decision Engine │
+│ (Main Service) │
+└──────────┬──────────┘
+ │ Events
+ ▼
+┌─────────────────────┐
+│ Kafka │
+│ (Event Stream) │
+└──────────┬──────────┘
+ │ Real-time
+ ▼
+┌─────────────────────┐
+│ ClickHouse │
+│ ┌───────────────┐ │
+│ │ Kafka Engine │ │
+│ │ Tables │ │
+│ └───────┬───────┘ │
+│ │ │
+│ ▼ │
+│ ┌───────────────┐ │
+│ │ Materialized │ │
+│ │ Views │ │
+│ └───────┬───────┘ │
+│ │ │
+│ ▼ │
+│ ┌───────────────┐ │
+│ │ Storage │ │
+│ │ Tables │ │
+│ └───────────────┘ │
+└─────────────────────┘
+```
+
+## Components
+
+### 1. Event Tracking
+- **Endpoints Tracked**: `/routing/evaluate` and `/decide-gateway`
+- **Event Data**: Request/response payloads, processing time, gateway selection, errors
+- **Middleware**: Automatic event capture for tracked endpoints
+
+### 2. Data Storage
+- **Kafka Topics**: `decision-engine-routing-events`
+- **ClickHouse Tables**:
+ - `routing_events_queue` (Kafka engine for ingestion)
+ - `routing_events` (CollapsingMergeTree for storage)
+ - `routing_events_hourly` (Hourly aggregations)
+ - `routing_events_daily` (Daily aggregations)
+
+### 3. Real-time Processing
+- **Kafka Producer**: Batched event publishing
+- **Materialized Views**: Real-time data transformation
+- **Aggregations**: Automatic hourly and daily rollups
+
+## Quick Start
+
+### 1. Start Analytics Infrastructure
+
+```bash
+# Start with analytics profile
+docker-compose --profile analytics up -d
+
+# This will start:
+# - Zookeeper
+# - Kafka
+# - ClickHouse
+# - Analytics migrator (runs schema setup)
+```
+
+### 2. Enable Analytics in Configuration
+
+Update your `config/development.toml`:
+
+```toml
+[analytics]
+enabled = true
+
+[analytics.kafka]
+brokers = ["kafka:29092"]
+topic_prefix = "decision-engine"
+batch_size = 100
+batch_timeout_ms = 1000
+
+[analytics.clickhouse]
+host = "http://clickhouse:8123"
+username = "analytics_user"
+password = "analytics_pass"
+database = "decision_engine_analytics"
+```
+
+### 3. Start Decision Engine
+
+```bash
+# Start the main application
+docker-compose up open-router-local
+```
+
+## Database Schema
+
+### Routing Events Table
+
+```sql
+CREATE TABLE routing_events (
+ event_id String,
+ merchant_id LowCardinality(String),
+ request_id String,
+ endpoint LowCardinality(String),
+ method LowCardinality(String),
+ request_payload String,
+ response_payload String,
+ status_code UInt16,
+ processing_time_ms UInt32,
+ gateway_selected LowCardinality(Nullable(String)),
+ routing_algorithm_id Nullable(String),
+ error_message Nullable(String),
+ user_agent Nullable(String),
+ ip_address Nullable(String),
+ created_at DateTime DEFAULT now(),
+ inserted_at DateTime DEFAULT now(),
+ sign_flag Int8
+) ENGINE = CollapsingMergeTree(sign_flag)
+PARTITION BY toStartOfDay(created_at)
+ORDER BY (created_at, merchant_id, request_id, event_id);
+```
+
+### Aggregated Views
+
+- **Hourly Aggregations**: Request counts, success/failure rates, performance metrics
+- **Daily Aggregations**: Daily summaries with unique request tracking
+
+## Querying Analytics Data
+
+### Basic Queries
+
+```sql
+-- Total requests by endpoint
+SELECT
+ endpoint,
+ sum(sign_flag) as total_requests
+FROM routing_events
+WHERE created_at >= now() - INTERVAL 1 DAY
+GROUP BY endpoint;
+
+-- Success rate by gateway
+SELECT
+ gateway_selected,
+ sum(if(status_code < 400, sign_flag, 0)) as successful_requests,
+ sum(sign_flag) as total_requests,
+ (successful_requests / total_requests) * 100 as success_rate
+FROM routing_events
+WHERE created_at >= now() - INTERVAL 1 DAY
+ AND gateway_selected IS NOT NULL
+GROUP BY gateway_selected;
+
+-- Performance metrics
+SELECT
+ endpoint,
+ avg(processing_time_ms) as avg_processing_time,
+ quantile(0.95)(processing_time_ms) as p95_processing_time,
+ quantile(0.99)(processing_time_ms) as p99_processing_time
+FROM routing_events
+WHERE created_at >= now() - INTERVAL 1 DAY
+GROUP BY endpoint;
+```
+
+### Using Aggregated Tables
+
+```sql
+-- Hourly trends
+SELECT
+ hour,
+ endpoint,
+ total_requests,
+ successful_requests,
+ (successful_requests / total_requests) * 100 as success_rate,
+ avg_processing_time_ms
+FROM routing_events_hourly
+WHERE hour >= now() - INTERVAL 24 HOUR
+ORDER BY hour DESC;
+```
+
+## Configuration Options
+
+### Analytics Configuration
+
+```toml
+[analytics]
+enabled = true # Enable/disable analytics
+
+[analytics.kafka]
+brokers = ["kafka:29092"] # Kafka broker addresses
+topic_prefix = "decision-engine" # Topic prefix for events
+batch_size = 100 # Events per batch
+batch_timeout_ms = 1000 # Batch timeout in milliseconds
+
+[analytics.clickhouse]
+host = "http://clickhouse:8123" # ClickHouse HTTP endpoint
+username = "analytics_user" # ClickHouse username
+password = "analytics_pass" # ClickHouse password
+database = "decision_engine_analytics" # Database name
+```
+
+## Monitoring and Maintenance
+
+### Health Checks
+
+The analytics client provides health check functionality:
+
+```rust
+// Check analytics connectivity
+analytics_client.health_check().await?;
+```
+
+### Data Retention
+
+- **Raw Events**: 18 months (configurable via TTL)
+- **Hourly Aggregations**: 12 months
+- **Daily Aggregations**: 24 months
+
+### Performance Considerations
+
+1. **Batch Processing**: Events are batched for efficient Kafka publishing
+2. **Async Processing**: Analytics don't block request processing
+3. **Fallback Handling**: Graceful degradation when analytics are unavailable
+4. **Partitioning**: Data partitioned by day for efficient queries
+
+## Troubleshooting
+
+### Common Issues
+
+1. **Kafka Connection Failed**
+ - Check Kafka broker connectivity
+ - Verify topic creation
+ - Check network configuration
+
+2. **ClickHouse Connection Failed**
+ - Verify ClickHouse is running
+ - Check credentials and database existence
+ - Verify network connectivity
+
+3. **Missing Events**
+ - Check analytics middleware is enabled
+ - Verify endpoint tracking configuration
+ - Check Kafka topic consumption
+
+### Debugging
+
+Enable debug logging for analytics:
+
+```toml
+[log.console]
+level = "DEBUG"
+```
+
+Check analytics client status:
+
+```bash
+# Check if analytics is enabled
+curl http://localhost:8080/health
+
+# Check Kafka topics
+docker exec -it open-router-kafka kafka-topics --bootstrap-server localhost:9092 --list
+
+# Check ClickHouse tables
+docker exec -it open-router-clickhouse clickhouse-client --query "SHOW TABLES FROM decision_engine_analytics"
+```
+
+## Development
+
+### Adding New Event Types
+
+1. Extend `RoutingEventData` struct in `src/analytics/types.rs`
+2. Update ClickHouse schema in `analytics/migrations/`
+3. Modify event extraction logic in middleware
+4. Update aggregation queries if needed
+
+### Testing
+
+```bash
+# Run analytics tests
+cargo test analytics
+
+# Test with sample events
+curl -X POST http://localhost:8080/routing/evaluate \
+ -H "Content-Type: application/json" \
+ -H "x-merchant-id: test-merchant" \
+ -d '{"test": "data"}'
+```
+
+## Security Considerations
+
+1. **Data Privacy**: Ensure sensitive data is properly masked
+2. **Access Control**: Restrict ClickHouse access to authorized users
+3. **Network Security**: Use proper network isolation
+4. **Data Retention**: Implement appropriate data retention policies
diff --git a/analytics/migrations/001_routing_events.sql b/analytics/migrations/001_routing_events.sql
new file mode 100644
index 00000000..27faa863
--- /dev/null
+++ b/analytics/migrations/001_routing_events.sql
@@ -0,0 +1,108 @@
+-- Merged SQL Migration File for Decision Engine Analytics
+-- This file combines all migration steps into a single comprehensive migration
+-- Created by merging: 001_routing_events.sql, 002_fix_datetime_parsing.sql, 002_fix_datetime_parsing_alternative.sql, 003_unix_timestamp_fix.sql
+
+-- =============================================================================
+-- STEP 1: Database Setup
+-- =============================================================================
+
+-- Create database if not exists
+CREATE DATABASE IF NOT EXISTS decision_engine_analytics;
+
+-- Use the analytics database
+USE decision_engine_analytics;
+
+-- =============================================================================
+-- STEP 2: Create Storage Tables (Final Schema)
+-- =============================================================================
+
+-- Create storage table with CollapsingMergeTree for routing events
+CREATE TABLE IF NOT EXISTS routing_events (
+ `event_id` String,
+ `merchant_id` LowCardinality(String),
+ `request_id` String,
+ `endpoint` LowCardinality(String),
+ `method` LowCardinality(String),
+ `request_payload` String,
+ `response_payload` String,
+ `status_code` UInt16,
+ `processing_time_ms` UInt32,
+ `gateway_selected` LowCardinality(Nullable(String)),
+ `routing_algorithm_id` Nullable(String),
+ `error_message` Nullable(String),
+ `user_agent` Nullable(String),
+ `ip_address` Nullable(String),
+ `created_at` DateTime DEFAULT now() CODEC(T64, LZ4),
+ `inserted_at` DateTime DEFAULT now() CODEC(T64, LZ4),
+ `sign_flag` Int8,
+ INDEX endpointIndex endpoint TYPE bloom_filter GRANULARITY 1,
+ INDEX gatewayIndex gateway_selected TYPE bloom_filter GRANULARITY 1,
+ INDEX statusIndex status_code TYPE bloom_filter GRANULARITY 1,
+ INDEX merchantIndex merchant_id TYPE bloom_filter GRANULARITY 1
+) ENGINE = CollapsingMergeTree(sign_flag)
+PARTITION BY toStartOfDay(created_at)
+ORDER BY (created_at, merchant_id, request_id, event_id)
+TTL created_at + toIntervalMonth(18)
+SETTINGS index_granularity = 8192;
+
+-- =============================================================================
+-- STEP 3: Create Kafka Integration (Final Version with Unix Timestamp Support)
+-- =============================================================================
+
+-- Drop existing views and tables if they exist (for clean migration)
+DROP VIEW IF EXISTS routing_events_mv;
+DROP TABLE IF EXISTS routing_events_queue;
+
+-- Create Kafka engine table with Unix timestamp handling (final version)
+CREATE TABLE IF NOT EXISTS routing_events_queue (
+ `event_id` String,
+ `merchant_id` String,
+ `request_id` String,
+ `endpoint` LowCardinality(String),
+ `method` LowCardinality(String),
+ `request_payload` String,
+ `response_payload` String,
+ `status_code` UInt16,
+ `processing_time_ms` UInt32,
+ `gateway_selected` LowCardinality(Nullable(String)),
+ `routing_algorithm_id` Nullable(String),
+ `error_message` Nullable(String),
+ `user_agent` Nullable(String),
+ `ip_address` Nullable(String),
+ `created_at` Int64, -- Unix timestamp (final fix)
+ `sign_flag` Int8
+) ENGINE = Kafka
+SETTINGS
+ kafka_broker_list = 'open-router-kafka:29092',
+ kafka_topic_list = 'decision-engine-routing-events',
+ kafka_group_name = 'decision-engine-analytics',
+ kafka_format = 'JSONEachRow',
+ kafka_handle_error_mode = 'stream';
+
+-- Create materialized view with Unix timestamp conversion (final version)
+CREATE MATERIALIZED VIEW IF NOT EXISTS routing_events_mv TO routing_events AS
+SELECT
+ event_id,
+ merchant_id,
+ request_id,
+ endpoint,
+ method,
+ request_payload,
+ response_payload,
+ status_code,
+ processing_time_ms,
+ gateway_selected,
+ routing_algorithm_id,
+ error_message,
+ user_agent,
+ ip_address,
+ -- Convert Unix timestamp to DateTime (final fix)
+ CASE
+ WHEN created_at > 0
+ THEN toDateTime(created_at)
+ ELSE now()
+ END AS created_at,
+ now() AS inserted_at,
+ sign_flag
+FROM routing_events_queue
+WHERE length(_error) = 0;
diff --git a/analytics/run_migrations.sh b/analytics/run_migrations.sh
new file mode 100755
index 00000000..fa3a4e02
--- /dev/null
+++ b/analytics/run_migrations.sh
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+echo 'Waiting for ClickHouse to be ready...'
+sleep 10
+
+echo 'Running analytics migrations...'
+for file in /analytics/migrations/*.sql; do
+ if [ -f "$file" ]; then
+ echo "Executing: $file"
+ clickhouse-client --host clickhouse --port 9000 --user analytics_user --password analytics_pass --multiquery --query "$(cat $file)"
+ if [ $? -eq 0 ]; then
+ echo "Successfully executed: $file"
+ else
+ echo "Failed to execute: $file"
+ exit 1
+ fi
+ fi
+done
+
+echo 'Analytics migrations completed!'
diff --git a/config.example.toml b/config.example.toml
index a5733002..ed691db9 100644
--- a/config.example.toml
+++ b/config.example.toml
@@ -11,11 +11,14 @@ port = 3001 # The port where the server should be hosted on
request_count = 1 # The requests per duration
duration = 60 # duration to rate limit the delete api (in sec)
-
[cache]
tti = 7200 # Idle time after a get/insert of a cache entry to free the cache (in secs)
max_capacity = 5000 # Max capacity of a single table cache
+[cache_config]
+service_config_redis_prefix = "DE_service_config_"
+service_config_ttl = 300 # 5 minutes
+
[database]
username = "sam" # username for the database
password = "damn" # password of the database
@@ -63,4 +66,3 @@ private_key = "key.pem" # path to the private key file (`pem` format)
client_idle_timeout = 90 # timeout for idle sockets being kept-alive
pool_max_idle_per_host = 10 # maximum idle connection per host allowed in the pool.
identity = "" # identity to be used for client certificate authentication in mtls.
-
diff --git a/config/development.toml b/config/development.toml
index 56b26693..bf996e26 100644
--- a/config/development.toml
+++ b/config/development.toml
@@ -9,7 +9,7 @@ port = 8080
[metrics]
host = "127.0.0.1"
-port = 9090
+port = 9094
[limit]
request_count = 1
@@ -49,164 +49,689 @@ max_feed_count = 200
tti = 7200 # i.e. 2 hours
max_capacity = 5000
+[cache_config]
+service_config_redis_prefix = "DE_service_config_"
+service_config_ttl = 300 # 5 minutes
+
+[compression_filepath]
+zstd_compression_filepath = "/tmp/extra-paths/redis-zstd-dictionaries/sbx"
+
+[analytics]
+enabled = false
+
+[analytics.kafka]
+brokers = ["localhost:9092"]
+topic_prefix = "decision-engine"
+batch_size = 100
+batch_timeout_ms = 1000
+max_consecutive_failures = 5
+
+[analytics.clickhouse]
+host = "http://clickhouse:8123"
+username = "analytics_user"
+password = "analytics_pass"
+database = "decision_engine_analytics"
+
+[secrets]
+open_router_private_key = ""
+
[tenant_secrets]
public = { schema = "public" }
[routing_config.keys]
+amount = { type = "integer", min = 0 }
+authentication_type = { type = "enum", values = "three_ds, no_three_ds" }
+bank_debit = { type = "enum", values = "ach, sepa, bacs, becs" }
+bank_redirect = { type = "enum", values = "giropay, ideal, sofort, eft, eps, bancontact_card, blik, local_bank_redirect, online_banking_thailand, online_banking_czech_republic, online_banking_finland, online_banking_fpx, online_banking_poland, online_banking_slovakia, przelewy24, trustly, bizum, interac, open_banking_uk, open_banking_pis" }
+bank_transfer = { type = "enum", values = "ach, sepa, sepa_bank_transfer, bacs, multibanco, pix, pse, permata_bank_transfer, bca_bank_transfer, bni_va, bri_va, cimb_va, danamon_va, mandiri_va, local_bank_transfer, instant_bank_transfer" }
billing_country = { type = "enum", values = "Afghanistan, AlandIslands, Albania, Algeria, AmericanSamoa, Andorra, Angola, Anguilla, Antarctica, AntiguaAndBarbuda, Argentina, Armenia, Aruba, Australia, Austria, Azerbaijan, Bahamas, Bahrain, Bangladesh, Barbados, Belarus, Belgium, Belize, Benin, Bermuda, Bhutan, BoliviaPlurinationalState, BonaireSintEustatiusAndSaba, BosniaAndHerzegovina, Botswana, BouvetIsland, Brazil, BritishIndianOceanTerritory, BruneiDarussalam, Bulgaria, BurkinaFaso, Burundi, CaboVerde, Cambodia, Cameroon, Canada, CaymanIslands, CentralAfricanRepublic, Chad, Chile, China, ChristmasIsland, CocosKeelingIslands, Colombia, Comoros, Congo, CongoDemocraticRepublic, CookIslands, CostaRica, CotedIvoire, Croatia, Cuba, Curacao, Cyprus, Czechia, Denmark, Djibouti, Dominica, DominicanRepublic, Ecuador, Egypt, ElSalvador, EquatorialGuinea, Eritrea, Estonia, Ethiopia, FalklandIslandsMalvinas, FaroeIslands, Fiji, Finland, France, FrenchGuiana, FrenchPolynesia, FrenchSouthernTerritories, Gabon, Gambia, Georgia, Germany, Ghana, Gibraltar, Greece, Greenland, Grenada, Guadeloupe, Guam, Guatemala, Guernsey, Guinea, GuineaBissau, Guyana, Haiti, HeardIslandAndMcDonaldIslands, HolySee, Honduras, HongKong, Hungary, Iceland, India, Indonesia, IranIslamicRepublic, Iraq, Ireland, IsleOfMan, Israel, Italy, Jamaica, Japan, Jersey, Jordan, Kazakhstan, Kenya, Kiribati, KoreaDemocraticPeoplesRepublic, KoreaRepublic, Kuwait, Kyrgyzstan, LaoPeoplesDemocraticRepublic, Latvia, Lebanon, Lesotho, Liberia, Libya, Liechtenstein, Lithuania, Luxembourg, Macao, MacedoniaTheFormerYugoslavRepublic, Madagascar, Malawi, Malaysia, Maldives, Mali, Malta, MarshallIslands, Martinique, Mauritania, Mauritius, Mayotte, Mexico, MicronesiaFederatedStates, MoldovaRepublic, Monaco, Mongolia, Montenegro, Montserrat, Morocco, Mozambique, Myanmar, Namibia, Nauru, Nepal, Netherlands, NewCaledonia, NewZealand, Nicaragua, Niger, Nigeria, Niue, NorfolkIsland, NorthernMarianaIslands, Norway, Oman, Pakistan, Palau, PalestineState, Panama, PapuaNewGuinea, Paraguay, Peru, Philippines, Pitcairn, Poland, Portugal, PuertoRico, Qatar, Reunion, Romania, RussianFederation, Rwanda, SaintBarthelemy, SaintHelenaAscensionAndTristandaCunha, SaintKittsAndNevis, SaintLucia, SaintMartinFrenchpart, SaintPierreAndMiquelon, SaintVincentAndTheGrenadines, Samoa, SanMarino, SaoTomeAndPrincipe, SaudiArabia, Senegal, Serbia, Seychelles, SierraLeone, Singapore, SintMaartenDutchpart, Slovakia, Slovenia, SolomonIslands, Somalia, SouthAfrica, SouthGeorgiaAndTheSouthSandwichIslands, SouthSudan, Spain, SriLanka, Sudan, Suriname, SvalbardAndJanMayen, Swaziland, Sweden, Switzerland, SyrianArabRepublic, TaiwanProvinceOfChina, Tajikistan, TanzaniaUnitedRepublic, Thailand, TimorLeste, Togo, Tokelau, Tonga, TrinidadAndTobago, Tunisia, Turkey, Turkmenistan, TurksAndCaicosIslands, Tuvalu, Uganda, Ukraine, UnitedArabEmirates, UnitedKingdomOfGreatBritainAndNorthernIreland, UnitedStatesOfAmerica, UnitedStatesMinorOutlyingIslands, Uruguay, Uzbekistan, Vanuatu, VenezuelaBolivarianRepublic, Vietnam, VirginIslandsBritish, VirginIslandsUS, WallisAndFutuna, WesternSahara, Yemen, Zambia, Zimbabwe" }
-issuer_country = { type = "enum", values = "Afghanistan, AlandIslands, Albania, Algeria, AmericanSamoa, Andorra, Angola, Anguilla, Antarctica, AntiguaAndBarbuda, Argentina, Armenia, Aruba, Australia, Austria, Azerbaijan, Bahamas, Bahrain, Bangladesh, Barbados, Belarus, Belgium, Belize, Benin, Bermuda, Bhutan, BoliviaPlurinationalState, BonaireSintEustatiusAndSaba, BosniaAndHerzegovina, Botswana, BouvetIsland, Brazil, BritishIndianOceanTerritory, BruneiDarussalam, Bulgaria, BurkinaFaso, Burundi, CaboVerde, Cambodia, Cameroon, Canada, CaymanIslands, CentralAfricanRepublic, Chad, Chile, China, ChristmasIsland, CocosKeelingIslands, Colombia, Comoros, Congo, CongoDemocraticRepublic, CookIslands, CostaRica, CotedIvoire, Croatia, Cuba, Curacao, Cyprus, Czechia, Denmark, Djibouti, Dominica, DominicanRepublic, Ecuador, Egypt, ElSalvador, EquatorialGuinea, Eritrea, Estonia, Ethiopia, FalklandIslandsMalvinas, FaroeIslands, Fiji, Finland, France, FrenchGuiana, FrenchPolynesia, FrenchSouthernTerritories, Gabon, Gambia, Georgia, Germany, Ghana, Gibraltar, Greece, Greenland, Grenada, Guadeloupe, Guam, Guatemala, Guernsey, Guinea, GuineaBissau, Guyana, Haiti, HeardIslandAndMcDonaldIslands, HolySee, Honduras, HongKong, Hungary, Iceland, India, Indonesia, IranIslamicRepublic, Iraq, Ireland, IsleOfMan, Israel, Italy, Jamaica, Japan, Jersey, Jordan, Kazakhstan, Kenya, Kiribati, KoreaDemocraticPeoplesRepublic, KoreaRepublic, Kuwait, Kyrgyzstan, LaoPeoplesDemocraticRepublic, Latvia, Lebanon, Lesotho, Liberia, Libya, Liechtenstein, Lithuania, Luxembourg, Macao, MacedoniaTheFormerYugoslavRepublic, Madagascar, Malawi, Malaysia, Maldives, Mali, Malta, MarshallIslands, Martinique, Mauritania, Mauritius, Mayotte, Mexico, MicronesiaFederatedStates, MoldovaRepublic, Monaco, Mongolia, Montenegro, Montserrat, Morocco, Mozambique, Myanmar, Namibia, Nauru, Nepal, Netherlands, NewCaledonia, NewZealand, Nicaragua, Niger, Nigeria, Niue, NorfolkIsland, NorthernMarianaIslands, Norway, Oman, Pakistan, Palau, PalestineState, Panama, PapuaNewGuinea, Paraguay, Peru, Philippines, Pitcairn, Poland, Portugal, PuertoRico, Qatar, Reunion, Romania, RussianFederation, Rwanda, SaintBarthelemy, SaintHelenaAscensionAndTristandaCunha, SaintKittsAndNevis, SaintLucia, SaintMartinFrenchpart, SaintPierreAndMiquelon, SaintVincentAndTheGrenadines, Samoa, SanMarino, SaoTomeAndPrincipe, SaudiArabia, Senegal, Serbia, Seychelles, SierraLeone, Singapore, SintMaartenDutchpart, Slovakia, Slovenia, SolomonIslands, Somalia, SouthAfrica, SouthGeorgiaAndTheSouthSandwichIslands, SouthSudan, Spain, SriLanka, Sudan, Suriname, SvalbardAndJanMayen, Swaziland, Sweden, Switzerland, SyrianArabRepublic, TaiwanProvinceOfChina, Tajikistan, TanzaniaUnitedRepublic, Thailand, TimorLeste, Togo, Tokelau, Tonga, TrinidadAndTobago, Tunisia, Turkey, Turkmenistan, TurksAndCaicosIslands, Tuvalu, Uganda, Ukraine, UnitedArabEmirates, UnitedKingdomOfGreatBritainAndNorthernIreland, UnitedStatesOfAmerica, UnitedStatesMinorOutlyingIslands, Uruguay, Uzbekistan, Vanuatu, VenezuelaBolivarianRepublic, Vietnam, VirginIslandsBritish, VirginIslandsUS, WallisAndFutuna, WesternSahara, Yemen, Zambia, Zimbabwe" }
business_country = { type = "enum", values = "Afghanistan, AlandIslands, Albania, Algeria, AmericanSamoa, Andorra, Angola, Anguilla, Antarctica, AntiguaAndBarbuda, Argentina, Armenia, Aruba, Australia, Austria, Azerbaijan, Bahamas, Bahrain, Bangladesh, Barbados, Belarus, Belgium, Belize, Benin, Bermuda, Bhutan, BoliviaPlurinationalState, BonaireSintEustatiusAndSaba, BosniaAndHerzegovina, Botswana, BouvetIsland, Brazil, BritishIndianOceanTerritory, BruneiDarussalam, Bulgaria, BurkinaFaso, Burundi, CaboVerde, Cambodia, Cameroon, Canada, CaymanIslands, CentralAfricanRepublic, Chad, Chile, China, ChristmasIsland, CocosKeelingIslands, Colombia, Comoros, Congo, CongoDemocraticRepublic, CookIslands, CostaRica, CotedIvoire, Croatia, Cuba, Curacao, Cyprus, Czechia, Denmark, Djibouti, Dominica, DominicanRepublic, Ecuador, Egypt, ElSalvador, EquatorialGuinea, Eritrea, Estonia, Ethiopia, FalklandIslandsMalvinas, FaroeIslands, Fiji, Finland, France, FrenchGuiana, FrenchPolynesia, FrenchSouthernTerritories, Gabon, Gambia, Georgia, Germany, Ghana, Gibraltar, Greece, Greenland, Grenada, Guadeloupe, Guam, Guatemala, Guernsey, Guinea, GuineaBissau, Guyana, Haiti, HeardIslandAndMcDonaldIslands, HolySee, Honduras, HongKong, Hungary, Iceland, India, Indonesia, IranIslamicRepublic, Iraq, Ireland, IsleOfMan, Israel, Italy, Jamaica, Japan, Jersey, Jordan, Kazakhstan, Kenya, Kiribati, KoreaDemocraticPeoplesRepublic, KoreaRepublic, Kuwait, Kyrgyzstan, LaoPeoplesDemocraticRepublic, Latvia, Lebanon, Lesotho, Liberia, Libya, Liechtenstein, Lithuania, Luxembourg, Macao, MacedoniaTheFormerYugoslavRepublic, Madagascar, Malawi, Malaysia, Maldives, Mali, Malta, MarshallIslands, Martinique, Mauritania, Mauritius, Mayotte, Mexico, MicronesiaFederatedStates, MoldovaRepublic, Monaco, Mongolia, Montenegro, Montserrat, Morocco, Mozambique, Myanmar, Namibia, Nauru, Nepal, Netherlands, NewCaledonia, NewZealand, Nicaragua, Niger, Nigeria, Niue, NorfolkIsland, NorthernMarianaIslands, Norway, Oman, Pakistan, Palau, PalestineState, Panama, PapuaNewGuinea, Paraguay, Peru, Philippines, Pitcairn, Poland, Portugal, PuertoRico, Qatar, Reunion, Romania, RussianFederation, Rwanda, SaintBarthelemy, SaintHelenaAscensionAndTristandaCunha, SaintKittsAndNevis, SaintLucia, SaintMartinFrenchpart, SaintPierreAndMiquelon, SaintVincentAndTheGrenadines, Samoa, SanMarino, SaoTomeAndPrincipe, SaudiArabia, Senegal, Serbia, Seychelles, SierraLeone, Singapore, SintMaartenDutchpart, Slovakia, Slovenia, SolomonIslands, Somalia, SouthAfrica, SouthGeorgiaAndTheSouthSandwichIslands, SouthSudan, Spain, SriLanka, Sudan, Suriname, SvalbardAndJanMayen, Swaziland, Sweden, Switzerland, SyrianArabRepublic, TaiwanProvinceOfChina, Tajikistan, TanzaniaUnitedRepublic, Thailand, TimorLeste, Togo, Tokelau, Tonga, TrinidadAndTobago, Tunisia, Turkey, Turkmenistan, TurksAndCaicosIslands, Tuvalu, Uganda, Ukraine, UnitedArabEmirates, UnitedKingdomOfGreatBritainAndNorthernIreland, UnitedStatesOfAmerica, UnitedStatesMinorOutlyingIslands, Uruguay, Uzbekistan, Vanuatu, VenezuelaBolivarianRepublic, Vietnam, VirginIslandsBritish, VirginIslandsUS, WallisAndFutuna, WesternSahara, Yemen, Zambia, Zimbabwe" }
business_label = { type = "str_value" }
-metadata = { type = "udf" }
-pay_later = { type = "enum", values = "affirm, alma, afterpay_clearpay, klarna, pay_bright, atome, walley" }
-gift_card = { type = "enum", values = "givex, pay_safe_card" }
-upi = { type = "enum", values = "upi_collect, upi_intent" }
-wallet = { type = "enum", values = "amazon_pay, apple_pay, google_pay, paypal, ali_pay, ali_pay_hk, dana, mb_way, mobile_pay, samsung_pay, twint, vipps, touch_n_go, swish, we_chat_pay, go_pay, gcash, momo, kakao_pay, cashapp, mifinity, paze" }
-voucher = { type = "enum", values = "boleto, efecty, pago_efectivo, red_compra, red_pagos, indomaret, alfamart, oxxo, seven_eleven, lawson, mini_stop, family_mart, seicomart, pay_easy" }
-bank_transfer = { type = "enum", values = "ach, sepa, sepa_bank_transfer, bacs, multibanco, pix, pse, permata_bank_transfer, bca_bank_transfer, bni_va, bri_va, cimb_va, danamon_va, mandiri_va, local_bank_transfer, instant_bank_transfer" }
-bank_redirect = { type = "enum", values = "giropay, ideal, sofort, eft, eps, bancontact_card, blik, local_bank_redirect, online_banking_thailand, online_banking_czech_republic, online_banking_finland, online_banking_fpx, online_banking_poland, online_banking_slovakia, przelewy24, trustly, bizum, interac, open_banking_uk, open_banking_pis" }
-customer_device_display_size = { type = "enum", values = "size320x568, size375x667, size390x844, size414x896, size428x926, size768x1024, size834x1112, size834x1194, size1024x1366, size1280x720, size1366x768, size1440x900, size1920x1080, size2560x1440, size3840x2160, size500x600, size600x400, size360x640, size412x915, size800x1280" }
-customer_device_type = { type = "enum", values = "mobile, tablet, desktop, gaming_console" }
-customer_device_platform = { type = "enum", values = "web, android, ios" }
-bank_debit = { type = "enum", values = "ach, sepa, bacs, becs" }
-crypto = { type = "enum", values = "crypto_currency" }
-reward = { type = "enum", values = "evoucher, classic_reward" }
+capture_method = { type = "enum", values = "automatic, manual, manual_multiple, scheduled, sequential_automatic" }
+card = { type = "enum", values = "debit, credit" }
+card_bin = { type = "str_value", exact_length = 6, regex = "^[0-9]{6}$" }
+card_discovery = { type = "enum", values = "manual, saved_card, click_to_pay" }
+card_network = { type = "enum", values = "visa, VISA, Visa, visaCard, mastercard, MASTERCARD, MasterCard, masterCard, mastercardCard, master_card, Master_card, Master_Card, Master Card, Mastercard, american_express, AMERICANEXPRESS, AmericanExpress, americanExpress, americanExpressCard, amex, AMEX, Amex, jcb, JCB, Jcb, diners_club, DINERSCLUB, DinersClub, dinersClub, dinersClubCard, discover, DISCOVER, Discover, discoverCard, cartes_bancaires, CARTESBANCAIRES, CartesBancaires, cartesBancaires, union_pay, UNIONPAY, UnionPay, unionPay, interac, INTERAC, Interac, rupay, RUPAY, RuPay, ruPay, maestro, MAESTRO, Maestro, star, STAR, Star, pulse, PULSE, Pulse, accel, ACCEL, Accel, nyce, NYCE, Nyce" }
card_redirect = { type = "enum", values = "knet, benefit, momo_atm, card_redirect" }
-real_time_payment = { type = "enum", values = "fps, duit_now, prompt_pay, viet_qr" }
-open_banking = { type = "enum", values = "open_banking_pis" }
-mobile_payment = { type = "enum", values = "direct_carrier_billing" }
-payment_method = { type = "enum", values = "card, card_redirect, pay_later, wallet, bank_redirect, bank_transfer, crypto, bank_debit, reward, real_time_payment, upi, voucher, gift_card, open_banking, mobile_payment" }
card_type = { type = "enum", values = "debit, credit" }
-payment_card_bin = { type = "udf" }
-issuer_name = { type = "str_value" }
-payment_card_type = { type = "enum", values = "CREDIT, DEBIT" }
+crypto = { type = "enum", values = "crypto_currency" }
+currency = { type = "enum", values = "AED, AFN, ALL, AMD, ANG, AOA, ARS, AUD, AWG, AZN, BAM, BBD, BDT, BGN, BHD, BIF, BMD, BND, BOB, BRL, BSD, BTN, BWP, BYN, BZD, CAD, CDF, CHF, CLF, CLP, CNY, COP, CRC, CUC, CUP, CVE, CZK, DJF, DKK, DOP, DZD, EGP, ERN, ETB, EUR, FJD, FKP, GBP, GEL, GHS, GIP, GMD, GNF, GTQ, GYD, HKD, HNL, HRK, HTG, HUF, IDR, ILS, INR, IQD, IRR, ISK, JMD, JOD, JPY, KES, KGS, KHR, KMF, KPW, KRW, KWD, KYD, KZT, LAK, LBP, LKR, LRD, LSL, LYD, MAD, MDL, MGA, MKD, MMK, MNT, MOP, MRU, MUR, MVR, MWK, MXN, MYR, MZN, NAD, NGN, NIO, NOK, NPR, NZD, OMR, PAB, PEN, PGK, PHP, PKR, PLN, PYG, QAR, RON, RSD, RUB, RWF, SAR, SBD, SCR, SDG, SEK, SGD, SHP, SLE, SLL, SOS, SRD, SSP, STD, STN, SVC, SYP, SZL, THB, TJS, TMT, TND, TOP, TRY, TTD, TWD, TZS, UAH, UGX, USD, UYU, UZS, VES, VND, VUV, WST, XAF, XCD, XOF, XPF, YER, ZAR, ZMW, ZWL" }
+extended_card_bin = { type = "str_value", exact_length = 8, regex = "^[0-9]{8}$" }
+gift_card = { type = "enum", values = "givex, pay_safe_card" }
+issuer_country = { type = "enum", values = "Afghanistan, AlandIslands, Albania, Algeria, AmericanSamoa, Andorra, Angola, Anguilla, Antarctica, AntiguaAndBarbuda, Argentina, Armenia, Aruba, Australia, Austria, Azerbaijan, Bahamas, Bahrain, Bangladesh, Barbados, Belarus, Belgium, Belize, Benin, Bermuda, Bhutan, BoliviaPlurinationalState, BonaireSintEustatiusAndSaba, BosniaAndHerzegovina, Botswana, BouvetIsland, Brazil, BritishIndianOceanTerritory, BruneiDarussalam, Bulgaria, BurkinaFaso, Burundi, CaboVerde, Cambodia, Cameroon, Canada, CaymanIslands, CentralAfricanRepublic, Chad, Chile, China, ChristmasIsland, CocosKeelingIslands, Colombia, Comoros, Congo, CongoDemocraticRepublic, CookIslands, CostaRica, CotedIvoire, Croatia, Cuba, Curacao, Cyprus, Czechia, Denmark, Djibouti, Dominica, DominicanRepublic, Ecuador, Egypt, ElSalvador, EquatorialGuinea, Eritrea, Estonia, Ethiopia, FalklandIslandsMalvinas, FaroeIslands, Fiji, Finland, France, FrenchGuiana, FrenchPolynesia, FrenchSouthernTerritories, Gabon, Gambia, Georgia, Germany, Ghana, Gibraltar, Greece, Greenland, Grenada, Guadeloupe, Guam, Guatemala, Guernsey, Guinea, GuineaBissau, Guyana, Haiti, HeardIslandAndMcDonaldIslands, HolySee, Honduras, HongKong, Hungary, Iceland, India, Indonesia, IranIslamicRepublic, Iraq, Ireland, IsleOfMan, Israel, Italy, Jamaica, Japan, Jersey, Jordan, Kazakhstan, Kenya, Kiribati, KoreaDemocraticPeoplesRepublic, KoreaRepublic, Kuwait, Kyrgyzstan, LaoPeoplesDemocraticRepublic, Latvia, Lebanon, Lesotho, Liberia, Libya, Liechtenstein, Lithuania, Luxembourg, Macao, MacedoniaTheFormerYugoslavRepublic, Madagascar, Malawi, Malaysia, Maldives, Mali, Malta, MarshallIslands, Martinique, Mauritania, Mauritius, Mayotte, Mexico, MicronesiaFederatedStates, MoldovaRepublic, Monaco, Mongolia, Montenegro, Montserrat, Morocco, Mozambique, Myanmar, Namibia, Nauru, Nepal, Netherlands, NewCaledonia, NewZealand, Nicaragua, Niger, Nigeria, Niue, NorfolkIsland, NorthernMarianaIslands, Norway, Oman, Pakistan, Palau, PalestineState, Panama, PapuaNewGuinea, Paraguay, Peru, Philippines, Pitcairn, Poland, Portugal, PuertoRico, Qatar, Reunion, Romania, RussianFederation, Rwanda, SaintBarthelemy, SaintHelenaAscensionAndTristandaCunha, SaintKittsAndNevis, SaintLucia, SaintMartinFrenchpart, SaintPierreAndMiquelon, SaintVincentAndTheGrenadines, Samoa, SanMarino, SaoTomeAndPrincipe, SaudiArabia, Senegal, Serbia, Seychelles, SierraLeone, Singapore, SintMaartenDutchpart, Slovakia, Slovenia, SolomonIslands, Somalia, SouthAfrica, SouthGeorgiaAndTheSouthSandwichIslands, SouthSudan, Spain, SriLanka, Sudan, Suriname, SvalbardAndJanMayen, Swaziland, Sweden, Switzerland, SyrianArabRepublic, TaiwanProvinceOfChina, Tajikistan, TanzaniaUnitedRepublic, Thailand, TimorLeste, Togo, Tokelau, Tonga, TrinidadAndTobago, Tunisia, Turkey, Turkmenistan, TurksAndCaicosIslands, Tuvalu, Uganda, Ukraine, UnitedArabEmirates, UnitedKingdomOfGreatBritainAndNorthernIreland, UnitedStatesOfAmerica, UnitedStatesMinorOutlyingIslands, Uruguay, Uzbekistan, Vanuatu, VenezuelaBolivarianRepublic, Vietnam, VirginIslandsBritish, VirginIslandsUS, WallisAndFutuna, WesternSahara, Yemen, Zambia, Zimbabwe" }
+issuer_name = { type = "str_value", min_length = 1 }
mandate_acceptance_type = { type = "enum", values = "online, offline" }
mandate_type = { type = "enum", values = "single_use, multi_use" }
-card_network = { type = "enum", values = "visa, VISA, Visa, visaCard, mastercard, MASTERCARD, MasterCard, masterCard, mastercardCard, master_card, Master_card, Master_Card, Master Card, Mastercard, american_express, AMERICANEXPRESS, AmericanExpress, americanExpress, americanExpressCard, amex, AMEX, Amex, jcb, JCB, Jcb, diners_club, DINERSCLUB, DinersClub, dinersClub, dinersClubCard, discover, DISCOVER, Discover, discoverCard, cartes_bancaires, CARTESBANCAIRES, CartesBancaires, cartesBancaires, union_pay, UNIONPAY, UnionPay, unionPay, interac, INTERAC, Interac, rupay, RUPAY, RuPay, ruPay, maestro, MAESTRO, Maestro, star, STAR, Star, pulse, PULSE, Pulse, accel, ACCEL, Accel, nyce, NYCE, Nyce" }
-payment_type = { type = "enum", values = "normal, new_mandate, setup_mandate, recurring_mandate, non_mandate" }
+metadata = { type = "udf" }
+mobile_payment = { type = "enum", values = "direct_carrier_billing" }
+network_token = { type = "enum", values = "network_token" }
+open_banking = { type = "enum", values = "open_banking_pis" }
+pay_later = { type = "enum", values = "affirm, alma, afterpay_clearpay, klarna, pay_bright, atome, walley" }
+payment_method = { type = "enum", values = "card, card_redirect, pay_later, wallet, bank_redirect, bank_transfer, crypto, bank_debit, reward, real_time_payment, upi, voucher, gift_card, open_banking, mobile_payment" }
payment_method_type = { type = "enum", values = "ach, affirm, afterpay_clearpay, alfamart, ali_pay, ali_pay_hk, alma, amazon_pay, apple_pay, atome, bacs, bancontact_card, becs, benefit, bizum, blik, boleto, bca_bank_transfer, bni_va, bri_va, card, card_redirect, cimb_va, classic_reward, credit, crypto_currency, cashapp, dana, danamon_va, debit, duit_now, efecty, eft, eps, fps, evoucher, giropay, givex, google_pay, go_pay, gcash, ideal, interac, indomaret, klarna, kakao_pay, local_bank_redirect, mandiri_va, knet, mb_way, mobile_pay, momo, momo_atm, multibanco, online_banking_thailand, online_banking_czech_republic, online_banking_finland, online_banking_fpx, online_banking_poland, online_banking_slovakia, oxxo, pago_efectivo, permata_bank_transfer, open_banking_uk, pay_bright, paypal, paze, pix, pay_safe_card, przelewy24, prompt_pay, pse, red_compra, red_pagos, samsung_pay, sepa, sepa_bank_transfer, sofort, swish, touch_n_go, trustly, twint, upi_collect, upi_intent, vipps, viet_qr, venmo, walley, we_chat_pay, seven_eleven, lawson, mini_stop, family_mart, seicomart, pay_easy, local_bank_transfer, mifinity, open_banking_pis, direct_carrier_billing, instant_bank_transfer" }
-authentication_type = { type = "enum", values = "three_ds, no_three_ds" }
-capture_methods = { type = "enum", values = "automatic, manual, manual_multiple, scheduled, sequential_automatic" }
+payment_type = { type = "enum", values = "normal, new_mandate, setup_mandate, recurring_mandate, non_mandate" }
+real_time_payment = { type = "enum", values = "fps, duit_now, prompt_pay, viet_qr" }
+reward = { type = "enum", values = "evoucher, classic_reward" }
setup_future_usage = { type = "enum", values = "on_session, off_session" }
-payment_card_network = { type = "enum", values = "visa, mastercard, american_express, jcb, diners_club, discover, cartes_bancaires, union_pay, interac, rupay, maestro" }
-amount = { type = "integer" }
-login_date = { type = "str_value" }
-currency = { type = "enum", values = "AED, AFN, ALL, AMD, ANG, AOA, ARS, AUD, AWG, AZN, BAM, BBD, BDT, BGN, BHD, BIF, BMD, BND, BOB, BRL, BSD, BTN, BWP, BYN, BZD, CAD, CDF, CHF, CLF, CLP, CNY, COP, CRC, CUC, CUP, CVE, CZK, DJF, DKK, DOP, DZD, EGP, ERN, ETB, EUR, FJD, FKP, GBP, GEL, GHS, GIP, GMD, GNF, GTQ, GYD, HKD, HNL, HRK, HTG, HUF, IDR, ILS, INR, IQD, IRR, ISK, JMD, JOD, JPY, KES, KGS, KHR, KMF, KPW, KRW, KWD, KYD, KZT, LAK, LBP, LKR, LRD, LSL, LYD, MAD, MDL, MGA, MKD, MMK, MNT, MOP, MRU, MUR, MVR, MWK, MXN, MYR, MZN, NAD, NGN, NIO, NOK, NPR, NZD, OMR, PAB, PEN, PGK, PHP, PKR, PLN, PYG, QAR, RON, RSD, RUB, RWF, SAR, SBD, SCR, SDG, SEK, SGD, SHP, SLE, SLL, SOS, SRD, SSP, STD, STN, SVC, SYP, SZL, THB, TJS, TMT, TND, TOP, TRY, TTD, TWD, TZS, UAH, UGX, USD, UYU, UZS, VES, VND, VUV, WST, XAF, XCD, XOF, XPF, YER, ZAR, ZMW, ZWL" }
-payment_card_issuer_country = { type = "enum", values = "AF, AX, AL, DZ, AS, AD, AO, AI, AQ, AG, AR, AM, AW, AU, AT, AZ, BS, BH, BD, BB, BY, BE, BZ, BJ, BM, BT, BO, BQ, BA, BW, BV, BR, IO, BN, BG, BF, BI, KH, CM, CA, CV, KY, CF, TD, CL, CN, CX, CC, CO, KM, CG, CD, CK, CR, CI, HR, CU, CW, CY, CZ, DK, DJ, DM, DO, EC, EG, SV, GQ, ER, EE, ET, FK, FO, FJ, FI, FR, GF, PF, TF, GA, GM, GE, DE, GH, GI, GR, GL, GD, GP, GU, GT, GG, GN, GW, GY, HT, HM, VA, HN, HK, HU, IS, IN, ID, IR, IQ, IE, IM, IL, IT, JM, JP, JE, JO, KZ, KE, KI, KP, KR, KW, KG, LA, LV, LB, LS, LR, LY, LI, LT, LU, MO, MK, MG, MW, MY, MV, ML, MT, MH, MQ, MR, MU, YT, MX, FM, MD, MC, MN, ME, MS, MA, MZ, MM, NA, NR, NP, NL, NC, NZ, NI, NE, NG, NU, NF, MP, NO, OM, PK, PW, PS, PA, PG, PY, PE, PH, PN, PL, PT, PR, QA, RE, RO, RU, RW, BL, SH, KN, LC, MF, PM, VC, WS, SM, ST, SA, SN, RS, SC, SL, SG, SX, SK, SI, SB, SO, ZA, GS, SS, ES, LK, SD, SR, SJ, SZ, SE, CH, SY, TW, TJ, TZ, TH, TL, TG, TK, TO, TT, TN, TR, TM, TC, TV, UG, UA, AE, GB, UM, UY, UZ, VU, VE, VN, VG, VI, WF, EH, YE, ZM, ZW, US" }
-card_bin = { type = "str_value" }
-capture_method = { type = "enum", values = "automatic, manual" }
-new_customer = { type = "udf" }
-udf1 = { type = "str_value" }
-order_udf1 = { type = "global_ref" }
-payment_payment_method = { type = "enum", values = "NB_HDFC, NB_ICICI, NB_SBI" }
-payment_payment_source = { type = "enum", values = "net.one97.paytm, @paytm" }
-txn_is_emi = { type = "enum", values = "true, false" }
-
-[routing_config.default]
-output = ["stripe", "adyen"]
-
-[[routing_config.constraint_graph.nodes]]
-preds = []
-succs = [0]
-
-[routing_config.constraint_graph.nodes.kind]
-kind = "value"
-
-[routing_config.constraint_graph.nodes.kind.data]
-kind = "value"
-
-[routing_config.constraint_graph.nodes.kind.data.data]
-key = "payment_method"
-comparison = "equal"
-
-[routing_config.constraint_graph.nodes.kind.data.data.value]
-type = "enum_variant"
-value = "card"
-
-[[routing_config.constraint_graph.nodes]]
-preds = []
-succs = [1]
-
-[routing_config.constraint_graph.nodes.kind]
-kind = "value"
-
-[routing_config.constraint_graph.nodes.kind.data]
-kind = "value"
-
-[routing_config.constraint_graph.nodes.kind.data.data]
-key = "payment_method"
-comparison = "equal"
-
-[routing_config.constraint_graph.nodes.kind.data.data.value]
-type = "enum_variant"
-value = "bank_debit"
-
-[[routing_config.constraint_graph.nodes]]
-preds = [0]
-succs = []
-
-[routing_config.constraint_graph.nodes.kind]
-kind = "value"
-
-[routing_config.constraint_graph.nodes.kind.data]
-kind = "value"
-
-[routing_config.constraint_graph.nodes.kind.data.data]
-key = "output"
-comparison = "equal"
-
-[routing_config.constraint_graph.nodes.kind.data.data.value]
-type = "enum_variant"
-value = "stripe"
-
-[[routing_config.constraint_graph.nodes]]
-preds = [1]
-succs = []
-
-[routing_config.constraint_graph.nodes.kind]
-kind = "value"
-
-[routing_config.constraint_graph.nodes.kind.data]
-kind = "value"
-
-[routing_config.constraint_graph.nodes.kind.data.data]
-key = "output"
-comparison = "equal"
-
-[routing_config.constraint_graph.nodes.kind.data.data.value]
-type = "enum_variant"
-value = "adyen"
-
-[[routing_config.constraint_graph.edges]]
-strength = "strong"
-relation = "positive"
-pred = 0
-succ = 2
-
-[[routing_config.constraint_graph.edges]]
-strength = "strong"
-relation = "positive"
-pred = 1
-succ = 3
+transaction_initiator = { type = "enum", values = "customer, merchant" }
+upi = { type = "enum", values = "upi_collect, upi_intent" }
+voucher = { type = "enum", values = "boleto, efecty, pago_efectivo, red_compra, red_pagos, indomaret, alfamart, oxxo, seven_eleven, lawson, mini_stop, family_mart, seicomart, pay_easy" }
+wallet = { type = "enum", values = "amazon_pay, apple_pay, google_pay, paypal, ali_pay, ali_pay_hk, dana, mb_way, mobile_pay, samsung_pay, twint, vipps, touch_n_go, swish, we_chat_pay, go_pay, gcash, momo, kakao_pay, cashapp, mifinity, paze" }
[debit_routing_config]
-fraud_check_fee = 0.01
+fraud_check_fee = 1.0
[debit_routing_config.network_fee]
-visa = { percentage = 0.1375, fixed_amount = 0.020 }
-mastercard = { percentage = 0.15, fixed_amount = 0.040 }
-accel = { percentage = 0.0, fixed_amount = 0.040 }
-nyce = { percentage = 0.10, fixed_amount = 0.015 }
-pulse = { percentage = 0.10, fixed_amount = 0.03 }
-star = { percentage = 0.10, fixed_amount = 0.015 }
+visa = { percentage = 0.1375, fixed_amount = 2.0 }
+mastercard = { percentage = 0.15, fixed_amount = 4.0 }
+accel = { percentage = 0.0, fixed_amount = 4.0 }
+nyce = { percentage = 0.10, fixed_amount = 1.5 }
+pulse = { percentage = 0.10, fixed_amount = 3.0 }
+star = { percentage = 0.10, fixed_amount = 1.5 }
[debit_routing_config.interchange_fee]
regulated = { percentage = 0.05, fixed_amount = 0.21 }
[debit_routing_config.interchange_fee.non_regulated]
-merchant_category_code_0001.visa = { percentage = 1.65, fixed_amount = 0.15 }
-merchant_category_code_0001.mastercard = { percentage = 1.65, fixed_amount = 0.15 }
-merchant_category_code_0001.accel = { percentage = 1.55, fixed_amount = 0.04 }
-merchant_category_code_0001.nyce = { percentage = 1.30, fixed_amount = 0.213125 }
-merchant_category_code_0001.pulse = { percentage = 1.60, fixed_amount = 0.15 }
-merchant_category_code_0001.star = { percentage = 1.63, fixed_amount = 0.15 }
+merchant_category_code_0001.visa = { percentage = 1.65, fixed_amount = 15.0 }
+merchant_category_code_0001.mastercard = { percentage = 1.65, fixed_amount = 15.0 }
+merchant_category_code_0001.accel = { percentage = 1.55, fixed_amount = 4.0 }
+merchant_category_code_0001.nyce = { percentage = 1.30, fixed_amount = 21.3125 }
+merchant_category_code_0001.pulse = { percentage = 1.60, fixed_amount = 15.0 }
+merchant_category_code_0001.star = { percentage = 1.63, fixed_amount = 15.0 }
+
+[pm_filters.default]
+google_pay = { country = "AL,DZ,AS,AO,AG,AR,AU,AT,AZ,BH,BY,BE,BR,BG,CA,CL,CO,HR,CZ,DK,DO,EG,EE,FI,FR,DE,GR,HK,HU,IN,ID,IE,IL,IT,JP,JO,KZ,KE,KW,LV,LB,LT,LU,MY,MX,NL,NZ,NO,OM,PK,PA,PE,PH,PL,PT,QA,RO,RU,SA,SG,SK,ZA,ES,LK,SE,CH,TW,TH,TR,UA,AE,GB,US,UY,VN" }
+apple_pay = { country = "AU,CN,HK,JP,MO,MY,NZ,SG,TW,AM,AT,AZ,BY,BE,BG,HR,CY,CZ,DK,EE,FO,FI,FR,GE,DE,GR,GL,GG,HU,IS,IE,IM,IT,KZ,JE,LV,LI,LT,LU,MT,MD,MC,ME,NL,NO,PL,PT,RO,SM,RS,SK,SI,ES,SE,CH,UA,GB,AR,CO,CR,BR,MX,PE,BH,IL,JO,KW,PS,QA,SA,AE,CA,UM,US,KR,VN,MA,ZA,VA,CL,SV,GT,HN,PA", currency = "AED,AUD,CHF,CAD,EUR,GBP,HKD,SGD,USD" }
+paypal = { currency = "AUD,BRL,CAD,CHF,CNY,CZK,DKK,EUR,GBP,HKD,HUF,ILS,JPY,MXN,MYR,NOK,NZD,PHP,PLN,SEK,SGD,THB,TWD,USD" }
+klarna = { country = "AT,BE,DK,FI,FR,DE,IE,IT,NL,NO,ES,SE,GB,US,CA", currency = "USD,GBP,EUR,CHF,DKK,SEK,NOK,AUD,PLN,CAD" }
+affirm = { country = "US", currency = "USD" }
+afterpay_clearpay = { country = "US,CA,GB,AU,NZ", currency = "GBP,AUD,NZD,CAD,USD" }
+giropay = { country = "DE", currency = "EUR" }
+eps = { country = "AT", currency = "EUR" }
+sofort = { country = "ES,GB,SE,AT,NL,DE,CH,BE,FR,FI,IT,PL", currency = "EUR" }
+ideal = { country = "NL", currency = "EUR" }
+
+[pm_filters.stripe]
+google_pay = { country = "AU, AT, BE, BR, BG, CA, HR, CZ, DK, EE, FI, FR, DE, GR, HK, HU, IN, ID, IE, IT, JP, LV, KE, LT, LU, MY, MX, NL, NZ, NO, PL, PT, RO, SG, SK, ZA, ES, SE, CH, TH, AE, GB, US, GI, LI, MT, CY, PH, IS, AR, CL, KR, IL"}
+apple_pay = { country = "AU, AT, BE, BR, BG, CA, HR, CY, CZ, DK, EE, FI, FR, DE, GR, HU, HK, IE, IT, JP, LV, LI, LT, LU, MT, MY, MX, NL, NZ, NO, PL, PT, RO, SK, SG, SI, ZA, ES, SE, CH, GB, AE, US" }
+klarna = { country = "AU,AT,BE,CA,CZ,DK,FI,FR,DE,GR,IE,IT,NL,NZ,NO,PL,PT,ES,SE,CH,GB,US", currency = "AUD,CAD,CHF,CZK,DKK,EUR,GBP,NOK,NZD,PLN,SEK,USD" }
+credit = { country = "AF,AX,AL,DZ,AS,AD,AO,AI,AQ,AG,AR,AM,AW,AU,AT,AZ,BS,BH,BD,BB,BY,BE,BZ,BJ,BM,BT,BO,BQ,BA,BW,BV,BR,IO,BN,BG,BF,BI,KH,CM,CA,CV,KY,CF,TD,CL,CN,CX,CC,CO,KM,CG,CD,CK,CR,CI,HR,CU,CW,CY,CZ,DK,DJ,DM,DO,EC,EG,SV,GQ,ER,EE,ET,FK,FO,FJ,FI,FR,GF,PF,TF,GA,GM,GE,DE,GH,GI,GR,GL,GD,GP,GU,GT,GG,GN,GW,GY,HT,HM,VA,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IM,IL,IT,JM,JP,JE,JO,KZ,KE,KI,KP,KR,KW,KG,LA,LV,LB,LS,LR,LY,LI,LT,LU,MO,MK,MG,MW,MY,MV,ML,MT,MH,MQ,MR,MU,YT,MX,FM,MD,MC,MN,ME,MS,MA,MZ,MM,NA,NR,NP,NL,NC,NZ,NI,NE,NG,NU,NF,MP,NO,OM,PK,PW,PS,PA,PG,PY,PE,PH,PN,PL,PT,PR,QA,RE,RO,RU,RW,BL,SH,KN,LC,MF,PM,VC,WS,SM,ST,SA,SN,RS,SC,SL,SG,SX,SK,SI,SB,SO,ZA,GS,SS,ES,LK,SD,SR,SJ,SZ,SE,CH,SY,TW,TJ,TZ,TH,TL,TG,TK,TO,TT,TN,TR,TM,TC,TV,UG,UA,AE,GB,UM,UY,UZ,VU,VE,VN,VG,VI,WF,EH,YE,ZM,ZW,US", currency = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BYN,BZD,CAD,CDF,CHF,CLF,CLP,CNY,COP,CRC,CUC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLE,SLL,SOS,SRD,SSP,STD,STN,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL"}
+debit = { country = "AF,AX,AL,DZ,AS,AD,AO,AI,AQ,AG,AR,AM,AW,AU,AT,AZ,BS,BH,BD,BB,BY,BE,BZ,BJ,BM,BT,BO,BQ,BA,BW,BV,BR,IO,BN,BG,BF,BI,KH,CM,CA,CV,KY,CF,TD,CL,CN,CX,CC,CO,KM,CG,CD,CK,CR,CI,HR,CU,CW,CY,CZ,DK,DJ,DM,DO,EC,EG,SV,GQ,ER,EE,ET,FK,FO,FJ,FI,FR,GF,PF,TF,GA,GM,GE,DE,GH,GI,GR,GL,GD,GP,GU,GT,GG,GN,GW,GY,HT,HM,VA,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IM,IL,IT,JM,JP,JE,JO,KZ,KE,KI,KP,KR,KW,KG,LA,LV,LB,LS,LR,LY,LI,LT,LU,MO,MK,MG,MW,MY,MV,ML,MT,MH,MQ,MR,MU,YT,MX,FM,MD,MC,MN,ME,MS,MA,MZ,MM,NA,NR,NP,NL,NC,NZ,NI,NE,NG,NU,NF,MP,NO,OM,PK,PW,PS,PA,PG,PY,PE,PH,PN,PL,PT,PR,QA,RE,RO,RU,RW,BL,SH,KN,LC,MF,PM,VC,WS,SM,ST,SA,SN,RS,SC,SL,SG,SX,SK,SI,SB,SO,ZA,GS,SS,ES,LK,SD,SR,SJ,SZ,SE,CH,SY,TW,TJ,TZ,TH,TL,TG,TK,TO,TT,TN,TR,TM,TC,TV,UG,UA,AE,GB,UM,UY,UZ,VU,VE,VN,VG,VI,WF,EH,YE,ZM,ZW,US", currency = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BYN,BZD,CAD,CDF,CHF,CLF,CLP,CNY,COP,CRC,CUC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLE,SLL,SOS,SRD,SSP,STD,STN,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL"}
+affirm = { country = "US", currency = "USD" }
+afterpay_clearpay = { country = "US,CA,GB,AU,NZ,FR,ES", currency = "USD,CAD,GBP,AUD,NZD" }
+cashapp = { country = "US", currency = "USD" }
+eps = { country = "AT", currency = "EUR" }
+giropay = { country = "DE", currency = "EUR" }
+ideal = { country = "NL", currency = "EUR" }
+multibanco = { country = "AT,BE,BG,HR,CY,CZ,DK,EE,FI,FR,DE,GI,GR,HU,IE,IT,LV,LI,LT,LU,MT,NL,NO,PL,PT,RO,SK,SI,ES,SE,CH,GB", currency = "EUR" }
+ach = { country = "US", currency = "USD" }
+revolut_pay = { currency = "EUR,GBP" }
+sepa = {country = "AT,BE,BG,HR,CY,CZ,DK,EE,FI,FR,DE,GI,GR,HU,IE,IT,LV,LI,LT,LU,MT,NL,NO,PL,PT,RO,SK,SI,ES,SE,CH,GB,IS,LI", currency="EUR"}
+bacs = { country = "GB", currency = "GBP" }
+becs = { country = "AU", currency = "AUD" }
+sofort = {country = "AT,BE,BG,HR,CY,CZ,DK,EE,FI,FR,DE,GR,HU,IS,IE,IT,LV,LI,LT,LU,MT,NL,NO,PL,PT,RO,SK,SI,ES,SE", currency = "EUR" }
+blik = {country="PL", currency = "PLN"}
+bancontact_card = { country = "BE", currency = "EUR" }
+przelewy24 = { country = "PL", currency = "EUR,PLN" }
+online_banking_fpx = { country = "MY", currency = "MYR" }
+amazon_pay = { country = "AF,AX,AL,DZ,AS,AD,AO,AI,AQ,AG,AR,AM,AW,AU,AT,AZ,BS,BH,BD,BB,BY,BE,BZ,BJ,BM,BT,BO,BQ,BA,BW,BV,BR,IO,BN,BG,BF,BI,KH,CM,CA,CV,KY,CF,TD,CL,CN,CX,CC,CO,KM,CG,CD,CK,CR,CI,HR,CU,CW,CY,CZ,DK,DJ,DM,DO,EC,EG,SV,GQ,ER,EE,ET,FK,FO,FJ,FI,FR,GF,PF,TF,GA,GM,GE,DE,GH,GI,GR,GL,GD,GP,GU,GT,GG,GN,GW,GY,HT,HM,VA,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IM,IL,IT,JM,JP,JE,JO,KZ,KE,KI,KP,KR,KW,KG,LA,LV,LB,LS,LR,LY,LI,LT,LU,MO,MK,MG,MW,MY,MV,ML,MT,MH,MQ,MR,MU,YT,MX,FM,MD,MC,MN,ME,MS,MA,MZ,MM,NA,NR,NP,NL,NC,NZ,NI,NE,NG,NU,NF,MP,NO,OM,PK,PW,PS,PA,PG,PY,PE,PH,PN,PL,PT,PR,QA,RE,RO,RU,RW,BL,SH,KN,LC,MF,PM,VC,WS,SM,ST,SA,SN,RS,SC,SL,SG,SX,SK,SI,SB,SO,ZA,GS,SS,ES,LK,SD,SR,SJ,SZ,SE,CH,SY,TW,TJ,TZ,TH,TL,TG,TK,TO,TT,TN,TR,TM,TC,TV,UG,UA,AE,GB,UM,UY,UZ,VU,VE,VN,VG,VI,WF,EH,YE,ZM,ZW,US", currency = "USD,AUD,GBP,DKK,EUR,HKD,JPY,NZD,NOK,ZAR,SEK,CHF" }
+we_chat_pay = { country = "CN", currency = "CNY,AUD,CAD,EUR,GBP,HKD,JPY,SGD,USD,DKK,NOK,SEK,CHF" }
+ali_pay = {country = "CN", currency = "AUD,CAD,CNY,EUR,GBP,HKD,JPY,MYR,NZD,SGD,USD"}
+
+[pm_filters.volt]
+open_banking = { country = "DE,GB,AT,BE,CY,EE,ES,FI,FR,GR,HR,IE,IT,LT,LU,LV,MT,NL,PT,SI,SK,BG,CZ,DK,HU,NO,PL,RO,SE,AU,BR", currency = "GBP,EUR,DKK,NOK,PLN,SEK" }
+open_banking_uk = { country = "DE,GB,AT,BE,CY,EE,ES,FI,FR,GR,HR,IE,IT,LT,LU,LV,MT,NL,PT,SI,SK,BG,CZ,DK,HU,NO,PL,RO,SE,AU,BR", currency = "GBP" }
+
+[pm_filters.razorpay]
+upi_collect = { country = "IN", currency = "INR" }
+
+[pm_filters.phonepe]
+upi_collect = { country = "IN", currency = "INR" }
+upi_intent = { country = "IN", currency = "INR" }
+
+[pm_filters.paytm]
+upi_collect = { country = "IN", currency = "INR" }
+upi_intent = { country = "IN", currency = "INR" }
+
+[pm_filters.hyperpg]
+credit = { currency = "INR,USD,GBP,EUR" }
+debit = { currency = "INR,USD,GBP,EUR" }
+
+[pm_filters.plaid]
+open_banking_pis = { currency = "EUR,GBP" }
+
+[pm_filters.adyen]
+google_pay = { country = "AT, AU, BE, BG, CA, HR, CZ, EE, FI, FR, DE, GR, HK, DK, HU, IE, IT, LV, LT, LU, NL, NO, PL, PT, RO, SK, ES, SE, CH, GB, US, NZ, SG", currency = "ALL, DZD, USD, AOA, XCD, ARS, AUD, EUR, AZN, BHD, BYN, BRL, BGN, CAD, CLP, COP, CZK, DKK, DOP, EGP, HKD, HUF, INR, IDR, ILS, JPY, JOD, KZT, KES, KWD, LBP, MYR, MXN, NZD, NOK, OMR, PKR, PAB, PEN, PHP, PLN, QAR, RON, RUB, SAR, SGD, ZAR, LKR, SEK, CHF, TWD, THB, TRY, UAH, AED, GBP, UYU, VND" }
+apple_pay = { country = "AT, BE, BG, HR, CY, CZ, DK, EE, FI, FR, DE, GR, GG, HU, IE, IM, IT, LV, LI, LT, LU, MT, NL, NO, PL, PT, RO, SK, SI, SE, ES, CH, GB, US, PR, CA, AU, HK, NZ, SG", currency = "EGP, MAD, ZAR, AUD, CNY, HKD, JPY, MOP, MYR, MNT, NZD, SGD, KRW, TWD, VND, AMD, EUR, AZN, BYN, BGN, CZK, DKK, GEL, GBP, HUF, ISK, KZT, CHF, MDL, NOK, PLN, RON, RSD, SEK, CHF, UAH, ARS, BRL, CLP, COP, CRC, DOP, GTQ, HNL, MXN, PAB, USD, PYG, PEN, BSD, UYU, BHD, ILS, JOD, KWD, OMR, ILS, QAR, SAR, AED, CAD" }
+paypal = { country = "AU,NZ,CN,JP,HK,MY,TH,KR,PH,ID,AE,KW,BR,ES,GB,SE,NO,SK,AT,NL,DE,HU,CY,LU,CH,BE,FR,DK,FI,RO,HR,UA,MT,SI,GI,PT,IE,CZ,EE,LT,LV,IT,PL,IS,CA,US", currency = "AUD,BRL,CAD,CZK,DKK,EUR,HKD,HUF,INR,JPY,MYR,MXN,NZD,NOK,PHP,PLN,RUB,GBP,SGD,SEK,CHF,THB,USD" }
+mobile_pay = { country = "DK,FI", currency = "DKK,SEK,NOK,EUR" }
+ali_pay = { country = "AU,JP,HK,SG,MY,TH,ES,GB,SE,NO,AT,NL,DE,CY,CH,BE,FR,DK,FI,RO,MT,SI,GR,PT,IE,IT,CA,US", currency = "USD,EUR,GBP,JPY,AUD,SGD,CHF,SEK,NOK,NZD,THB,HKD,CAD" }
+we_chat_pay = { country = "AU,NZ,CN,JP,HK,SG,ES,GB,SE,NO,AT,NL,DE,CY,CH,BE,FR,DK,LI,MT,SI,GR,PT,IT,CA,US", currency = "AUD,CAD,CNY,EUR,GBP,HKD,JPY,NZD,SGD,USD" }
+mb_way = { country = "PT", currency = "EUR" }
+klarna = { country = "AU,AT,BE,CA,CZ,DK,FI,FR,DE,GR,IE,IT,NO,PL,PT,RO,ES,SE,CH,NL,GB,US", currency = "AUD,EUR,CAD,CZK,DKK,NOK,PLN,RON,SEK,CHF,GBP,USD" }
+affirm = { country = "US", currency = "USD" }
+afterpay_clearpay = { country = "AU,NZ,ES,GB,FR,IT,CA,US", currency = "GBP" }
+pay_bright = { country = "CA", currency = "CAD" }
+walley = { country = "SE,NO,DK,FI", currency = "DKK,EUR,NOK,SEK" }
+giropay = { country = "DE", currency = "EUR" }
+eps = { country = "AT", currency = "EUR" }
+sofort = { not_available_flows = { capture_method = "manual" }, country = "AT,BE,DE,ES,CH,NL", currency = "CHF,EUR" }
+ideal = { not_available_flows = { capture_method = "manual" }, country = "NL", currency = "EUR" }
+blik = { country = "PL", currency = "PLN" }
+trustly = { country = "ES,GB,SE,NO,AT,NL,DE,DK,FI,EE,LT,LV", currency = "CZK,DKK,EUR,GBP,NOK,SEK" }
+online_banking_czech_republic = { country = "CZ", currency = "EUR,CZK" }
+online_banking_finland = { country = "FI", currency = "EUR" }
+online_banking_poland = { country = "PL", currency = "PLN" }
+online_banking_slovakia = { country = "SK", currency = "EUR,CZK" }
+bancontact_card = { country = "BE", currency = "EUR" }
+ach = { country = "US", currency = "USD" }
+bacs = { country = "GB", currency = "GBP" }
+sepa = { country = "ES,SK,AT,NL,DE,BE,FR,FI,PT,IE,EE,LT,LV,IT", currency = "EUR" }
+ali_pay_hk = { country = "HK", currency = "HKD" }
+bizum = { country = "ES", currency = "EUR" }
+go_pay = { country = "ID", currency = "IDR" }
+kakao_pay = { country = "KR", currency = "KRW" }
+momo = { country = "VN", currency = "VND" }
+gcash = { country = "PH", currency = "PHP" }
+online_banking_fpx = { country = "MY", currency = "MYR" }
+online_banking_thailand = { country = "TH", currency = "THB" }
+touch_n_go = { country = "MY", currency = "MYR" }
+atome = { country = "MY,SG", currency = "MYR,SGD" }
+swish = { country = "SE", currency = "SEK" }
+permata_bank_transfer = { country = "ID", currency = "IDR" }
+bca_bank_transfer = { country = "ID", currency = "IDR" }
+bni_va = { country = "ID", currency = "IDR" }
+bri_va = { country = "ID", currency = "IDR" }
+cimb_va = { country = "ID", currency = "IDR" }
+danamon_va = { country = "ID", currency = "IDR" }
+mandiri_va = { country = "ID", currency = "IDR" }
+alfamart = { country = "ID", currency = "IDR" }
+indomaret = { country = "ID", currency = "IDR" }
+open_banking_uk = { country = "GB", currency = "GBP" }
+oxxo = { country = "MX", currency = "MXN" }
+pay_safe_card = { country = "AT,AU,BE,BR,BE,CA,HR,CY,CZ,DK,FI,FR,GE,DE,GI,HU,IS,IE,KW,LV,IE,LI,LT,LU,MT,MX,MD,ME,NL,NZ,NO,PY,PE,PL,PT,RO,SA,RS,SK,SI,ES,SE,CH,TR,AE,GB,US,UY", currency = "EUR,AUD,BRL,CAD,CZK,DKK,GEL,GIP,HUF,KWD,CHF,MXN,MDL,NZD,NOK,PYG,PEN,PLN,RON,SAR,RSD,SEK,TRY,AED,GBP,USD,UYU" }
+seven_eleven = { country = "JP", currency = "JPY" }
+lawson = { country = "JP", currency = "JPY" }
+mini_stop = { country = "JP", currency = "JPY" }
+family_mart = { country = "JP", currency = "JPY" }
+seicomart = { country = "JP", currency = "JPY" }
+pay_easy = { country = "JP", currency = "JPY" }
+pix = { country = "BR", currency = "BRL" }
+boleto = { country = "BR", currency = "BRL" }
+
+[pm_filters.affirm]
+affirm = { country = "CA,US", currency = "CAD,USD" }
+
+[pm_filters.airwallex]
+credit = { country = "AU,HK,SG,NZ,US", currency = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BYN,BZD,CAD,CDF,CHF,CLP,CNY,COP,CRC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLE,SLL,SOS,SRD,SSP,STN,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL" }
+debit = { country = "AU,HK,SG,NZ,US", currency = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BYN,BZD,CAD,CDF,CHF,CLP,CNY,COP,CRC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLE,SLL,SOS,SRD,SSP,STN,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL" }
+google_pay = { country = "AL, DZ, AS, AO, AG, AR, AU, AZ, BH, BR, BG, CA, CL, CO, CZ, DK, DO, EG, HK, HU, ID, IL, JP, JO, KZ, KE, KW, LB, MY, MX, OM, PK, PA, PE, PH, PL, QA, RO, SA, SG, ZA, LK, SE, TW, TH, TR, UA, AE, UY, VN, AT, BE, HR, EE, FI, FR, DE, GR, IE, IT, LV, LT, LU, NL, PL, PT, SK, ES, SE, RO, BG", currency = "ALL, DZD, USD, AOA, XCD, ARS, AUD, EUR, AZN, BHD, BRL, BGN, CAD, CLP, COP, CZK, DKK, DOP, EGP, HKD, HUF, INR, IDR, ILS, JPY, JOD, KZT, KES, KWD, LBP, MYR, MXN, NZD, NOK, OMR, PKR, PAB, PEN, PHP, PLN, QAR, RON, SAR, SGD, ZAR, LKR, SEK, CHF, TWD, THB, TRY, UAH, AED, GBP, UYU, VND" }
+paypal = { currency = "AUD,BRL,CAD,CZK,DKK,EUR,HKD,HUF,JPY,MYR,MXN,NOK,NZD,PHP,PLN,GBP,RUB,SGD,SEK,CHF,THB,USD" }
+klarna = { currency = "EUR, DKK, NOK, PLN, SEK, CHF, GBP, USD, CZK" }
+trustly = {currency="DKK, EUR, GBP, NOK, PLN, SEK" }
+blik = { country="PL" , currency = "PLN" }
+ideal = { country="NL" , currency = "EUR" }
+atome = { country = "SG, MY" , currency = "SGD, MYR" }
+skrill = { country="AL, DZ, AD, AR, AM, AW, AU, AT, AZ, BS, BD, BE, BJ, BO, BA, BW, BR, BN, BG, KH, CM, CA, CL, CN, CX, CO, CR , HR, CW, CY, CZ, DK, DM, DO, EC, EG, EE , FK, FI, GE, DE, GH, GI, GR, GP, GU, GT, GG, HK, HU, IS, IN, ID , IQ, IE, IM, IL, IT, JE , KZ, KE , KR, KW, KG, LV , LS, LI, LT, LU , MK, MG, MY, MV, MT, MU, YT, MX, MD, MC, MN, ME, MA, NA, NP, NZ, NI, NE, NO, PK , PA, PY, PE, PH, PL, PT, PR, QA, RO , SM , SA, SN , SG, SX, SK, SI, ZA, SS, ES, LK, SE, CH, TW, TZ, TH, TN, AE, GB, UM, UY, VN, VG, VI, US" , currency = "EUR, GBP, USD" }
+indonesian_bank_transfer = { country="ID" , currency = "IDR" }
+
+[pm_filters.elavon]
+credit = { country = "US", currency = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BYN,BZD,CAD,CDF,CHF,CLP,CNY,COP,CRC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLE,SLL,SOS,SRD,SSP,STN,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL" }
+debit = { country = "US", currency = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BYN,BZD,CAD,CDF,CHF,CLP,CNY,COP,CRC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLE,SLL,SOS,SRD,SSP,STN,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL" }
+
+[pm_filters.xendit]
+credit = { country = "ID,PH", currency = "IDR,PHP,USD,SGD,MYR" }
+debit = { country = "ID,PH", currency = "IDR,PHP,USD,SGD,MYR" }
+qris = {currency = "IDR" }
+
+[pm_filters.tsys]
+credit = { country = "NA", currency = "AED, AFN, ALL, AMD, ANG, AOA, ARS, AUD, AWG, AZN, BAM, BBD, BDT, BGN, BHD, BIF, BMD, BND, BOB, BRL, BSD, BTN, BWP, BZD, CAD, CDF, CHF, CLP, CNY, COP, CRC, CUP, CVE, CZK, DJF, DKK, DOP, DZD, EGP, ERN, ETB, EUR, FJD, FKP, GBP, GEL, GHS, GIP, GMD, GNF, GTQ, GYD, HKD, HNL, HRK, HTG, HUF, IDR, ILS, INR, IQD, IRR, ISK, JMD, JOD, JPY, KES, KGS, KHR, KMF, KRW, KWD, KYD, KZT, LAK, LBP, LKR, LRD, LSL, LYD, MAD, MDL, MGA, MKD, MMK, MNT, MOP, MUR, MVR, MWK, MXN, MYR, MZN, NAD, NGN, NIO, NOK, NPR, NZD, OMR, PAB, PEN, PGK, PHP, PKR, PLN, PYG, QAR, RON, RSD, RUB, RWF, SAR, SBD, SCR, SDG, SEK, SGD, SHP, SLE, SOS, SRD, SSP, SVC, SYP, SZL, THB, TJS, TMT, TND, TOP, TRY, TTD, TWD, TZS, UAH, UGX, USD, UYU, UZS, VND, VUV, WST, XAF, XCD, XOF, XPF, YER, ZAR, ZMW, ZWL, BYN, KPW, STN, MRU, VES" }
+debit = { country = "NA", currency = "AED, AFN, ALL, AMD, ANG, AOA, ARS, AUD, AWG, AZN, BAM, BBD, BDT, BGN, BHD, BIF, BMD, BND, BOB, BRL, BSD, BTN, BWP, BZD, CAD, CDF, CHF, CLP, CNY, COP, CRC, CUP, CVE, CZK, DJF, DKK, DOP, DZD, EGP, ERN, ETB, EUR, FJD, FKP, GBP, GEL, GHS, GIP, GMD, GNF, GTQ, GYD, HKD, HNL, HRK, HTG, HUF, IDR, ILS, INR, IQD, IRR, ISK, JMD, JOD, JPY, KES, KGS, KHR, KMF, KRW, KWD, KYD, KZT, LAK, LBP, LKR, LRD, LSL, LYD, MAD, MDL, MGA, MKD, MMK, MNT, MOP, MUR, MVR, MWK, MXN, MYR, MZN, NAD, NGN, NIO, NOK, NPR, NZD, OMR, PAB, PEN, PGK, PHP, PKR, PLN, PYG, QAR, RON, RSD, RUB, RWF, SAR, SBD, SCR, SDG, SEK, SGD, SHP, SLE, SOS, SRD, SSP, SVC, SYP, SZL, THB, TJS, TMT, TND, TOP, TRY, TTD, TWD, TZS, UAH, UGX, USD, UYU, UZS, VND, VUV, WST, XAF, XCD, XOF, XPF, YER, ZAR, ZMW, ZWL, BYN, KPW, STN, MRU, VES" }
+
+[pm_filters.billwerk]
+credit = { country = "DE, DK, FR, SE", currency = "DKK, NOK" }
+debit = { country = "DE, DK, FR, SE", currency = "DKK, NOK" }
+
+[pm_filters.fiservemea]
+credit = { country = "DE, FR, IT, NL, PL, ES, ZA, GB, AE", currency = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BYN,BZD,CAD,CDF,CHF,CLP,CNY,COP,CRC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLE,SLL,SOS,SRD,SSP,STN,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL" }
+debit = { country = "DE, FR, IT, NL, PL, ES, ZA, GB, AE", currency = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BYN,BZD,CAD,CDF,CHF,CLP,CNY,COP,CRC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLE,SLL,SOS,SRD,SSP,STN,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL" }
+
+[pm_filters.getnet]
+credit = { country = "AR, BR, CL, MX, UY, ES, PT, DE, IT, FR, NL, BE, AT, PL, CH, GB, IE, LU, DK, SE, NO, FI, IN, AE", currency = "ARS, BRL, CLP, MXN, UYU, EUR, PLN, CHF, GBP, DKK, SEK, NOK, INR, AED" }
+
+[pm_filters.hipay]
+credit = { country = "GB, CH, SE, DK, NO, PL, CZ, US, CA, JP, HK, AU, ZA", currency = "EUR, GBP, CHF, SEK, DKK, NOK, PLN, CZK, USD, CAD, JPY, HKD, AUD, ZAR" }
+debit = { country = "GB, CH, SE, DK, NO, PL, CZ, US, CA, JP, HK, AU, ZA", currency = "EUR, GBP, CHF, SEK, DKK, NOK, PLN, CZK, USD, CAD, JPY, HKD, AUD, ZAR" }
+
+[pm_filters.moneris]
+credit = { country = "AE, AF, AL, AO, AR, AT, AU, AW, AZ, BA, BB, BD, BE, BG, BH, BI, BM, BN, BO, BR, BT, BY, BZ, CH, CL, CN, CO, CR, CU, CV, CY, CZ, DE, DJ, DK, DO, DZ, EE, EG, ES, FI, FJ, FR, GB, GE, GI, GM, GN, GR, GT, GY, HK, HN, HR, HT, HU, ID, IE, IL, IN, IS, IT, JM, JO, JP, KE, KM, KR, KW, KY, KZ, LA, LK, LR, LS, LV, LT, LU, MA, MD, MG, MK, MO, MR, MT, MU, MV, MW, MX, MY, MZ, NA, NG, NI, NL, NO, NP, NZ, OM, PE, PG, PK, PL, PT, PY, QA, RO, RS, RU, RW, SA, SB, SC, SE, SG, SH, SI, SK, SL, SR, SV, SZ, TH, TJ, TM, TN, TR, TT, TW, TZ, UG, US, UY, UZ, VN, VU, WS, ZA, ZM", currency = "AED, AFN, ALL, ANG, AOA, ARS, AUD, AWG, AZN, BAM, BBD, BDT, BGN, BHD, BIF, BMD, BND, BOB, BRL, BTN, BYN, BZD, CHF, CLP, CNY, COP, CRC, CUP, CVE, CZK, DJF, DKK, DOP, DZD, EGP, EUR, FJD, GBP, GEL, GIP, GMD, GNF, GTQ, GYD, HKD, HNL, HRK, HTG, HUF, IDR, ILS, INR, ISK, JMD, JOD, JPY, KES, KMF, KRW, KWD, KYD, KZT, LAK, LKR, LRD, LSL, MAD, MDL, MGA, MKD, MOP, MRU, MUR, MVR, MWK, MXN, MYR, MZN, NAD, NGN, NIO, NOK, NPR, NZD, OMR, PEN, PGK, PHP, PKR, PLN, PYG, QAR, RON, RSD, RUB, RWF, SAR, SBD, SCR, SEK, SGD, SHP, SLL, SRD, SVC, SZL, THB, TJS, TMT, TND, TRY, TTD, TWD, TZS, UGX, USD, UYU, UZS, VND, VUV, WST, XCD, XOF, XPF, ZAR, ZMW" }
+debit = { country = "AE, AF, AL, AO, AR, AT, AU, AW, AZ, BA, BB, BD, BE, BG, BH, BI, BM, BN, BO, BR, BT, BY, BZ, CH, CL, CN, CO, CR, CU, CV, CY, CZ, DE, DJ, DK, DO, DZ, EE, EG, ES, FI, FJ, FR, GB, GE, GI, GM, GN, GR, GT, GY, HK, HN, HR, HT, HU, ID, IE, IL, IN, IS, IT, JM, JO, JP, KE, KM, KR, KW, KY, KZ, LA, LK, LR, LS, LV, LT, LU, MA, MD, MG, MK, MO, MR, MT, MU, MV, MW, MX, MY, MZ, NA, NG, NI, NL, NO, NP, NZ, OM, PE, PG, PK, PL, PT, PY, QA, RO, RS, RU, RW, SA, SB, SC, SE, SG, SH, SI, SK, SL, SR, SV, SZ, TH, TJ, TM, TN, TR, TT, TW, TZ, UG, US, UY, UZ, VN, VU, WS, ZA, ZM", currency = "AED, AFN, ALL, ANG, AOA, ARS, AUD, AWG, AZN, BAM, BBD, BDT, BGN, BHD, BIF, BMD, BND, BOB, BRL, BTN, BYN, BZD, CHF, CLP, CNY, COP, CRC, CUP, CVE, CZK, DJF, DKK, DOP, DZD, EGP, EUR, FJD, GBP, GEL, GIP, GMD, GNF, GTQ, GYD, HKD, HNL, HRK, HTG, HUF, IDR, ILS, INR, ISK, JMD, JOD, JPY, KES, KMF, KRW, KWD, KYD, KZT, LAK, LKR, LRD, LSL, MAD, MDL, MGA, MKD, MOP, MRU, MUR, MVR, MWK, MXN, MYR, MZN, NAD, NGN, NIO, NOK, NPR, NZD, OMR, PEN, PGK, PHP, PKR, PLN, PYG, QAR, RON, RSD, RUB, RWF, SAR, SBD, SCR, SEK, SGD, SHP, SLL, SRD, SVC, SZL, THB, TJS, TMT, TND, TRY, TTD, TWD, TZS, UGX, USD, UYU, UZS, VND, VUV, WST, XCD, XOF, XPF, ZAR, ZMW" }
+
+[pm_filters.opennode]
+crypto_currency = { country = "US, CA, GB, AU, BR, MX, SG, PH, NZ, ZA, JP, AT, BE, HR, CY, EE, FI, FR, DE, GR, IE, IT, LV, LT, LU, MT, NL, PT, SK, SI, ES", currency = "USD, CAD, GBP, AUD, BRL, MXN, SGD, PHP, NZD, ZAR, JPY, EUR" }
+
+[pm_filters.bambora]
+credit = { country = "US,CA", currency = "USD" }
+debit = { country = "US,CA", currency = "USD" }
+
+[pm_filters.bankofamerica]
+credit = { country = "AF,AL,DZ,AD,AO,AI,AG,AR,AM,AW,AU,AT,AZ,BS,BH,BD,BB,BY,BE,BZ,BJ,BM,BT,BO,BA,BW,BN,BG,BF,BI,KH,CM,CA,CV,KY,CF,TD,CL,CN,CO,KM,CD,CG,CK,CR,HR,CU,CW,CY,CZ,DK,DJ,DM,DO,EC,SV,GQ,ER,EE,ET,FK,FO,FJ,FI,FR,GF,PF,TF,GA,GM,GE,DE,GH,GI,GR,GL,GD,GP,GU,GT,GG,GN,GW,GY,HT,HM,VA,HN,HK,HU,IS,ID,IR,IQ,IE,IM,IL,IT,JM,JP,JE,JO,KZ,KE,KI,KR,KW,KG,LA,LV,LB,LS,LR,LY,LI,LT,LU,MO,MG,MW,MY,MV,ML,MT,MH,MR,MU,MX,FM,MD,MC,MN,ME,MS,MA,MZ,MM,NA,NR,NP,NL,NC,NZ,NI,NE,NG,NU,NO,OM,PK,PW,PS,PA,PG,PY,PE,PH,PL,PT,PR,QA,CG,RO,RW,KN,LC,VC,WS,SM,ST,SA,SN,RS,SC,SL,SG,SX,SK,SI,SO,ZA,GS,ES,LK,SR,SJ,SZ,SE,CH,TW,TJ,TZ,TH,TL,TG,TO,TT,TN,TR,TM,TC,TV,UG,UA,AE,GB,US,UY,UZ,VU,VE,VN,VG,WF,YE,ZM,ZW", currency = "USD" }
+debit = { country = "AF,AL,DZ,AD,AO,AI,AG,AR,AM,AW,AU,AT,AZ,BS,BH,BD,BB,BY,BE,BZ,BJ,BM,BT,BO,BA,BW,BN,BG,BF,BI,KH,CM,CA,CV,KY,CF,TD,CL,CN,CO,KM,CD,CG,CK,CR,HR,CU,CW,CY,CZ,DK,DJ,DM,DO,EC,SV,GQ,ER,EE,ET,FK,FO,FJ,FI,FR,GF,PF,TF,GA,GM,GE,DE,GH,GI,GR,GL,GD,GP,GU,GT,GG,GN,GW,GY,HT,HM,VA,HN,HK,HU,IS,ID,IR,IQ,IE,IM,IL,IT,JM,JP,JE,JO,KZ,KE,KI,KR,KW,KG,LA,LV,LB,LS,LR,LY,LI,LT,LU,MO,MG,MW,MY,MV,ML,MT,MH,MR,MU,MX,FM,MD,MC,MN,ME,MS,MA,MZ,MM,NA,NR,NP,NL,NC,NZ,NI,NE,NG,NU,NO,OM,PK,PW,PS,PA,PG,PY,PE,PH,PL,PT,PR,QA,CG,RO,RW,KN,LC,VC,WS,SM,ST,SA,SN,RS,SC,SL,SG,SX,SK,SI,SO,ZA,GS,ES,LK,SR,SJ,SZ,SE,CH,TW,TJ,TZ,TH,TL,TG,TO,TT,TN,TR,TM,TC,TV,UG,UA,AE,GB,US,UY,UZ,VU,VE,VN,VG,WF,YE,ZM,ZW", currency = "USD" }
+apple_pay = { country = "AU,AT,BH,BE,BR,BG,CA,CL,CN,CO,CR,HR,CY,CZ,DK,DO,EC,EE,SV,FI,FR,DE,GR,GT,HN,HK,HU,IS,IN,IE,IL,IT,JP,JO,KZ,KW,LV,LI,LT,LU,MY,MT,MX,MC,ME,NL,NZ,NO,OM,PA,PY,PE,PL,PT,QA,RO,SA,SG,SK,SI,ZA,KR,ES,SE,CH,TW,AE,GB,US,UY,VN,VA", currency = "USD" }
+google_pay = { country = "AU,AT,BE,BR,CA,CL,CO,CR,CY,CZ,DK,DO,EC,EE,SV,FI,FR,DE,GR,GT,HN,HK,HU,IS,IN,IE,IL,IT,JP,JO,KZ,KW,LV,LI,LT,LU,MY,MT,MX,NL,NZ,NO,OM,PA,PY,PE,PL,PT,QA,RO,SA,SG,SK,SI,ZA,KR,ES,SE,CH,TW,AE,GB,US,UY,VN,VA", currency = "USD" }
+samsung_pay = { country = "AU,BH,BR,CA,CN,DK,FI,FR,DE,HK,IN,IT,JP,KZ,KR,KW,MY,NZ,NO,OM,QA,SA,SG,ZA,ES,SE,CH,TW,AE,GB,US", currency = "USD" }
+
+[pm_filters.cybersource]
+credit = { currency = "USD,GBP,EUR,PLN,SEK,XOF,CAD,KWD,QAR" }
+debit = { currency = "USD,GBP,EUR,PLN,SEK,XOF,CAD,KWD,QAR" }
+apple_pay = { currency = "ARS, CAD, CLP, COP, CNY, EUR, HKD, KWD, MYR, MXN, NZD, PEN, QAR, SAR, SGD, ZAR, UAH, GBP, AED, USD, PLN, SEK" }
+google_pay = { currency = "ARS, AUD, CAD, CLP, COP, EUR, HKD, INR, KWD, MYR, MXN, NZD, PEN, QAR, SAR, SGD, ZAR, UAH, AED, GBP, USD, PLN, SEK" }
+samsung_pay = { currency = "USD,GBP,EUR,SEK" }
+paze = { currency = "USD,SEK" }
+
+[pm_filters.barclaycard]
+credit = { currency = "USD,GBP,EUR,PLN,SEK" }
+debit = { currency = "USD,GBP,EUR,PLN,SEK" }
+google_pay = { currency = "ARS, AUD, CAD, CLP, COP, EUR, HKD, INR, KWD, MYR, MXN, NZD, PEN, QAR, SAR, SGD, ZAR, UAH, AED, GBP, USD, PLN, SEK" }
+apple_pay = { currency = "ARS, CAD, CLP, COP, CNY, EUR, HKD, KWD, MYR, MXN, NZD, PEN, QAR, SAR, SGD, ZAR, UAH, GBP, AED, USD, PLN, SEK" }
+
+
+[pm_filters.globepay]
+ali_pay = { country = "GB",currency = "GBP,CNY" }
+we_chat_pay = { country = "GB",currency = "GBP,CNY" }
+
+
+[pm_filters.itaubank]
+pix = { country = "BR", currency = "BRL" }
+
+[pm_filters.nexinets]
+credit = { country = "DE",currency = "EUR" }
+debit = { country = "DE",currency = "EUR" }
+ideal = { country = "DE",currency = "EUR" }
+giropay = { country = "DE",currency = "EUR" }
+sofort = { country = "DE",currency = "EUR" }
+eps = { country = "DE",currency = "EUR" }
+apple_pay = { country = "DE",currency = "EUR" }
+paypal = { country = "DE",currency = "EUR" }
+
+
+[pm_filters.nuvei]
+credit = { country = "AF,AX,AL,DZ,AS,AD,AO,AI,AQ,AG,AR,AM,AW,AU,AT,AZ,BS,BH,BD,BB,BY,BE,BZ,BJ,BM,BT,BO,BQ,BA,BW,BV,BR,IO,BN,BG,BF,BI,KH,CM,CA,CV,KY,CF,TD,CL,CN,CX,CC,CO,KM,CG,CD,CK,CR,CI,HR,CU,CW,CY,CZ,DK,DJ,DM,DO,EC,EG,SV,GQ,ER,EE,ET,FK,FO,FJ,FI,FR,GF,PF,TF,GA,GM,GE,DE,GH,GI,GR,GL,GD,GP,GU,GT,GG,GN,GW,GY,HT,HM,VA,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IM,IL,IT,JM,JP,JE,JO,KZ,KE,KI,KP,KR,KW,KG,LA,LV,LB,LS,LR,LY,LI,LT,LU,MO,MK,MG,MW,MY,MV,ML,MT,MH,MQ,MR,MU,YT,MX,FM,MD,MC,MN,ME,MS,MA,MZ,MM,NA,NR,NP,NL,NC,NZ,NI,NE,NG,NU,NF,MP,NO,OM,PK,PW,PS,PA,PG,PY,PE,PH,PN,PL,PT,PR,QA,RE,RO,RU,RW,BL,SH,KN,LC,MF,PM,VC,WS,SM,ST,SA,SN,RS,SC,SL,SG,SX,SK,SI,SB,SO,ZA,GS,SS,ES,LK,SD,SR,SJ,SZ,SE,CH,SY,TW,TJ,TZ,TH,TL,TG,TK,TO,TT,TN,TR,TM,TC,TV,UG,UA,AE,GB,UM,UY,UZ,VU,VE,VN,VG,VI,WF,EH,YE,ZM,ZW,US",currency = "AED,ALL,AMD,ARS,AUD,AZN,BAM,BDT,BGN,BHD,BMD,BND,BRL,BYN,CAD,CHF,CLP,CNY,COP,CRC,CZK,DKK,DOP,DZD,EGP,EUR,GBP,GEL,GHS,GTQ,HKD,HUF,IDR,INR,IQD,ISK,JOD,JPY,KES,KGS,KRW,KWD,KYD,KZT,LBP,LKR,MAD,MDL,MKD,MMK,MNT,MUR,MWK,MXN,MYR,MZN,NAD,NGN,NOK,NZD,OMR,PEN,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,SAR,SEK,SGD,SOS,THB,TND,TOP,TRY,TTD,TWD,UAH,UGX,USD,UYU,UZS,VND,XAF,XOF,YER,ZAR" }
+debit = { country = "AF,AX,AL,DZ,AS,AD,AO,AI,AQ,AG,AR,AM,AW,AU,AT,AZ,BS,BH,BD,BB,BY,BE,BZ,BJ,BM,BT,BO,BQ,BA,BW,BV,BR,IO,BN,BG,BF,BI,KH,CM,CA,CV,KY,CF,TD,CL,CN,CX,CC,CO,KM,CG,CD,CK,CR,CI,HR,CU,CW,CY,CZ,DK,DJ,DM,DO,EC,EG,SV,GQ,ER,EE,ET,FK,FO,FJ,FI,FR,GF,PF,TF,GA,GM,GE,DE,GH,GI,GR,GL,GD,GP,GU,GT,GG,GN,GW,GY,HT,HM,VA,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IM,IL,IT,JM,JP,JE,JO,KZ,KE,KI,KP,KR,KW,KG,LA,LV,LB,LS,LR,LY,LI,LT,LU,MO,MK,MG,MW,MY,MV,ML,MT,MH,MQ,MR,MU,YT,MX,FM,MD,MC,MN,ME,MS,MA,MZ,MM,NA,NR,NP,NL,NC,NZ,NI,NE,NG,NU,NF,MP,NO,OM,PK,PW,PS,PA,PG,PY,PE,PH,PN,PL,PT,PR,QA,RE,RO,RU,RW,BL,SH,KN,LC,MF,PM,VC,WS,SM,ST,SA,SN,RS,SC,SL,SG,SX,SK,SI,SB,SO,ZA,GS,SS,ES,LK,SD,SR,SJ,SZ,SE,CH,SY,TW,TJ,TZ,TH,TL,TG,TK,TO,TT,TN,TR,TM,TC,TV,UG,UA,AE,GB,UM,UY,UZ,VU,VE,VN,VG,VI,WF,EH,YE,ZM,ZW,US",currency = "AED,ALL,AMD,ARS,AUD,AZN,BAM,BDT,BGN,BHD,BMD,BND,BRL,BYN,CAD,CHF,CLP,CNY,COP,CRC,CZK,DKK,DOP,DZD,EGP,EUR,GBP,GEL,GHS,GTQ,HKD,HUF,IDR,INR,IQD,ISK,JOD,JPY,KES,KGS,KRW,KWD,KYD,KZT,LBP,LKR,MAD,MDL,MKD,MMK,MNT,MUR,MWK,MXN,MYR,MZN,NAD,NGN,NOK,NZD,OMR,PEN,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,SAR,SEK,SGD,SOS,THB,TND,TOP,TRY,TTD,TWD,UAH,UGX,USD,UYU,UZS,VND,XAF,XOF,YER,ZAR" }
+klarna = { country = "AU,CA,GB,IN,JP,NZ,PH,SG,TH,US",currency = "AED,ALL,AMD,ARS,AUD,AZN,BAM,BDT,BGN,BHD,BMD,BND,BRL,BYN,CAD,CHF,CLP,CNY,COP,CRC,CZK,DKK,DOP,DZD,EGP,EUR,GBP,GEL,GHS,GTQ,HKD,HUF,IDR,INR,IQD,ISK,JOD,JPY,KES,KGS,KRW,KWD,KYD,KZT,LBP,LKR,MAD,MDL,MKD,MMK,MNT,MUR,MWK,MXN,MYR,MZN,NAD,NGN,NOK,NZD,OMR,PEN,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,SAR,SEK,SGD,SOS,THB,TND,TOP,TRY,TTD,TWD,UAH,UGX,USD,UYU,UZS,VND,XAF,XOF,YER,ZAR" }
+afterpay_clearpay = { country = "AU,CA,GB,IN,JP,NZ,PH,SG,TH,US",currency = "AED,ALL,AMD,ARS,AUD,AZN,BAM,BDT,BGN,BHD,BMD,BND,BRL,BYN,CAD,CHF,CLP,CNY,COP,CRC,CZK,DKK,DOP,DZD,EGP,EUR,GBP,GEL,GHS,GTQ,HKD,HUF,IDR,INR,IQD,ISK,JOD,JPY,KES,KGS,KRW,KWD,KYD,KZT,LBP,LKR,MAD,MDL,MKD,MMK,MNT,MUR,MWK,MXN,MYR,MZN,NAD,NGN,NOK,NZD,OMR,PEN,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,SAR,SEK,SGD,SOS,THB,TND,TOP,TRY,TTD,TWD,UAH,UGX,USD,UYU,UZS,VND,XAF,XOF,YER,ZAR" }
+giropay = { currency = "EUR" }
+ideal = { currency = "EUR" }
+sofort = { country = "AU,CA,GB,IN,JP,NZ,PH,SG,TH,US",currency = "AED,ALL,AMD,ARS,AUD,AZN,BAM,BDT,BGN,BHD,BMD,BND,BRL,BYN,CAD,CHF,CLP,CNY,COP,CRC,CZK,DKK,DOP,DZD,EGP,EUR,GBP,GEL,GHS,GTQ,HKD,HUF,IDR,INR,IQD,ISK,JOD,JPY,KES,KGS,KRW,KWD,KYD,KZT,LBP,LKR,MAD,MDL,MKD,MMK,MNT,MUR,MWK,MXN,MYR,MZN,NAD,NGN,NOK,NZD,OMR,PEN,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,SAR,SEK,SGD,SOS,THB,TND,TOP,TRY,TTD,TWD,UAH,UGX,USD,UYU,UZS,VND,XAF,XOF,YER,ZAR" }
+eps = { country = "AU,CA,GB,IN,JP,NZ,PH,SG,TH,US",currency = "AED,ALL,AMD,ARS,AUD,AZN,BAM,BDT,BGN,BHD,BMD,BND,BRL,BYN,CAD,CHF,CLP,CNY,COP,CRC,CZK,DKK,DOP,DZD,EGP,EUR,GBP,GEL,GHS,GTQ,HKD,HUF,IDR,INR,IQD,ISK,JOD,JPY,KES,KGS,KRW,KWD,KYD,KZT,LBP,LKR,MAD,MDL,MKD,MMK,MNT,MUR,MWK,MXN,MYR,MZN,NAD,NGN,NOK,NZD,OMR,PEN,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,SAR,SEK,SGD,SOS,THB,TND,TOP,TRY,TTD,TWD,UAH,UGX,USD,UYU,UZS,VND,XAF,XOF,YER,ZAR" }
+apple_pay = { country = "AU,AT,BY,BE,BR,BG,CA,CN,HR,CY,CZ,DK,EE,FO,FI,FR,GE,DE,GR,GL,GG,HK,HU,IS,IE,IM,IL,IT,JP,JE,KZ,LV,LI,LT,LU,MO,MT,MC,NL,NZ,NO,PL,PT,RO,RU,SM,SA,SG,SK,SI,ES,SE,CH,TW,UA,AE,GB,US,VA",currency = "AED,ALL,AMD,ARS,AUD,AZN,BAM,BDT,BGN,BHD,BMD,BND,BRL,BYN,CAD,CHF,CLP,CNY,COP,CRC,CZK,DKK,DOP,DZD,EGP,EUR,GBP,GEL,GHS,GTQ,HKD,HUF,IDR,INR,IQD,ISK,JOD,JPY,KES,KGS,KRW,KWD,KYD,KZT,LBP,LKR,MAD,MDL,MKD,MMK,MNT,MUR,MWK,MXN,MYR,MZN,NAD,NGN,NOK,NZD,OMR,PEN,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,SAR,SEK,SGD,SOS,THB,TND,TOP,TRY,TTD,TWD,UAH,UGX,USD,UYU,UZS,VND,XAF,XOF,YER,ZAR" }
+google_pay = { country = "AF,AX,AL,DZ,AD,AO,AI,AQ,AG,AR,AM,AW,AU,AT,AZ,BS,BH,BD,BB,BY,BE,BZ,BJ,BM,BT,BO,BQ,BA,BW,BV,BR,IO,BN,BG,BF,KH,CM,CA,CV,KY,CF,TD,CL,CN,TW,CX,CC,CO,KM,CG,CK,CR,CI,HR,CW,CY,CZ,DK,DJ,DM,DO,EC,EG,SV,GQ,ER,EE,ET,FK,FO,FJ,FI,FR,GF,PF,TF,GA,GM,GE,DE,GH,GI,GR,GL,GD,GP,GU,GT,GG,GN,GW,GY,HT,HM,HN,HK,HU,IS,IN,ID,IQ,IE,IM,IL,IT,JM,JP,JE,JO,KZ,KE,KI,KW,KG,LA,LV,LB,LS,LR,LY,LI,LT,LU,MO,MK,MG,MW,MY,MV,ML,MT,MH,MQ,MR,MU,YT,MX,FM,MD,MC,MN,ME,MS,MA,MZ,MM,NA,NR,NP,NL,NC,NZ,NI,NE,NG,NU,NF,MP,NO,OM,PK,PW,PS,PA,PG,PY,PE,PH,PN,PL,PT,PR,QA,RE,RO,RU,RW,BL,SH,KN,LC,MF,PM,VI,VC,WS,SM,ST,SA,SN,RS,SC,SL,SG,SK,SI,SB,SO,ZA,GS,KR,ES,LK,SR,SJ,SZ,SE,CH,TW,TJ,TZ,TH,TL,TG,TK,TO,TT,TN,TR,TM,TC,TV,UG,UA,AE,GB,UY,UZ,VU,VA,VE,VN,VI,WF,EH,YE,ZM,ZW,US",currency = "AED,ALL,AMD,ARS,AUD,AZN,BAM,BDT,BGN,BHD,BMD,BND,BRL,BYN,CAD,CHF,CLP,CNY,COP,CRC,CZK,DKK,DOP,DZD,EGP,EUR,GBP,GEL,GHS,GTQ,HKD,HUF,IDR,INR,IQD,ISK,JOD,JPY,KES,KGS,KRW,KWD,KYD,KZT,LBP,LKR,MAD,MDL,MKD,MMK,MNT,MUR,MWK,MXN,MYR,MZN,NAD,NGN,NOK,NZD,OMR,PEN,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,SAR,SEK,SGD,SOS,THB,TND,TOP,TRY,TTD,TWD,UAH,UGX,USD,UYU,UZS,VND,XAF,XOF,YER,ZAR" }
+paypal = { country = "AU,CA,GB,IN,JP,NZ,PH,SG,TH,US",currency = "AED,ALL,AMD,ARS,AUD,AZN,BAM,BDT,BGN,BHD,BMD,BND,BRL,BYN,CAD,CHF,CLP,CNY,COP,CRC,CZK,DKK,DOP,DZD,EGP,EUR,GBP,GEL,GHS,GTQ,HKD,HUF,IDR,INR,IQD,ISK,JOD,JPY,KES,KGS,KRW,KWD,KYD,KZT,LBP,LKR,MAD,MDL,MKD,MMK,MNT,MUR,MWK,MXN,MYR,MZN,NAD,NGN,NOK,NZD,OMR,PEN,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,SAR,SEK,SGD,SOS,THB,TND,TOP,TRY,TTD,TWD,UAH,UGX,USD,UYU,UZS,VND,XAF,XOF,YER,ZAR" }
+
+[payout_method_filters.nuvei]
+credit = { country = "AF,AX,AL,DZ,AS,AD,AO,AI,AQ,AG,AR,AM,AW,AU,AT,AZ,BS,BH,BD,BB,BY,BE,BZ,BJ,BM,BT,BO,BQ,BA,BW,BV,BR,IO,BN,BG,BF,BI,KH,CM,CA,CV,KY,CF,TD,CL,CN,CX,CC,CO,KM,CG,CD,CK,CR,CI,HR,CU,CW,CY,CZ,DK,DJ,DM,DO,EC,EG,SV,GQ,ER,EE,ET,FK,FO,FJ,FI,FR,GF,PF,TF,GA,GM,GE,DE,GH,GI,GR,GL,GD,GP,GU,GT,GG,GN,GW,GY,HT,HM,VA,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IM,IL,IT,JM,JP,JE,JO,KZ,KE,KI,KP,KR,KW,KG,LA,LV,LB,LS,LR,LY,LI,LT,LU,MO,MK,MG,MW,MY,MV,ML,MT,MH,MQ,MR,MU,YT,MX,FM,MD,MC,MN,ME,MS,MA,MZ,MM,NA,NR,NP,NL,NC,NZ,NI,NE,NG,NU,NF,MP,NO,OM,PK,PW,PS,PA,PG,PY,PE,PH,PN,PL,PT,PR,QA,RE,RO,RU,RW,BL,SH,KN,LC,MF,PM,VC,WS,SM,ST,SA,SN,RS,SC,SL,SG,SX,SK,SI,SB,SO,ZA,GS,SS,ES,LK,SD,SR,SJ,SZ,SE,CH,SY,TW,TJ,TZ,TH,TL,TG,TK,TO,TT,TN,TR,TM,TC,TV,UG,UA,AE,GB,UM,UY,UZ,VU,VE,VN,VG,VI,WF,EH,YE,ZM,ZW,US",currency = "AED,ALL,AMD,ARS,AUD,AZN,BAM,BDT,BGN,BHD,BMD,BND,BRL,BYN,CAD,CHF,CLP,CNY,COP,CRC,CZK,DKK,DOP,DZD,EGP,EUR,GBP,GEL,GHS,GTQ,HKD,HUF,IDR,INR,IQD,ISK,JOD,JPY,KES,KGS,KRW,KWD,KYD,KZT,LBP,LKR,MAD,MDL,MKD,MMK,MNT,MUR,MWK,MXN,MYR,MZN,NAD,NGN,NOK,NZD,OMR,PEN,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,SAR,SEK,SGD,SOS,THB,TND,TOP,TRY,TTD,TWD,UAH,UGX,USD,UYU,UZS,VND,XAF,XOF,YER,ZAR" }
+debit = { country = "AF,AX,AL,DZ,AS,AD,AO,AI,AQ,AG,AR,AM,AW,AU,AT,AZ,BS,BH,BD,BB,BY,BE,BZ,BJ,BM,BT,BO,BQ,BA,BW,BV,BR,IO,BN,BG,BF,BI,KH,CM,CA,CV,KY,CF,TD,CL,CN,CX,CC,CO,KM,CG,CD,CK,CR,CI,HR,CU,CW,CY,CZ,DK,DJ,DM,DO,EC,EG,SV,GQ,ER,EE,ET,FK,FO,FJ,FI,FR,GF,PF,TF,GA,GM,GE,DE,GH,GI,GR,GL,GD,GP,GU,GT,GG,GN,GW,GY,HT,HM,VA,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IM,IL,IT,JM,JP,JE,JO,KZ,KE,KI,KP,KR,KW,KG,LA,LV,LB,LS,LR,LY,LI,LT,LU,MO,MK,MG,MW,MY,MV,ML,MT,MH,MQ,MR,MU,YT,MX,FM,MD,MC,MN,ME,MS,MA,MZ,MM,NA,NR,NP,NL,NC,NZ,NI,NE,NG,NU,NF,MP,NO,OM,PK,PW,PS,PA,PG,PY,PE,PH,PN,PL,PT,PR,QA,RE,RO,RU,RW,BL,SH,KN,LC,MF,PM,VC,WS,SM,ST,SA,SN,RS,SC,SL,SG,SX,SK,SI,SB,SO,ZA,GS,SS,ES,LK,SD,SR,SJ,SZ,SE,CH,SY,TW,TJ,TZ,TH,TL,TG,TK,TO,TT,TN,TR,TM,TC,TV,UG,UA,AE,GB,UM,UY,UZ,VU,VE,VN,VG,VI,WF,EH,YE,ZM,ZW,US",currency = "AED,ALL,AMD,ARS,AUD,AZN,BAM,BDT,BGN,BHD,BMD,BND,BRL,BYN,CAD,CHF,CLP,CNY,COP,CRC,CZK,DKK,DOP,DZD,EGP,EUR,GBP,GEL,GHS,GTQ,HKD,HUF,IDR,INR,IQD,ISK,JOD,JPY,KES,KGS,KRW,KWD,KYD,KZT,LBP,LKR,MAD,MDL,MKD,MMK,MNT,MUR,MWK,MXN,MYR,MZN,NAD,NGN,NOK,NZD,OMR,PEN,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,SAR,SEK,SGD,SOS,THB,TND,TOP,TRY,TTD,TWD,UAH,UGX,USD,UYU,UZS,VND,XAF,XOF,YER,ZAR" }
+
+[pm_filters.checkout]
+debit = { country = "AT,BE,BG,HR,CY,CZ,DK,EE,FI,FR,DE,GR,HU,IS,IE,IT,LV,LI,LT,LU,MT,NL,NO,PL,PT,RO,SK,SI,ES,SE,CH,GB,US,AU,HK,SG,SA,AE,BH,MX,AR,CL,CO,PE", currency = "AED,AFN,ALL,AMD,ANG,AOA,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BYN,BZD,CAD,CDF,CHF,CLP,CNY,COP,CRC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLE,SLL,SOS,SRD,SSP,STN,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL" }
+credit = { country = "AT,BE,BG,HR,CY,CZ,DK,EE,FI,FR,DE,GR,HU,IS,IE,IT,LV,LI,LT,LU,MT,NL,NO,PL,PT,RO,SK,SI,ES,SE,CH,GB,US,AU,HK,SG,SA,AE,BH,MX,AR,CL,CO,PE", currency = "AED,AFN,ALL,AMD,ANG,AOA,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BYN,BZD,CAD,CDF,CHF,CLP,CNY,COP,CRC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLE,SLL,SOS,SRD,SSP,STN,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL" }
+google_pay = { country = "AL,DZ, AS, AO, AG, AR, AU, AT, AZ, BH, BY, BE, BR, CA, BG, CL, CO, HR, DK, DO, EE, EG, FI, FR, DE, GR, HK, HU, IN, ID, IE, IL, IT, JP, JO, KZ, KE, KW, LV, LB, LT, LU, MY, MX, NL, NZ, NO, OM, PK, PA, PE, PH, PL, PT, QA, RO, SA, SG, SK, ZA, ES, LK, SE, CH, TH, TW, TR, UA, AE, US, UY, VN", currency = "AED, ALL, AOA, AUD, AZN, BGN, BHD, BRL, CAD, CHF, CLP, COP, CZK, DKK, DOP, DZD, EGP, EUR, GBP, HKD, HUF, IDR, ILS, INR, JPY, KES, KWD, KZT, LKR, MXN, MYR, NOK, NZD, OMR, PAB, PEN, PHP, PKR, PLN, QAR, RON, SAR, SEK, SGD, THB, TRY, TWD, UAH, USD, UYU, VND, XCD, ZAR" }
+apple_pay = { country = "AM,US, AT, AZ, BY, BE, BG, HR, CY, DK, EE, FO, FI, FR, GE, DE, GR, GL, GG, HU, IS, IE, IM, IT, KZ, JE, LV, LI, LT, LU, MT, MD, MC, ME, NL, NO, PL, PT, RO, SM, RS, SK, SI, ES, SE, CH, UA, GB, VA, AU , HK, JP , MY , MN, NZ, SG, TW, VN, EG , MA, ZA, AR, BR, CL, CO, CR, DO, EC, SV, GT, HN, MX, PA, PY, PE, UY, BH, IL, JO, KW, OM,QA, SA, AE, CA", currency = "EGP, MAD, ZAR, AUD, CNY, HKD, JPY, MOP, MYR, MNT, NZD, SGD, KRW, TWD, VND, AMD, EUR, BGN, CZK, DKK, GEL, GBP, HUF, ISK, KZT, CHF, MDL, NOK, PLN, RON, RSD, SEK, UAH, BRL, COP, CRC, DOP, GTQ, HNL, MXN, PAB, PYG, PEN, BSD, UYU, BHD, ILS, JOD, KWD, OMR, QAR, SAR, AED, CAD, USD" }
+
+[pm_filters.checkbook]
+ach = { country = "US", currency = "USD" }
+
+[pm_filters.nexixpay]
+credit = { country = "AT,BE,CY,EE,FI,FR,DE,GR,IE,IT,LV,LT,LU,MT,NL,PT,SK,SI,ES,BG,HR,DK,GB,NO,PL,CZ,RO,SE,CH,HU,AU,BR,US", currency = "ARS,AUD,BHD,CAD,CLP,CNY,COP,HRK,CZK,DKK,HKD,HUF,INR,JPY,KZT,JOD,KRW,KWD,MYR,MXN,NGN,NOK,PHP,QAR,RUB,SAR,SGD,VND,ZAR,SEK,CHF,THB,AED,EGP,GBP,USD,TWD,BYN,RSD,AZN,RON,TRY,AOA,BGN,EUR,UAH,PLN,BRL" }
+debit = { country = "AT,BE,CY,EE,FI,FR,DE,GR,IE,IT,LV,LT,LU,MT,NL,PT,SK,SI,ES,BG,HR,DK,GB,NO,PL,CZ,RO,SE,CH,HU,AU,BR,US", currency = "ARS,AUD,BHD,CAD,CLP,CNY,COP,HRK,CZK,DKK,HKD,HUF,INR,JPY,KZT,JOD,KRW,KWD,MYR,MXN,NGN,NOK,PHP,QAR,RUB,SAR,SGD,VND,ZAR,SEK,CHF,THB,AED,EGP,GBP,USD,TWD,BYN,RSD,AZN,RON,TRY,AOA,BGN,EUR,UAH,PLN,BRL" }
+
+[pm_filters.square]
+credit = { country = "AU,CA,FR,IE,JP,ES,GB,US", currency = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BZD,CAD,CDF,CHF,CLP,CNY,COP,CRC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLE,SLL,SOS,SRD,SSP,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW" }
+debit = { country = "AU,CA,FR,IE,JP,ES,GB,US", currency = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BZD,CAD,CDF,CHF,CLP,CNY,COP,CRC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLE,SLL,SOS,SRD,SSP,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW" }
+
+[pm_filters.iatapay]
+upi_collect = { country = "IN", currency = "INR" }
+upi_intent = { country = "IN", currency = "INR" }
+ideal = { country = "NL", currency = "EUR" }
+local_bank_redirect = { country = "AT,BE,EE,FI,FR,DE,IE,IT,LV,LT,LU,NL,PT,ES,GB,IN,HK,SG,TH,BR,MX,GH,VN,MY,PH,JO,AU,CO", currency = "EUR,GBP,INR,HKD,SGD,THB,BRL,MXN,GHS,VND,MYR,PHP,JOD,AUD,COP" }
+duit_now = { country = "MY", currency = "MYR" }
+fps = { country = "GB", currency = "GBP" }
+prompt_pay = { country = "TH", currency = "THB" }
+viet_qr = { country = "VN", currency = "VND" }
+
+[pm_filters.coinbase]
+crypto_currency = { country = "ZA,US,BR,CA,TR,SG,VN,GB,DE,FR,ES,PT,IT,NL,AU" }
+
+[pm_filters.novalnet]
+credit = { country = "AD,AE,AL,AM,AR,AT,AU,AZ,BA,BB,BD,BE,BG,BH,BI,BM,BN,BO,BR,BS,BW,BY,BZ,CA,CD,CH,CL,CN,CO,CR,CU,CY,CZ,DE,DJ,DK,DO,DZ,EE,EG,ET,ES,FI,FJ,FR,GB,GE,GH,GI,GM,GR,GT,GY,HK,HN,HR,HU,ID,IE,IL,IN,IS,IT,JM,JO,JP,KE,KH,KR,KW,KY,KZ,LB,LK,LT,LV,LY,MA,MC,MD,ME,MG,MK,MN,MO,MT,MV,MW,MX,MY,NG,NI,NO,NP,NL,NZ,OM,PA,PE,PG,PH,PK,PL,PT,PY,QA,RO,RS,RU,RW,SA,SB,SC,SE,SG,SH,SI,SK,SL,SO,SM,SR,ST,SV,SY,TH,TJ,TN,TO,TR,TW,TZ,UA,UG,US,UY,UZ,VE,VA,VN,VU,WS,CF,AG,DM,GD,KN,LC,VC,YE,ZA,ZM", currency = "AED,ALL,AMD,ARS,AUD,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BWP,BYN,BZD,CAD,CDF,CHF,CLP,CNY,COP,CRC,CUP,CZK,DJF,DKK,DOP,DZD,EGP,ETB,EUR,FJD,GBP,GEL,GHS,GIP,GMD,GTQ,GYD,HKD,HNL,HRK,HUF,IDR,ILS,INR,ISK,JMD,JOD,JPY,KES,KHR,KRW,KWD,KYD,KZT,LBP,LKR,LYD,MAD,MDL,MGA,MKD,MNT,MOP,MVR,MWK,MXN,MYR,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SEK,SGD,SHP,SLL,SOS,SRD,STN,SVC,SYP,THB,TJS,TND,TOP,TRY,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,YER,ZAR,ZMW" }
+debit = { country = "AD,AE,AL,AM,AR,AT,AU,AZ,BA,BB,BD,BE,BG,BH,BI,BM,BN,BO,BR,BS,BW,BY,BZ,CA,CD,CH,CL,CN,CO,CR,CU,CY,CZ,DE,DJ,DK,DO,DZ,EE,EG,ET,ES,FI,FJ,FR,GB,GE,GH,GI,GM,GR,GT,GY,HK,HN,HR,HU,ID,IE,IL,IN,IS,IT,JM,JO,JP,KE,KH,KR,KW,KY,KZ,LB,LK,LT,LV,LY,MA,MC,MD,ME,MG,MK,MN,MO,MT,MV,MW,MX,MY,NG,NI,NO,NP,NL,NZ,OM,PA,PE,PG,PH,PK,PL,PT,PY,QA,RO,RS,RU,RW,SA,SB,SC,SE,SG,SH,SI,SK,SL,SO,SM,SR,ST,SV,SY,TH,TJ,TN,TO,TR,TW,TZ,UA,UG,US,UY,UZ,VE,VA,VN,VU,WS,CF,AG,DM,GD,KN,LC,VC,YE,ZA,ZM", currency = "AED,ALL,AMD,ARS,AUD,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BWP,BYN,BZD,CAD,CDF,CHF,CLP,CNY,COP,CRC,CUP,CZK,DJF,DKK,DOP,DZD,EGP,ETB,EUR,FJD,GBP,GEL,GHS,GIP,GMD,GTQ,GYD,HKD,HNL,HRK,HUF,IDR,ILS,INR,ISK,JMD,JOD,JPY,KES,KHR,KRW,KWD,KYD,KZT,LBP,LKR,LYD,MAD,MDL,MGA,MKD,MNT,MOP,MVR,MWK,MXN,MYR,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SEK,SGD,SHP,SLL,SOS,SRD,STN,SVC,SYP,THB,TJS,TND,TOP,TRY,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,YER,ZAR,ZMW" }
+apple_pay = { country = "EG, MA, ZA, CN, HK, JP, MY, MN, SG, KR, VN, AT, BE, BG, HR, CY, CZ, DK, EE, FI, FR, GE, DE, GR, GL, HU, IS, IE, IT, LV, LI, LT, LU, MT, MD, MC, ME, NL, NO, PL, PT, RO, SM, RS, SK, SI, ES, SE, CH, UA, GB, VA, CA, US, BH, IL, JO, KW, OM, QA, SA, AE, AR, BR, CL, CO, CR, SV, GT, MX, PY, PE, UY, BS, DO, AM, KZ, NZ", currency = "EGP, MAD, ZAR, AUD, CNY, HKD, JPY, MOP, MYR, MNT, NZD, SGD, KRW, TWD, VND, AMD, EUR, AZN, BGN, CZK, DKK, GEL, GBP, HUF, ISK, KZT, CHF, MDL, NOK, PLN, RON, RSD, SEK, UAH, ARS, BRL, CLP, COP, CRC, DOP, USD, GTQ, HNL, MXN, PAB, PYG, PEN, BSD, UYU, BHD, ILS, JOD, KWD, OMR, QAR, SAR, AED, CAD" }
+google_pay = { country = "AO, EG, KE, ZA, AR, BR, CL, CO, MX, PE, UY, AG, DO, AE, TR, SA, QA, OM, LB, KW, JO, IL, BH, KZ, VN, TH, SG, MY, JP, HK, LK, IN, US, CA, GB, UA, CH, SE, ES, SK, PT, RO, PL, NO, NL, LU, LT, LV, IE, IT, HU, GR, DE, FR, FI, EE, DK, CZ, HR, BG, BE, AT, AL", currency = "ALL, DZD, USD, XCD, ARS, AUD, EUR, AZN, BHD, BRL, BGN, CAD, CLP, COP, CZK, DKK, DOP, EGP, HKD, HUF, INR, IDR, ILS, JPY, JOD, KZT, KES, KWD, LBP, MYR, MXN, NZD, NOK, OMR, PKR, PAB, PEN, PHP, PLN, QAR, RON, RUB, SAR, SGD, ZAR, LKR, SEK, CHF, TWD, THB, TRY, UAH, AED, GBP, UYU, VND" }
+paypal = { country = "AD,AE,AL,AM,AR,AT,AU,AZ,BA,BB,BD,BE,BG,BH,BI,BM,BN,BO,BR,BS,BW,BY,BZ,CA,CD,CH,CL,CN,CO,CR,CU,CY,CZ,DE,DJ,DK,DO,DZ,EE,EG,ET,ES,FI,FJ,FR,GB,GE,GH,GI,GM,GR,GT,GY,HK,HN,HR,HU,ID,IE,IL,IN,IS,IT,JM,JO,JP,KE,KH,KR,KW,KY,KZ,LB,LK,LT,LV,LY,MA,MC,MD,ME,MG,MK,MN,MO,MT,MV,MW,MX,MY,NG,NI,NO,NP,NL,NZ,OM,PA,PE,PG,PH,PK,PL,PT,PY,QA,RO,RS,RU,RW,SA,SB,SC,SE,SG,SH,SI,SK,SL,SO,SM,SR,ST,SV,SY,TH,TJ,TN,TO,TR,TW,TZ,UA,UG,US,UY,UZ,VE,VA,VN,VU,WS,CF,AG,DM,GD,KN,LC,VC,YE,ZA,ZM", currency = "AED,ALL,AMD,ARS,AUD,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BWP,BYN,BZD,CAD,CDF,CHF,CLP,CNY,COP,CRC,CUP,CZK,DJF,DKK,DOP,DZD,EGP,ETB,EUR,FJD,GBP,GEL,GHS,GIP,GMD,GTQ,GYD,HKD,HNL,HRK,HUF,IDR,ILS,INR,ISK,JMD,JOD,JPY,KES,KHR,KRW,KWD,KYD,KZT,LBP,LKR,LYD,MAD,MDL,MGA,MKD,MNT,MOP,MVR,MWK,MXN,MYR,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SEK,SGD,SHP,SLL,SOS,SRD,STN,SVC,SYP,THB,TJS,TND,TOP,TRY,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,YER,ZAR,ZMW" }
+sepa = {country = "FR, IT, GR, BE, BG, FI, EE, HR, IE, DE, DK, LT, LV, MT, LU, AT, NL, PT, RO, PL, SK, SE, ES, SI, HU, CZ, CY, GB, LI, NO, IS, MC, CH, YT, PM, SM", currency="EUR"}
+sepa_guaranteed_debit = {country = "AT, CH, DE", currency="EUR"}
+
+[pm_filters.braintree]
+credit = { country = "AD,AT,AU,BE,BG,CA,CH,CY,CZ,DE,DK,EE,ES,FI,FR,GB,GG,GI,GR,HK,HR,HU,IE,IM,IT,JE,LI,LT,LU,LV,MT,MC,MY,NL,NO,NZ,PL,PT,RO,SE,SG,SI,SK,SM,US", currency = "AED,AMD,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BIF,BMD,BND,BOB,BRL,BSD,BWP,BYN,BZD,CAD,CHF,CLP,CNY,COP,CRC,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,ISK,JMD,JPY,KES,KGS,KHR,KMF,KRW,KYD,KZT,LAK,LBP,LKR,LRD,LSL,MAD,MDL,MKD,MNT,MOP,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SEK,SGD,SHP,SLL,SOS,SRD,STD,SVC,SYP,SZL,THB,TJS,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL"}
+debit = { country = "AD,AT,AU,BE,BG,CA,CH,CY,CZ,DE,DK,EE,ES,FI,FR,GB,GG,GI,GR,HK,HR,HU,IE,IM,IT,JE,LI,LT,LU,LV,MT,MC,MY,NL,NO,NZ,PL,PT,RO,SE,SG,SI,SK,SM,US", currency = "AED,AMD,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BIF,BMD,BND,BOB,BRL,BSD,BWP,BYN,BZD,CAD,CHF,CLP,CNY,COP,CRC,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,ISK,JMD,JPY,KES,KGS,KHR,KMF,KRW,KYD,KZT,LAK,LBP,LKR,LRD,LSL,MAD,MDL,MKD,MNT,MOP,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SEK,SGD,SHP,SLL,SOS,SRD,STD,SVC,SYP,SZL,THB,TJS,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL"}
+
+[pm_filters.facilitapay]
+pix = { country = "BR", currency = "BRL" }
+
+[pm_filters.finix]
+credit = { country = "AF,AX,AL,DZ,AS,AD,AO,AI,AQ,AG,AR,AM,AW,AU,AT,AZ,BS,BH,BD,BB,BY,BE,BZ,BJ,BM,BT,BO,BQ,BA,BW,BV,BR,IO,BN,BG,BF,BI,KH,CM,CA,CV,KY,CF,TD,CL,CN,CX,CC,CO,KM,CG,CD,CK,CR,CI,HR,CU,CW,CY,CZ,DK,DJ,DM,DO,EC,EG,SV,GQ,ER,EE,ET,FK,FO,FJ,FI,FR,GF,PF,TF,GA,GM,GE,DE,GH,GI,GR,GL,GD,GP,GU,GT,GG,GN,GW,GY,HT,HM,VA,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IM,IL,IT,JM,JP,JE,JO,KZ,KE,KI,KP,KR,KW,KG,LA,LV,LB,LS,LR,LY,LI,LT,LU,MO,MK,MG,MW,MY,MV,ML,MT,MH,MQ,MR,MU,YT,MX,FM,MD,MC,MN,ME,MS,MA,MZ,MM,NA,NR,NP,NL,NC,NZ,NI,NE,NG,NU,NF,MP,NO,OM,PK,PW,PS,PA,PG,PY,PE,PH,PN,PL,PT,PR,QA,RE,RO,RU,RW,BL,SH,KN,LC,MF,PM,VC,WS,SM,ST,SA,SN,RS,SC,SL,SG,SX,SK,SI,SB,SO,ZA,GS,SS,ES,LK,SD,SR,SJ,SZ,SE,CH,SY,TW,TJ,TZ,TH,TL,TG,TK,TO,TT,TN,TR,TM,TC,TV,UG,UA,AE,GB,UM,UY,UZ,VU,VE,VN,VG,VI,WF,EH,YE,ZM,ZW,US", currency = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BYN,BZD,CAD,CDF,CHF,CLF,CLP,CNY,COP,CRC,CUC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLE,SLL,SOS,SRD,SSP,STD,STN,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL"}
+debit = { country = "AF,AX,AL,DZ,AS,AD,AO,AI,AQ,AG,AR,AM,AW,AU,AT,AZ,BS,BH,BD,BB,BY,BE,BZ,BJ,BM,BT,BO,BQ,BA,BW,BV,BR,IO,BN,BG,BF,BI,KH,CM,CA,CV,KY,CF,TD,CL,CN,CX,CC,CO,KM,CG,CD,CK,CR,CI,HR,CU,CW,CY,CZ,DK,DJ,DM,DO,EC,EG,SV,GQ,ER,EE,ET,FK,FO,FJ,FI,FR,GF,PF,TF,GA,GM,GE,DE,GH,GI,GR,GL,GD,GP,GU,GT,GG,GN,GW,GY,HT,HM,VA,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IM,IL,IT,JM,JP,JE,JO,KZ,KE,KI,KP,KR,KW,KG,LA,LV,LB,LS,LR,LY,LI,LT,LU,MO,MK,MG,MW,MY,MV,ML,MT,MH,MQ,MR,MU,YT,MX,FM,MD,MC,MN,ME,MS,MA,MZ,MM,NA,NR,NP,NL,NC,NZ,NI,NE,NG,NU,NF,MP,NO,OM,PK,PW,PS,PA,PG,PY,PE,PH,PN,PL,PT,PR,QA,RE,RO,RU,RW,BL,SH,KN,LC,MF,PM,VC,WS,SM,ST,SA,SN,RS,SC,SL,SG,SX,SK,SI,SB,SO,ZA,GS,SS,ES,LK,SD,SR,SJ,SZ,SE,CH,SY,TW,TJ,TZ,TH,TL,TG,TK,TO,TT,TN,TR,TM,TC,TV,UG,UA,AE,GB,UM,UY,UZ,VU,VE,VN,VG,VI,WF,EH,YE,ZM,ZW,US", currency = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BYN,BZD,CAD,CDF,CHF,CLF,CLP,CNY,COP,CRC,CUC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLE,SLL,SOS,SRD,SSP,STD,STN,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL"}
+google_pay = { country = "AD, AE, AG, AI, AM, AO, AQ, AR, AS, AT, AU, AW, AX, AZ, BA, BB, BD, BE, BF, BG, BH, BI, BJ, BM, BN, BO, BQ, BR, BS, BT, BV, BW, BZ, CA, CC, CG, CH, CI, CK, CL, CM, CN, CO, CR, CV, CW, CX, CY, CZ, DE, DJ, DK, DM, DO, DZ, EC, EE, EG, EH, ER, ES, FI, FJ, FK, FM, FO, FR, GA, GB, GD, GE, GF, GG, GH, GI, GL, GM, GN, GP, GQ, GR, GS, GT, GU, GW, GY, HK, HM, HN, HR, HT, HU, ID, IE, IL, IM, IN, IO, IS, IT, JE, JM, JO, JP, KE, KG, KH, KI, KM, KN, KR, KW, KY, KZ, LA, LC, LI, LK, LR, LS, LT, LU, LV, MA, MC, MD, ME, MF, MG, MH, MK, MN, MO, MP, MQ, MR, MS, MT, MU, MV, MW, MX, MY, MZ, NA, NC, NE, NF, NG, NL, NO, NP, NR, NU, NZ, OM, PA, PE, PF, PG, PH, PK, PL, PM, PN, PR, PT, PW, PY, QA, RE, RO, RS, RW, SA, SB, SC, SE, SG, SH, SI, SJ, SK, SL, SM, SN, SR, ST, SV, SX, SZ, TC, TD, TF, TG, TH, TJ, TK, TL, TM, TN, TO, TT, TV, TZ, UG, UM, UY, UZ, VA, VC, VG, VI, VN, VU, WF, WS, YT, ZA, ZM, US", currency = "USD, CAD" }
+apple_pay = { currency = "USD, CAD" }
+
+[pm_filters.helcim]
+credit = { country = "US, CA", currency = "USD, CAD" }
+debit = { country = "US, CA", currency = "USD, CAD" }
+
+[pm_filters.globalpay]
+credit = { country = "AF,AX,AL,DZ,AS,AD,AO,AI,AQ,AG,AR,AM,AW,AU,AT,AZ,BS,BH,BD,BB,BY,BE,BZ,BJ,BM,BT,BO,BQ,BA,BW,BV,BR,IO,BN,BG,BF,BI,KH,CM,CA,CV,KY,CF,TD,CL,CN,CX,CC,CO,KM,CG,CD,CK,CR,CI,HR,CU,CW,CY,CZ,DK,DJ,DM,DO,EC,EG,SV,GQ,ER,EE,SZ,ET,FK,FO,FJ,FI,FR,GF,PF,TF,GA,GM,GE,DE,GH,GI,GR,GL,GD,GP,GU,GT,GG,GN,GW,GY,HT,HM,VA,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IM,IL,IT,JM,JP,JE,JO,KZ,KE,KI,KP,KR,KW,KG,LA,LV,LB,LS,LR,LY,LI,LT,LU,MO,MK,MG,MW,MY,MV,ML,MT,MH,MQ,MR,MU,YT,MX,FM,MD,MC,MN,ME,MS,MA,MZ,MM,NA,NR,NP,NL,NC,NZ,NI,NE,NG,NU,NF,MP,NO,OM,PK,PW,PS,PA,PG,PY,PE,PH,PN,PL,PT,PR,QA,RE,RO,RU,RW,BL,SH,KN,LC,MF,PM,VC,WS,SM,ST,SA,SN,RS,SC,SL,SG,SX,SK,SI,SB,SO,ZA,GS,SS,ES,LK,SD,SR,SJ,SE,CH,SY,TW,TJ,TZ,TH,TL,TG,TK,TO,TT,TN,TR,TM,TC,TV,UG,UA,AE,GB,US,UM,UY,UZ,VU,VE,VN,VG,VI,WF,EH,YE,ZM,ZW", currency = "AFN,DZD,ARS,AMD,AWG,AUD,AZN,BSD,BHD,THB,PAB,BBD,BYN,BZD,BMD,BOB,BRL,BND,BGN,BIF,CVE,CAD,CLP,COP,KMF,CDF,NIO,CRC,CUP,CZK,GMD,DKK,MKD,DJF,DOP,VND,XCD,EGP,SVC,ETB,EUR,FKP,FJD,HUF,GHS,GIP,HTG,PYG,GNF,GYD,HKD,UAH,ISK,INR,IRR,IQD,JMD,JOD,KES,PGK,HRK,KWD,AOA,MMK,LAK,GEL,LBP,ALL,HNL,SLL,LRD,LYD,SZL,LSL,MGA,MWK,MYR,MUR,MXN,MDL,MAD,MZN,NGN,ERN,NAD,NPR,ANG,ILS,TWD,NZD,BTN,KPW,NOK,TOP,PKR,MOP,UYU,PHP,GBP,BWP,QAR,GTQ,ZAR,OMR,KHR,RON,MVR,IDR,RUB,RWF,SHP,SAR,RSD,SCR,SGD,PEN,SBD,KGS,SOS,TJS,SSP,LKR,SDG,SRD,SEK,CHF,SYP,BDT,WST,TZS,KZT,TTD,MNT,TND,TRY,TMT,AED,UGX,USD,UZS,VUV,KRW,YER,JPY,CNY,ZMW,ZWL,PLN,CLF,STD,CUC" }
+debit = { country = "AF,AX,AL,DZ,AS,AD,AO,AI,AQ,AG,AR,AM,AW,AU,AT,AZ,BS,BH,BD,BB,BY,BE,BZ,BJ,BM,BT,BO,BQ,BA,BW,BV,BR,IO,BN,BG,BF,BI,KH,CM,CA,CV,KY,CF,TD,CL,CN,CX,CC,CO,KM,CG,CD,CK,CR,CI,HR,CU,CW,CY,CZ,DK,DJ,DM,DO,EC,EG,SV,GQ,ER,EE,SZ,ET,FK,FO,FJ,FI,FR,GF,PF,TF,GA,GM,GE,DE,GH,GI,GR,GL,GD,GP,GU,GT,GG,GN,GW,GY,HT,HM,VA,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IM,IL,IT,JM,JP,JE,JO,KZ,KE,KI,KP,KR,KW,KG,LA,LV,LB,LS,LR,LY,LI,LT,LU,MO,MK,MG,MW,MY,MV,ML,MT,MH,MQ,MR,MU,YT,MX,FM,MD,MC,MN,ME,MS,MA,MZ,MM,NA,NR,NP,NL,NC,NZ,NI,NE,NG,NU,NF,MP,NO,OM,PK,PW,PS,PA,PG,PY,PE,PH,PN,PL,PT,PR,QA,RE,RO,RU,RW,BL,SH,KN,LC,MF,PM,VC,WS,SM,ST,SA,SN,RS,SC,SL,SG,SX,SK,SI,SB,SO,ZA,GS,SS,ES,LK,SD,SR,SJ,SE,CH,SY,TW,TJ,TZ,TH,TL,TG,TK,TO,TT,TN,TR,TM,TC,TV,UG,UA,AE,GB,US,UM,UY,UZ,VU,VE,VN,VG,VI,WF,EH,YE,ZM,ZW", currency = "AFN,DZD,ARS,AMD,AWG,AUD,AZN,BSD,BHD,THB,PAB,BBD,BYN,BZD,BMD,BOB,BRL,BND,BGN,BIF,CVE,CAD,CLP,COP,KMF,CDF,NIO,CRC,CUP,CZK,GMD,DKK,MKD,DJF,DOP,VND,XCD,EGP,SVC,ETB,EUR,FKP,FJD,HUF,GHS,GIP,HTG,PYG,GNF,GYD,HKD,UAH,ISK,INR,IRR,IQD,JMD,JOD,KES,PGK,HRK,KWD,AOA,MMK,LAK,GEL,LBP,ALL,HNL,SLL,LRD,LYD,SZL,LSL,MGA,MWK,MYR,MUR,MXN,MDL,MAD,MZN,NGN,ERN,NAD,NPR,ANG,ILS,TWD,NZD,BTN,KPW,NOK,TOP,PKR,MOP,UYU,PHP,GBP,BWP,QAR,GTQ,ZAR,OMR,KHR,RON,MVR,IDR,RUB,RWF,SHP,SAR,RSD,SCR,SGD,PEN,SBD,KGS,SOS,TJS,SSP,LKR,SDG,SRD,SEK,CHF,SYP,BDT,WST,TZS,KZT,TTD,MNT,TND,TRY,TMT,AED,UGX,USD,UZS,VUV,KRW,YER,JPY,CNY,ZMW,ZWL,PLN,CLF,STD,CUC" }
+eps = { country = "AT", currency = "EUR" }
+giropay = { country = "DE", currency = "EUR" }
+ideal = { country = "NL", currency = "EUR" }
+sofort = { country = "AT,BE,DE,ES,IT,NL", currency = "EUR" }
+
+[pm_filters.jpmorgan]
+debit = { country = "CA, GB, US, AT, BE, BG, HR, CY, CZ, DK, EE, FI, FR, DE, GR, HU, IE, IT, LV, LT, LU, MT, NL, PL, PT, RO, SK, SI, ES, SE", currency = "USD, EUR, GBP, AUD, NZD, SGD, CAD, JPY, HKD, KRW, TWD, MXN, BRL, DKK, NOK, ZAR, SEK, CHF, CZK, PLN, TRY, AFN, ALL, DZD, AOA, ARS, AMD, AWG, AZN, BSD, BDT, BBD, BYN, BZD, BMD, BOB, BAM, BWP, BND, BGN, BIF, BTN, XOF, XAF, XPF, KHR, CVE, KYD, CLP, CNY, COP, KMF, CDF, CRC, HRK, DJF, DOP, XCD, EGP, ETB, FKP, FJD, GMD, GEL, GHS, GIP, GTQ, GYD, HTG, HNL, HUF, ISK, INR, IDR, ILS, JMD, KZT, KES, LAK, LBP, LSL, LRD, MOP, MKD, MGA, MWK, MYR, MVR, MRU, MUR, MDL, MNT, MAD, MZN, MMK, NAD, NPR, ANG, PGK, NIO, NGN, PKR, PAB, PYG, PEN, PHP, QAR, RON, RWF, SHP, WST, STN, SAR, RSD, SCR, SLL, SBD, SOS, LKR, SRD, SZL, TJS, TZS, THB, TOP, TTD, UGX, UAH, AED, UYU, UZS, VUV, VND, YER, ZMW" }
+credit = { country = "CA, GB, US, AT, BE, BG, HR, CY, CZ, DK, EE, FI, FR, DE, GR, HU, IE, IT, LV, LT, LU, MT, NL, PL, PT, RO, SK, SI, ES, SE", currency = "USD, EUR, GBP, AUD, NZD, SGD, CAD, JPY, HKD, KRW, TWD, MXN, BRL, DKK, NOK, ZAR, SEK, CHF, CZK, PLN, TRY, AFN, ALL, DZD, AOA, ARS, AMD, AWG, AZN, BSD, BDT, BBD, BYN, BZD, BMD, BOB, BAM, BWP, BND, BGN, BIF, BTN, XOF, XAF, XPF, KHR, CVE, KYD, CLP, CNY, COP, KMF, CDF, CRC, HRK, DJF, DOP, XCD, EGP, ETB, FKP, FJD, GMD, GEL, GHS, GIP, GTQ, GYD, HTG, HNL, HUF, ISK, INR, IDR, ILS, JMD, KZT, KES, LAK, LBP, LSL, LRD, MOP, MKD, MGA, MWK, MYR, MVR, MRU, MUR, MDL, MNT, MAD, MZN, MMK, NAD, NPR, ANG, PGK, NIO, NGN, PKR, PAB, PYG, PEN, PHP, QAR, RON, RWF, SHP, WST, STN, SAR, RSD, SCR, SLL, SBD, SOS, LKR, SRD, SZL, TJS, TZS, THB, TOP, TTD, UGX, UAH, AED, UYU, UZS, VUV, VND, YER, ZMW" }
+
+[pm_filters.bitpay]
+crypto_currency = { country = "US, CA, GB, AT, BE, BG, HR, CY, CZ, DK, EE, FI, FR, DE, GR, HU, IE, IT, LV, LT, LU, MT, NL, PL, PT, RO, SK, SI, ES, SE", currency = "USD, AUD, CAD, GBP, MXN, NZD, CHF, EUR"}
+
+[pm_filters.paybox]
+debit = { country = "FR", currency = "CAD, AUD, EUR, USD" }
+credit = { country = "FR", currency = "CAD, AUD, EUR, USD" }
+
+[pm_filters.payload]
+debit = { currency = "USD,CAD" }
+credit = { currency = "USD,CAD" }
+ach = { currency = "USD,CAD" }
+
+
+[pm_filters.digitalvirgo]
+direct_carrier_billing = {country = "MA, CM, ZA, EG, SN, DZ, TN, ML, GN, GH, LY, GA, CG, MG, BW, SD, NG, ID, SG, AZ, TR, FR, ES, PL, GB, PT, DE, IT, BE, IE, SK, GR, NL, CH, BR, MX, AR, CL, AE, IQ, KW, BH, SA, QA, PS, JO, OM, RU" , currency = "MAD, XOF, XAF, ZAR, EGP, DZD, TND, GNF, GHS, LYD, XAF, CDF, MGA, BWP, SDG, NGN, IDR, SGD, RUB, AZN, TRY, EUR, PLN, GBP, CHF, BRL, MXN, ARS, CLP, AED, IQD, KWD, BHD, SAR, QAR, ILS, JOD, OMR" }
+
+[pm_filters.payu]
+debit = { country = "AE, AF, AL, AM, CW, AO, AR, AU, AW, AZ, BA, BB, BG, BH, BI, BM, BN, BO, BR, BS, BW, BY, BZ, CA, CD, LI, CL, CN, CO, CR, CV, CZ, DJ, DK, DO, DZ, EG, ET, AD, FJ, FK, GG, GE, GH, GI, GM, GN, GT, GY, HK, HN, HR, HT, HU, ID, IL, IQ, IS, JM, JO, JP, KG, KH, KM, KR, KW, KY, KZ, LA, LB, LR, LS, MA, MD, MG, MK, MN, MO, MR, MV, MW, MX, MY, MZ, NA, NG, NI, BV, CK, OM, PA, PE, PG, PL, PY, QA, RO, RS, RW, SA, SB, SC, SE, SG, SH, SO, SR, SV, SZ, TH, TJ, TM, TN, TO, TR, TT, TW, TZ, UG, AS, UY, UZ, VE, VN, VU, WS, CM, AI, BJ, PF, YE, ZA, ZM, ZW", currency = "AED, AFN, ALL, AMD, ANG, AOA, ARS, AUD, AWG, AZN, BAM, BBD, BGN, BHD, BIF, BMD, BND, BOB, BRL, BSD, BWP, BYN, BZD, CAD, CDF, CHF, CLP, CNY, COP, CRC, CVE, CZK, DJF, DKK, DOP, DZD, EGP, ETB, EUR, FJD, FKP, GBP, GEL, GHS, GIP, GMD, GNF, GTQ, GYD, HKD, HNL, HRK, HTG, HUF, IDR, ILS, IQD, ISK, JMD, JOD, JPY, KGS, KHR, KMF, KRW, KWD, KYD, KZT, LAK, LBP, LRD, LSL, MAD, MDL, MGA, MKD, MNT, MOP, MRU, MVR, MWK, MXN, MYR, MZN, NAD, NGN, NIO, NOK, NZD, OMR, PAB, PEN, PGK, PLN, PYG, QAR, RON, RSD, RWF, SAR, SBD, SCR, SEK, SGD, SHP, SOS, SRD, SVC, SZL, THB, TJS, TMT, TND, TOP, TRY, TTD, TWD, TZS, UGX, USD, UYU, UZS, VES, VND, VUV, WST, XAF, XCD, XOF, XPF, YER, ZAR, ZMW, ZWL" }
+credit = { country = "AE, AF, AL, AM, CW, AO, AR, AU, AW, AZ, BA, BB, BG, BH, BI, BM, BN, BO, BR, BS, BW, BY, BZ, CA, CD, LI, CL, CN, CO, CR, CV, CZ, DJ, DK, DO, DZ, EG, ET, AD, FJ, FK, GG, GE, GH, GI, GM, GN, GT, GY, HK, HN, HR, HT, HU, ID, IL, IQ, IS, JM, JO, JP, KG, KH, KM, KR, KW, KY, KZ, LA, LB, LR, LS, MA, MD, MG, MK, MN, MO, MR, MV, MW, MX, MY, MZ, NA, NG, NI, BV, CK, OM, PA, PE, PG, PL, PY, QA, RO, RS, RW, SA, SB, SC, SE, SG, SH, SO, SR, SV, SZ, TH, TJ, TM, TN, TO, TR, TT, TW, TZ, UG, AS, UY, UZ, VE, VN, VU, WS, CM, AI, BJ, PF, YE, ZA, ZM, ZW", currency = "AED, AFN, ALL, AMD, ANG, AOA, ARS, AUD, AWG, AZN, BAM, BBD, BGN, BHD, BIF, BMD, BND, BOB, BRL, BSD, BWP, BYN, BZD, CAD, CDF, CHF, CLP, CNY, COP, CRC, CVE, CZK, DJF, DKK, DOP, DZD, EGP, ETB, EUR, FJD, FKP, GBP, GEL, GHS, GIP, GMD, GNF, GTQ, GYD, HKD, HNL, HRK, HTG, HUF, IDR, ILS, IQD, ISK, JMD, JOD, JPY, KGS, KHR, KMF, KRW, KWD, KYD, KZT, LAK, LBP, LRD, LSL, MAD, MDL, MGA, MKD, MNT, MOP, MRU, MVR, MWK, MXN, MYR, MZN, NAD, NGN, NIO, NOK, NZD, OMR, PAB, PEN, PGK, PLN, PYG, QAR, RON, RSD, RWF, SAR, SBD, SCR, SEK, SGD, SHP, SOS, SRD, SVC, SZL, THB, TJS, TMT, TND, TOP, TRY, TTD, TWD, TZS, UGX, USD, UYU, UZS, VES, VND, VUV, WST, XAF, XCD, XOF, XPF, YER, ZAR, ZMW, ZWL" }
+google_pay = { country = "AL, DZ, AS, AO, AR, AU, AZ, BH, BY, BR, BG, CA, CL, CO, HR, CZ, DK, DO, EG, HK, HU, ID, IN, IL, JP, JO, KZ, KW, LB, MY, MX, OM, PA, PE, PL, QA, RO, SA, SG, SE, TW, TH, TR, AE, UY, VN", currency = "ALL, DZD, USD, AOA, XCD, ARS, AUD, EUR, AZN, BHD, BYN, BRL, BGN, CAD, CLP, COP, CZK, DKK, DOP, EGP, HKD, HUF, INR, IDR, ILS, JPY, JOD, KZT, KWD, LBP, MYR, MXN, NZD, NOK, OMR, PAB, PEN, PLN, QAR, RON, SAR, SGD, ZAR, SEK, CHF, TWD, THB, TRY, UAH, AED, GBP, UYU, VND" }
+
+[pm_filters.klarna]
+klarna = { country = "AU,AT,BE,CA,CZ,DK,FI,FR,DE,GR,IE,IT,NL,NZ,NO,PL,PT,ES,SE,CH,GB,US", currency = "AUD,EUR,EUR,CAD,CZK,DKK,EUR,EUR,EUR,EUR,EUR,EUR,EUR,NZD,NOK,PLN,EUR,EUR,SEK,CHF,GBP,USD" }
+
+[pm_filters.flexiti]
+flexiti = { country = "CA", currency = "CAD" }
+
+[pm_filters.mifinity]
+mifinity = { country = "BR,CN,SG,MY,DE,CH,DK,GB,ES,AD,GI,FI,FR,GR,HR,IT,JP,MX,AR,CO,CL,PE,VE,UY,PY,BO,EC,GT,HN,SV,NI,CR,PA,DO,CU,PR,NL,NO,PL,PT,SE,RU,TR,TW,HK,MO,AX,AL,DZ,AS,AO,AI,AG,AM,AW,AU,AT,AZ,BS,BH,BD,BB,BE,BZ,BJ,BM,BT,BQ,BA,BW,IO,BN,BG,BF,BI,KH,CM,CA,CV,KY,CF,TD,CX,CC,KM,CG,CK,CI,CW,CY,CZ,DJ,DM,EG,GQ,ER,EE,ET,FK,FO,FJ,GF,PF,TF,GA,GM,GE,GH,GL,GD,GP,GU,GG,GN,GW,GY,HT,HM,VA,IS,IN,ID,IE,IM,IL,JE,JO,KZ,KE,KI,KW,KG,LA,LV,LB,LS,LI,LT,LU,MK,MG,MW,MV,ML,MT,MH,MQ,MR,MU,YT,FM,MD,MC,MN,ME,MS,MA,MZ,NA,NR,NP,NC,NZ,NE,NG,NU,NF,MP,OM,PK,PW,PS,PG,PH,PN,QA,RE,RO,RW,BL,SH,KN,LC,MF,PM,VC,WS,SM,ST,SA,SN,RS,SC,SL,SX,SK,SI,SB,SO,ZA,GS,KR,LK,SR,SJ,SZ,TH,TL,TG,TK,TO,TT,TN,TM,TC,TV,UG,UA,AE,UZ,VU,VN,VG,VI,WF,EH,ZM", currency = "AUD,CAD,CHF,CNY,CZK,DKK,EUR,GBP,INR,JPY,NOK,NZD,PLN,RUB,SEK,ZAR,USD,EGP,UYU,UZS" }
+
+[pm_filters.zen]
+credit = { not_available_flows = { capture_method = "manual" } }
+debit = { not_available_flows = { capture_method = "manual" } }
+boleto = { country = "BR", currency = "BRL" }
+efecty = { country = "CO", currency = "COP" }
+multibanco = { country = "PT", currency = "EUR" }
+pago_efectivo = { country = "PE", currency = "PEN" }
+pse = { country = "CO", currency = "COP" }
+pix = { country = "BR", currency = "BRL" }
+red_compra = { country = "CL", currency = "CLP" }
+red_pagos = { country = "UY", currency = "UYU" }
+
+[pm_filters.zsl]
+local_bank_transfer = { country = "CN", currency = "CNY" }
+
+[pm_filters.aci]
+credit = { country = "AD,AE,AT,BE,BG,CH,CN,CO,CR,CY,CZ,DE,DK,DO,EE,EG,ES,ET,FI,FR,GB,GH,GI,GR,GT,HN,HK,HR,HU,ID,IE,IS,IT,JP,KH,LA,LI,LT,LU,LY,MK,MM,MX,MY,MZ,NG,NZ,OM,PA,PE,PK,PL,PT,QA,RO,SA,SN,SE,SI,SK,SV,TH,UA,US,UY,VN,ZM", currency = "AED,ALL,ARS,BGN,CHF,CLP,CNY,COP,CRC,CZK,DKK,DOP,EGP,EUR,GBP,GHS,HKD,HNL,HRK,HUF,IDR,ILS,ISK,JPY,KHR,KPW,LAK,LKR,MAD,MKD,MMK,MXN,MYR,MZN,NGN,NOK,NZD,OMR,PAB,PEN,PHP,PKR,PLN,QAR,RON,RSD,SAR,SEK,SGD,THB,TRY,TWD,UAH,USD,UYU,VND,ZAR,ZMW" }
+debit = { country = "AD,AE,AT,BE,BG,CH,CN,CO,CR,CY,CZ,DE,DK,DO,EE,EG,ES,ET,FI,FR,GB,GH,GI,GR,GT,HN,HK,HR,HU,ID,IE,IS,IT,JP,KH,LA,LI,LT,LU,LY,MK,MM,MX,MY,MZ,NG,NZ,OM,PA,PE,PK,PL,PT,QA,RO,SA,SN,SE,SI,SK,SV,TH,UA,US,UY,VN,ZM", currency = "AED,ALL,ARS,BGN,CHF,CLP,CNY,COP,CRC,CZK,DKK,DOP,EGP,EUR,GBP,GHS,HKD,HNL,HRK,HUF,IDR,ILS,ISK,JPY,KHR,KPW,LAK,LKR,MAD,MKD,MMK,MXN,MYR,MZN,NGN,NOK,NZD,OMR,PAB,PEN,PHP,PKR,PLN,QAR,RON,RSD,SAR,SEK,SGD,THB,TRY,TWD,UAH,USD,UYU,VND,ZAR,ZMW" }
+mb_way = { country = "EE,ES,PT", currency = "EUR" }
+ali_pay = { country = "CN", currency = "CNY" }
+eps = { country = "AT", currency = "EUR" }
+ideal = { country = "NL", currency = "EUR" }
+giropay = { country = "DE", currency = "EUR" }
+sofort = { country = "AT,BE,CH,DE,ES,GB,IT,NL,PL", currency = "CHF,EUR,GBP,HUF,PLN"}
+interac = { country = "CA", currency = "CAD,USD"}
+przelewy24 = { country = "PL", currency = "CZK,EUR,GBP,PLN" }
+trustly = { country = "ES,GB,SE,NO,AT,NL,DE,DK,FI,EE,LT,LV", currency = "CZK,DKK,EUR,GBP,NOK,SEK" }
+klarna = { country = "AU,AT,BE,CA,CZ,DK,FI,FR,DE,GR,IE,IT,NL,NZ,NO,PL,PT,ES,SE,CH,GB,US", currency = "CHF,DKK,EUR,GBP,NOK,PLN,SEK,USD,AUD,NZD,CAD" }
+
+[pm_filters.gigadat]
+interac = { currency = "CAD"}
+
+[pm_filters.loonio]
+interac = { currency = "CAD"}
+
+[pm_filters.dlocal]
+oxxo = { currency = "MXN" }
+
+[pm_filters.mollie]
+eps = { country = "AT", currency = "EUR" }
+ideal = { country = "NL", currency = "EUR" }
+przelewy24 = { country = "PL", currency = "PLN,EUR" }
+klarna = { country = "DE,AT,NL,BE,FR,GB,IT,ES,PT,SE,DK,FI,NO,CH,IR,CZ,PL,GR,SK", currency = "EUR,GBP,DKK,SEK,NOK,CHF,PLN,CZK" }
+
+[pm_filters.redsys]
+credit = { currency = "AUD,BGN,CAD,CHF,COP,CZK,DKK,EUR,GBP,HRK,HUF,ILS,INR,JPY,MYR,NOK,NZD,PEN,PLN,RUB,SAR,SEK,SGD,THB,USD,ZAR", country="ES" }
+debit = { currency = "AUD,BGN,CAD,CHF,COP,CZK,DKK,EUR,GBP,HRK,HUF,ILS,INR,JPY,MYR,NOK,NZD,PEN,PLN,RUB,SAR,SEK,SGD,THB,USD,ZAR", country="ES" }
+
+[pm_filters.stax]
+credit = { country = "US", currency = "USD" }
+debit = { country = "US", currency = "USD" }
+ach = { country = "US", currency = "USD" }
+
+[pm_filters.prophetpay]
+card_redirect = { country = "US", currency = "USD" }
+
+[pm_filters.multisafepay]
+credit = { country = "AF,AX,AL,DZ,AS,AD,AO,AI,AQ,AG,AR,AM,AW,AU,AT,AZ,BS,BH,BD,BB,BY,BE,BZ,BJ,BM,BT,BO,BQ,BA,BW,BV,BR,IO,BN,BG,BF,BI,CV,KH,CM,CA,KY,CF,TD,CL,CN,CX,CC,CO,KM,CG,CD,CK,CR,CI,HR,CU,CW,CY,CZ,DK,DJ,DM,DO,EC,EG,SV,GQ,ER,EE,ET,FK,FO,FJ,FI,FR,GF,PF,TF,GA,GM,GE,DE,GH,GI,GR,GL,GD,GP,GU,GT,GG,GN,GW,GY,HT,HM,VA,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IM,IL,IT,JM,JP,JE,JO,KZ,KE,KI,KP,KR,KW,KG,LA,LV,LB,LS,LR,LY,LI,LT,LU,MO,MK,MG,MW,MY,MV,ML,MT,MH,MQ,MR,MU,YT,MX,FM,MD,MC,MN,ME,MS,MA,MZ,MM,NA,NR,NP,NL,NC,NZ,NI,NE,NG,NU,NF,MP,NO,OM,PK,PW,PS,PA,PG,PY,PE,PH,PN,PL,PT,PR,QA,RE,RO,RU,RW,BL,SH,KN,LC,MF,PM,VC,WS,SM,ST,SA,SN,RS,SC,SL,SG,SX,SK,SI,SB,SO,ZA,GS,SS,ES,LK,SD,SR,SJ,SZ,SE,CH,SY,TW,TJ,TZ,TH,TL,TG,TK,TO,TT,TN,TR,TM,TC,TV,UG,UA,AE,GB,US,UM,UY,UZ,VU,VE,VN,VG,VI,WF,EH,YE,ZM,ZW", currency = "AED,AUD,BRL,CAD,CHF,CLP,CNY,COP,CZK,DKK,EUR,GBP,HKD,HRK,HUF,ILS,INR,ISK,JPY,KRW,MXN,MYR,NOK,NZD,PEN,PLN,RON,RUB,SEK,SGD,TRY,TWD,USD,ZAR", not_available_flows = { capture_method = "manual" } }
+debit = { country = "AF,AX,AL,DZ,AS,AD,AO,AI,AQ,AG,AR,AM,AW,AU,AT,AZ,BS,BH,BD,BB,BY,BE,BZ,BJ,BM,BT,BO,BQ,BA,BW,BV,BR,IO,BN,BG,BF,BI,CV,KH,CM,CA,KY,CF,TD,CL,CN,CX,CC,CO,KM,CG,CD,CK,CR,CI,HR,CU,CW,CY,CZ,DK,DJ,DM,DO,EC,EG,SV,GQ,ER,EE,ET,FK,FO,FJ,FI,FR,GF,PF,TF,GA,GM,GE,DE,GH,GI,GR,GL,GD,GP,GU,GT,GG,GN,GW,GY,HT,HM,VA,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IM,IL,IT,JM,JP,JE,JO,KZ,KE,KI,KP,KR,KW,KG,LA,LV,LB,LS,LR,LY,LI,LT,LU,MO,MK,MG,MW,MY,MV,ML,MT,MH,MQ,MR,MU,YT,MX,FM,MD,MC,MN,ME,MS,MA,MZ,MM,NA,NR,NP,NL,NC,NZ,NI,NE,NG,NU,NF,MP,NO,OM,PK,PW,PS,PA,PG,PY,PE,PH,PN,PL,PT,PR,QA,RE,RO,RU,RW,BL,SH,KN,LC,MF,PM,VC,WS,SM,ST,SA,SN,RS,SC,SL,SG,SX,SK,SI,SB,SO,ZA,GS,SS,ES,LK,SD,SR,SJ,SZ,SE,CH,SY,TW,TJ,TZ,TH,TL,TG,TK,TO,TT,TN,TR,TM,TC,TV,UG,UA,AE,GB,US,UM,UY,UZ,VU,VE,VN,VG,VI,WF,EH,YE,ZM,ZW", currency = "AED,AUD,BRL,CAD,CHF,CLP,CNY,COP,CZK,DKK,EUR,GBP,HKD,HRK,HUF,ILS,INR,ISK,JPY,KRW,MXN,MYR,NOK,NZD,PEN,PLN,RON,RUB,SEK,SGD,TRY,TWD,USD,ZAR", not_available_flows = { capture_method = "manual" } }
+google_pay = { country = "AL, DZ, AS, AO, AG, AR, AU, AT, AZ, BH, BY, BE, BR, BG, CA, CL, CO, HR, CZ, DK, DO, EG, EE, FI, FR, DE, GR, HK, HU, IN, ID, IE, IL, IT, JP, JO, KZ, KE, KW, LV, LB, LT, LU, MY, MX, NL, NZ, NO, OM, PK, PA, PE, PH, PL, PT, QA, RO, RU, SA, SG, SK, ZA, ES, LK, SE, CH, TW, TH, TR, UA, AE, GB, US, UY, VN", currency = "AED, AUD, BRL, CAD, CHF, CLP, COP, CZK, DKK, EUR, GBP, HKD, HRK, HUF, ILS, INR, JPY, MXN, MYR, NOK, NZD, PEN, PHP, PLN, RON, RUB, SEK, SGD, THB, TRY, TWD, UAH, USD, ZAR" }
+paypal = { country = "AF,AX,AL,DZ,AS,AD,AO,AI,AQ,AG,AR,AM,AW,AU,AT,AZ,BS,BH,BD,BB,BY,BE,BZ,BJ,BM,BT,BO,BQ,BA,BW,BV,BR,IO,BN,BG,BF,BI,CV,KH,CM,CA,KY,CF,TD,CL,CN,CX,CC,CO,KM,CG,CD,CK,CR,CI,HR,CU,CW,CY,CZ,DK,DJ,DM,DO,EC,EG,SV,GQ,ER,EE,ET,FK,FO,FJ,FI,FR,GF,PF,TF,GA,GM,GE,DE,GH,GI,GR,GL,GD,GP,GU,GT,GG,GN,GW,GY,HT,HM,VA,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IM,IL,IT,JM,JP,JE,JO,KZ,KE,KI,KP,KR,KW,KG,LA,LV,LB,LS,LR,LY,LI,LT,LU,MO,MK,MG,MW,MY,MV,ML,MT,MH,MQ,MR,MU,YT,MX,FM,MD,MC,MN,ME,MS,MA,MZ,MM,NA,NR,NP,NL,NC,NZ,NI,NE,NG,NU,NF,MP,NO,OM,PK,PW,PS,PA,PG,PY,PE,PH,PN,PL,PT,PR,QA,RE,RO,RU,RW,BL,SH,KN,LC,MF,PM,VC,WS,SM,ST,SA,SN,RS,SC,SL,SG,SX,SK,SI,SB,SO,ZA,GS,SS,ES,LK,SD,SR,SJ,SZ,SE,CH,SY,TW,TJ,TZ,TH,TL,TG,TK,TO,TT,TN,TR,TM,TC,TV,UG,UA,AE,GB,US,UM,UY,UZ,VU,VE,VN,VG,VI,WF,EH,YE,ZM,ZW", currency = "AUD,BRL,CAD,CHF,CZK,DKK,EUR,GBP,HKD,HRK,HUF,JPY,MXN,MYR,NOK,NZD,PHP,PLN,RUB,SEK,SGD,THB,TRY,TWD,USD" }
+giropay = { country = "DE", currency = "EUR" }
+ideal = { country = "NL", currency = "EUR" }
+klarna = { country = "AT,BE,DK,FI,FR,DE,IT,NL,NO,PT,ES,SE,GB", currency = "DKK,EUR,GBP,NOK,SEK" }
+trustly = { country = "AT,CZ,DK,EE,FI,DE,LV,LT,NL,NO,PL,PT,ES,SE,GB" , currency = "EUR,GBP,SEK"}
+ali_pay = { currency = "EUR,USD" }
+we_chat_pay = { currency = "EUR"}
+eps = { country = "AT" , currency = "EUR" }
+mb_way = { country = "PT" , currency = "EUR" }
+sofort = { country = "AT,BE,FR,DE,IT,PL,ES,CH,GB" , currency = "EUR"}
+
+[pm_filters.cashtocode]
+classic = { country = "AF,AX,AL,DZ,AS,AD,AO,AI,AQ,AG,AR,AM,AW,AU,AT,AZ,BS,BH,BD,BB,BY,BE,BZ,BJ,BM,BT,BO,BQ,BA,BW,BV,BR,IO,BN,BG,BF,BI,KH,CM,CA,CV,KY,CF,TD,CL,CN,CX,CC,CO,KM,CG,CD,CK,CR,CI,HR,CU,CW,CY,CZ,DK,DJ,DM,DO,EC,EG,SV,GQ,ER,EE,ET,FK,FO,FJ,FI,FR,GF,PF,TF,GA,GM,GE,DE,GH,GI,GR,GL,GD,GP,GU,GT,GG,GN,GW,GY,HT,HM,VA,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IM,IL,IT,JM,JP,JE,JO,KZ,KE,KI,KP,KR,KW,KG,LA,LV,LB,LS,LR,LY,LI,LT,LU,MO,MK,MG,MW,MY,MV,ML,MT,MH,MQ,MR,MU,YT,MX,FM,MD,MC,MN,ME,MS,MA,MZ,MM,NA,NR,NP,NL,NC,NZ,NI,NE,NG,NU,NF,MP,NO,OM,PK,PW,PS,PA,PG,PY,PE,PH,PN,PL,PT,PR,QA,RE,RO,RU,RW,BL,SH,KN,LC,MF,PM,VC,WS,SM,ST,SA,SN,RS,SC,SL,SG,SX,SK,SI,SB,SO,ZA,GS,SS,ES,LK,SD,SR,SJ,SZ,SE,CH,SY,TW,TJ,TZ,TH,TL,TG,TK,TO,TT,TN,TR,TM,TC,TV,UG,UA,AE,GB,UM,UY,UZ,VU,VE,VN,VG,VI,WF,EH,YE,ZM,ZW,US", currency = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BYN,BZD,CAD,CDF,CHF,CLF,CLP,CNY,COP,CRC,CUC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLE,SLL,SOS,SRD,SSP,STD,STN,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL" }
+evoucher = { country = "AF,AX,AL,DZ,AS,AD,AO,AI,AQ,AG,AR,AM,AW,AU,AT,AZ,BS,BH,BD,BB,BY,BE,BZ,BJ,BM,BT,BO,BQ,BA,BW,BV,BR,IO,BN,BG,BF,BI,KH,CM,CA,CV,KY,CF,TD,CL,CN,CX,CC,CO,KM,CG,CD,CK,CR,CI,HR,CU,CW,CY,CZ,DK,DJ,DM,DO,EC,EG,SV,GQ,ER,EE,ET,FK,FO,FJ,FI,FR,GF,PF,TF,GA,GM,GE,DE,GH,GI,GR,GL,GD,GP,GU,GT,GG,GN,GW,GY,HT,HM,VA,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IM,IL,IT,JM,JP,JE,JO,KZ,KE,KI,KP,KR,KW,KG,LA,LV,LB,LS,LR,LY,LI,LT,LU,MO,MK,MG,MW,MY,MV,ML,MT,MH,MQ,MR,MU,YT,MX,FM,MD,MC,MN,ME,MS,MA,MZ,MM,NA,NR,NP,NL,NC,NZ,NI,NE,NG,NU,NF,MP,NO,OM,PK,PW,PS,PA,PG,PY,PE,PH,PN,PL,PT,PR,QA,RE,RO,RU,RW,BL,SH,KN,LC,MF,PM,VC,WS,SM,ST,SA,SN,RS,SC,SL,SG,SX,SK,SI,SB,SO,ZA,GS,SS,ES,LK,SD,SR,SJ,SZ,SE,CH,SY,TW,TJ,TZ,TH,TL,TG,TK,TO,TT,TN,TR,TM,TC,TV,UG,UA,AE,GB,UM,UY,UZ,VU,VE,VN,VG,VI,WF,EH,YE,ZM,ZW,US", currency = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BYN,BZD,CAD,CDF,CHF,CLF,CLP,CNY,COP,CRC,CUC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLE,SLL,SOS,SRD,SSP,STD,STN,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL" }
+
+[pm_filters.wellsfargo]
+credit = { country = "AF,AX,AL,DZ,AS,AD,AO,AI,AQ,AG,AR,AM,AW,AU,AT,AZ,BS,BH,BD,BB,BY,BE,BZ,BJ,BM,BT,BO,BQ,BA,BW,BV,BR,IO,BN,BG,BF,BI,KH,CM,CA,CV,KY,CF,TD,CL,CN,CX,CC,CO,KM,CG,CD,CK,CR,CI,HR,CU,CW,CY,CZ,DK,DJ,DM,DO,EC,EG,SV,GQ,ER,EE,ET,FK,FO,FJ,FI,FR,GF,PF,TF,GA,GM,GE,DE,GH,GI,GR,GL,GD,GP,GU,GT,GG,GN,GW,GY,HT,HM,VA,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IM,IL,IT,JM,JP,JE,JO,KZ,KE,KI,KP,KR,KW,KG,LA,LV,LB,LS,LR,LY,LI,LT,LU,MO,MK,MG,MW,MY,MV,ML,MT,MH,MQ,MR,MU,YT,MX,FM,MD,MC,MN,ME,MS,MA,MZ,MM,NA,NR,NP,NL,NC,NZ,NI,NE,NG,NU,NF,MP,NO,OM,PK,PW,PS,PA,PG,PY,PE,PH,PN,PL,PT,PR,QA,RE,RO,RU,RW,BL,SH,KN,LC,MF,PM,VC,WS,SM,ST,SA,SN,RS,SC,SL,SG,SX,SK,SI,SB,SO,ZA,GS,SS,ES,LK,SD,SR,SJ,SZ,SE,CH,SY,TW,TJ,TZ,TH,TL,TG,TK,TO,TT,TN,TR,TM,TC,TV,UG,UA,US,AE,GB,UM,UY,UZ,VU,VE,VN,VG,VI,WF,EH,YE,ZM,ZW", currency = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BYN,BZD,CAD,CDF,CHF,CLP,CNY,COP,CRC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLE,SLL,SOS,SRD,SSP,STN,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL" }
+debit = { country = "AF,AX,AL,DZ,AS,AD,AO,AI,AQ,AG,AR,AM,AW,AU,AT,AZ,BS,BH,BD,BB,BY,BE,BZ,BJ,BM,BT,BO,BQ,BA,BW,BV,BR,IO,BN,BG,BF,BI,KH,CM,CA,CV,KY,CF,TD,CL,CN,CX,CC,CO,KM,CG,CD,CK,CR,CI,HR,CU,CW,CY,CZ,DK,DJ,DM,DO,EC,EG,SV,GQ,ER,EE,ET,FK,FO,FJ,FI,FR,GF,PF,TF,GA,GM,GE,DE,GH,GI,GR,GL,GD,GP,GU,GT,GG,GN,GW,GY,HT,HM,VA,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IM,IL,IT,JM,JP,JE,JO,KZ,KE,KI,KP,KR,KW,KG,LA,LV,LB,LS,LR,LY,LI,LT,LU,MO,MK,MG,MW,MY,MV,ML,MT,MH,MQ,MR,MU,YT,MX,FM,MD,MC,MN,ME,MS,MA,MZ,MM,NA,NR,NP,NL,NC,NZ,NI,NE,NG,NU,NF,MP,NO,OM,PK,PW,PS,PA,PG,PY,PE,PH,PN,PL,PT,PR,QA,RE,RO,RU,RW,BL,SH,KN,LC,MF,PM,VC,WS,SM,ST,SA,SN,RS,SC,SL,SG,SX,SK,SI,SB,SO,ZA,GS,SS,ES,LK,SD,SR,SJ,SZ,SE,CH,SY,TW,TJ,TZ,TH,TL,TG,TK,TO,TT,TN,TR,TM,TC,TV,UG,UA,US,AE,GB,UM,UY,UZ,VU,VE,VN,VG,VI,WF,EH,YE,ZM,ZW", currency = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BYN,BZD,CAD,CDF,CHF,CLP,CNY,COP,CRC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLE,SLL,SOS,SRD,SSP,STN,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL" }
+google_pay = { country = "US", currency = "USD" }
+apple_pay = { country = "US", currency = "USD" }
+ach = { country = "US", currency = "USD" }
+
+[pm_filters.trustpay]
+credit = { not_available_flows = { capture_method = "manual" } }
+debit = { not_available_flows = { capture_method = "manual" } }
+instant_bank_transfer = { country = "CZ,SK,GB,AT,DE,IT", currency = "CZK, EUR, GBP" }
+instant_bank_transfer_poland = { country = "PL", currency = "PLN" }
+instant_bank_transfer_finland = { country = "FI", currency = "EUR" }
+sepa = { country = "ES,SK,AT,NL,DE,BE,FR,FI,PT,IE,EE,LT,LV,IT,GB", currency = "EUR" }
+
+[pm_filters.tesouro]
+credit = { country = "AF,AL,DZ,AD,AO,AI,AG,AR,AM,AW,AU,AT,AZ,BS,BH,BD,BB,BY,BE,BZ,BJ,BM,BT,BO,BA,BW,BN,BG,BF,BI,KH,CM,CA,CV,KY,CF,TD,CL,CN,CO,KM,CD,CG,CK,CR,HR,CU,CW,CY,CZ,DK,DJ,DM,DO,EC,SV,GQ,ER,EE,ET,FK,FO,FJ,FI,FR,GF,PF,TF,GA,GM,GE,DE,GH,GI,GR,GL,GD,GP,GU,GT,GG,GN,GW,GY,HT,HM,VA,HN,HK,HU,IS,ID,IR,IQ,IE,IM,IL,IT,JM,JP,JE,JO,KZ,KE,KI,KR,KW,KG,LA,LV,LB,LS,LR,LY,LI,LT,LU,MO,MG,MW,MY,MV,ML,MT,MH,MR,MU,MX,FM,MD,MC,MN,ME,MS,MA,MZ,MM,NA,NR,NP,NL,NC,NZ,NI,NE,NG,NU,NO,OM,PK,PW,PS,PA,PG,PY,PE,PH,PL,PT,PR,QA,CG,RO,RW,KN,LC,VC,WS,SM,ST,SA,SN,RS,SC,SL,SG,SX,SK,SI,SO,ZA,GS,ES,LK,SR,SJ,SZ,SE,CH,TW,TJ,TZ,TH,TL,TG,TO,TT,TN,TR,TM,TC,TV,UG,UA,AE,GB,US,UY,UZ,VU,VE,VN,VG,WF,YE,ZM,ZW", currency = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BYN,BZD,CAD,CDF,CHF,CLF,CLP,CNY,COP,CRC,CUC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLE,SLL,SOS,SRD,SSP,STD,STN,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL" }
+debit = { country = "AF,AL,DZ,AD,AO,AI,AG,AR,AM,AW,AU,AT,AZ,BS,BH,BD,BB,BY,BE,BZ,BJ,BM,BT,BO,BA,BW,BN,BG,BF,BI,KH,CM,CA,CV,KY,CF,TD,CL,CN,CO,KM,CD,CG,CK,CR,HR,CU,CW,CY,CZ,DK,DJ,DM,DO,EC,SV,GQ,ER,EE,ET,FK,FO,FJ,FI,FR,GF,PF,TF,GA,GM,GE,DE,GH,GI,GR,GL,GD,GP,GU,GT,GG,GN,GW,GY,HT,HM,VA,HN,HK,HU,IS,ID,IR,IQ,IE,IM,IL,IT,JM,JP,JE,JO,KZ,KE,KI,KR,KW,KG,LA,LV,LB,LS,LR,LY,LI,LT,LU,MO,MG,MW,MY,MV,ML,MT,MH,MR,MU,MX,FM,MD,MC,MN,ME,MS,MA,MZ,MM,NA,NR,NP,NL,NC,NZ,NI,NE,NG,NU,NO,OM,PK,PW,PS,PA,PG,PY,PE,PH,PL,PT,PR,QA,CG,RO,RW,KN,LC,VC,WS,SM,ST,SA,SN,RS,SC,SL,SG,SX,SK,SI,SO,ZA,GS,ES,LK,SR,SJ,SZ,SE,CH,TW,TJ,TZ,TH,TL,TG,TO,TT,TN,TR,TM,TC,TV,UG,UA,AE,GB,US,UY,UZ,VU,VE,VN,VG,WF,YE,ZM,ZW", currency = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BYN,BZD,CAD,CDF,CHF,CLF,CLP,CNY,COP,CRC,CUC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLE,SLL,SOS,SRD,SSP,STD,STN,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL" }
+apple_pay = { currency = "USD" }
+google_pay = { currency = "USD" }
+
+[pm_filters.authorizedotnet]
+credit = {currency = "CAD,USD"}
+debit = {currency = "CAD,USD"}
+google_pay = {currency = "CHF,DKK,EUR,GBP,NOK,PLN,SEK,USD,AUD,NZD,CAD"}
+apple_pay = {currency = "EUR,GBP,ISK,USD,AUD,CAD,BRL,CLP,COP,CRC,CZK,DKK,EGP,GEL,GHS,GTQ,HNL,HKD,HUF,ILS,INR,JPY,KZT,KRW,KWD,MAD,MXN,MYR,NOK,NZD,PEN,PLN,PYG,QAR,RON,SAR,SEK,SGD,THB,TWD,UAH,AED,VND,ZAR"}
+paypal = {currency = "AUD,BRL,CAD,CHF,CNY,CZK,DKK,EUR,GBP,HKD,HUF,ILS,JPY,MXN,MYR,NOK,NZD,PHP,PLN,SEK,SGD,THB,TWD,USD"}
+
+[pm_filters.dwolla]
+ach = { country = "US", currency = "USD" }
+
+[pm_filters.worldpay]
+debit = { country = "AF,DZ,AW,AU,AZ,BS,BH,BD,BB,BZ,BM,BT,BO,BA,BW,BR,BN,BG,BI,KH,CA,CV,KY,CL,CO,KM,CD,CR,CZ,DK,DJ,ST,DO,EC,EG,SV,ER,ET,FK,FJ,GM,GE,GH,GI,GT,GN,GY,HT,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IL,IT,JM,JP,JO,KZ,KE,KW,LA,LB,LS,LR,LY,LT,MO,MK,MG,MW,MY,MV,MR,MU,MX,MD,MN,MA,MZ,MM,NA,NZ,NI,NG,KP,NO,AR,PK,PG,PY,PE,UY,PH,PL,GB,QA,OM,RO,RU,RW,WS,SG,ST,ZA,KR,LK,SH,SD,SR,SZ,SE,CH,SY,TW,TJ,TZ,TH,TT,TN,TR,UG,UA,US,UZ,VU,VE,VN,ZM,ZW", currency = "AFN,DZD,ANG,AWG,AUD,AZN,BSD,BHD,BDT,BBD,BZD,BMD,BTN,BOB,BAM,BWP,BRL,BND,BGN,BIF,KHR,CAD,CVE,KYD,XOF,XAF,XPF,CLP,COP,KMF,CDF,CRC,EUR,CZK,DKK,DJF,DOP,XCD,EGP,SVC,ERN,ETB,EUR,FKP,FJD,GMD,GEL,GHS,GIP,GTQ,GNF,GYD,HTG,HNL,HKD,HUF,ISK,INR,IDR,IRR,IQD,ILS,JMD,JPY,JOD,KZT,KES,KWD,LAK,LBP,LSL,LRD,LYD,MOP,MKD,MGA,MWK,MYR,MVR,MRU,MUR,MXN,MDL,MNT,MAD,MZN,MMK,NAD,NPR,NZD,NIO,NGN,KPW,NOK,ARS,PKR,PAB,PGK,PYG,PEN,UYU,PHP,PLN,GBP,QAR,OMR,RON,RUB,RWF,WST,SAR,RSD,SCR,SLL,SGD,STN,SBD,SOS,ZAR,KRW,LKR,SHP,SDG,SRD,SZL,SEK,CHF,SYP,TWD,TJS,TZS,THB,TOP,TTD,TND,TRY,TMT,AED,UGX,UAH,USD,UZS,VUV,VND,YER,CNY,ZMW,ZWL" }
+credit = { country = "AF,DZ,AW,AU,AZ,BS,BH,BD,BB,BZ,BM,BT,BO,BA,BW,BR,BN,BG,BI,KH,CA,CV,KY,CL,CO,KM,CD,CR,CZ,DK,DJ,ST,DO,EC,EG,SV,ER,ET,FK,FJ,GM,GE,GH,GI,GT,GN,GY,HT,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IL,IT,JM,JP,JO,KZ,KE,KW,LA,LB,LS,LR,LY,LT,MO,MK,MG,MW,MY,MV,MR,MU,MX,MD,MN,MA,MZ,MM,NA,NZ,NI,NG,KP,NO,AR,PK,PG,PY,PE,UY,PH,PL,GB,QA,OM,RO,RU,RW,WS,SG,ST,ZA,KR,LK,SH,SD,SR,SZ,SE,CH,SY,TW,TJ,TZ,TH,TT,TN,TR,UG,UA,US,UZ,VU,VE,VN,ZM,ZW", currency = "AFN,DZD,ANG,AWG,AUD,AZN,BSD,BHD,BDT,BBD,BZD,BMD,BTN,BOB,BAM,BWP,BRL,BND,BGN,BIF,KHR,CAD,CVE,KYD,XOF,XAF,XPF,CLP,COP,KMF,CDF,CRC,EUR,CZK,DKK,DJF,DOP,XCD,EGP,SVC,ERN,ETB,EUR,FKP,FJD,GMD,GEL,GHS,GIP,GTQ,GNF,GYD,HTG,HNL,HKD,HUF,ISK,INR,IDR,IRR,IQD,ILS,JMD,JPY,JOD,KZT,KES,KWD,LAK,LBP,LSL,LRD,LYD,MOP,MKD,MGA,MWK,MYR,MVR,MRU,MUR,MXN,MDL,MNT,MAD,MZN,MMK,NAD,NPR,NZD,NIO,NGN,KPW,NOK,ARS,PKR,PAB,PGK,PYG,PEN,UYU,PHP,PLN,GBP,QAR,OMR,RON,RUB,RWF,WST,SAR,RSD,SCR,SLL,SGD,STN,SBD,SOS,ZAR,KRW,LKR,SHP,SDG,SRD,SZL,SEK,CHF,SYP,TWD,TJS,TZS,THB,TOP,TTD,TND,TRY,TMT,AED,UGX,UAH,USD,UZS,VUV,VND,YER,CNY,ZMW,ZWL" }
+google_pay = { country = "AL, DZ, AS, AO, AG, AR, AU, AT, AZ, BH, BY, BE, BR, BG, CA, CL, CO, HR, CZ, DK, DO, EG, EE, FI, FR, DE, GR, HK, HU, IN, ID, IE, IL, IT, JP, JO, KZ, KE, KW, LV, LB, LT, LU, MY, MX, NL, NZ, NO, OM, PK, PA, PE, PH, PL, PT, QA, RO, RU, SA, SG, SK, ZA, ES, LK, SE, CH, TW, TH, TR, UA, AE, GB, US, UY, VN", currency = "DZD, AOA, USD, XCD, ARS, AUD, AZN, EUR, BHD, BYN, BRL, BGN, CAD, CLP, COP, CZK, DKK, DOP, EGP, HKD, HUF, INR, IDR, ILS, JPY, JOD, KZT, KES, KWD, LBP, MYR, MXN, NZD, NOK, OMR, PKR, PAB, PEN, PHP, PLN, QAR, RON, RUB, SAR, SGD, ZAR, LKR, SEK, CHF, TWD, THB, TRY, UAH, AED, GBP, UYU, VND" }
+apple_pay = { country = "EG, MA, ZA, AU, CN, HK, JP, MO, MY, MN, NZ, SG, TW, VN, AM, AT, AZ, BY, BE, BG, HR, CY, CZ, DK, EE, FO, FI, FR, GE, DE, GR, GL, GG, HU, IE, IS, IM, IT, KZ, JE, LV, LI, LT, LU, MT, MD, MC, ME, NL, NO, PL, PT, RO, SM, RS, SK, SI, ES, SE, CH, UA, GB, VA, AR, BR, CL, CO, CR, DO, EC, SV, GT, HN, MX, PA, PY, PE, BS, BH, IL, JO, KW, OM, PS, QA, SA, AE, CA, US, PR", currency = "EGP, MAD, ZAR, AUD, CNY, HKD, JPY, MOP, MYR, MNT, NZD, SGD, KRW, TWD, VND, EUR, AZN, BYN, BGN, CZK, DKK, GEL, GBP, HUF, ISK, KZT, CHF, MDL, NOK, PLN, RON, RSD, SEK, UAH, ARS, BRL, CLP, COP, CRC, DOP, USD, GTQ, HNL, MXN, PAB, PYG, PEN, BSD, UYU, BHD, ILS, JOD, KWD, OMR, QAR, SAR, AED, CAD" }
+
+[pm_filters.worldpayxml]
+debit = { country = "AF,DZ,AW,AU,AZ,BS,BH,BD,BB,BZ,BM,BT,BO,BA,BW,BR,BN,BG,BI,KH,CA,CV,KY,CL,CO,KM,CD,CR,CZ,DK,DJ,ST,DO,EC,EG,SV,ER,ET,FK,FJ,GM,GE,GH,GI,GT,GN,GY,HT,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IL,IT,JM,JP,JO,KZ,KE,KW,LA,LB,LS,LR,LY,LT,MO,MK,MG,MW,MY,MV,MR,MU,MX,MD,MN,MA,MZ,MM,NA,NZ,NI,NG,KP,NO,AR,PK,PG,PY,PE,UY,PH,PL,GB,QA,OM,RO,RU,RW,WS,SG,ST,ZA,KR,LK,SH,SD,SR,SZ,SE,CH,SY,TW,TJ,TZ,TH,TT,TN,TR,UG,UA,US,UZ,VU,VE,VN,ZM,ZW", currency = "AFN,DZD,ANG,AWG,AUD,AZN,BSD,BHD,BDT,BBD,BZD,BMD,BTN,BOB,BAM,BWP,BRL,BND,BGN,BIF,KHR,CAD,CVE,KYD,XOF,XAF,XPF,CLP,COP,KMF,CDF,CRC,EUR,CZK,DKK,DJF,DOP,XCD,EGP,SVC,ERN,ETB,EUR,FKP,FJD,GMD,GEL,GHS,GIP,GTQ,GNF,GYD,HTG,HNL,HKD,HUF,ISK,INR,IDR,IRR,IQD,ILS,JMD,JPY,JOD,KZT,KES,KWD,LAK,LBP,LSL,LRD,LYD,MOP,MKD,MGA,MWK,MYR,MVR,MRU,MUR,MXN,MDL,MNT,MAD,MZN,MMK,NAD,NPR,NZD,NIO,NGN,KPW,NOK,ARS,PKR,PAB,PGK,PYG,PEN,UYU,PHP,PLN,GBP,QAR,OMR,RON,RUB,RWF,WST,SAR,RSD,SCR,SLL,SGD,STN,SBD,SOS,ZAR,KRW,LKR,SHP,SDG,SRD,SZL,SEK,CHF,SYP,TWD,TJS,TZS,THB,TOP,TTD,TND,TRY,TMT,AED,UGX,UAH,USD,UZS,VUV,VND,YER,CNY,ZMW,ZWL" }
+credit = { country = "AF,DZ,AW,AU,AZ,BS,BH,BD,BB,BZ,BM,BT,BO,BA,BW,BR,BN,BG,BI,KH,CA,CV,KY,CL,CO,KM,CD,CR,CZ,DK,DJ,ST,DO,EC,EG,SV,ER,ET,FK,FJ,GM,GE,GH,GI,GT,GN,GY,HT,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IL,IT,JM,JP,JO,KZ,KE,KW,LA,LB,LS,LR,LY,LT,MO,MK,MG,MW,MY,MV,MR,MU,MX,MD,MN,MA,MZ,MM,NA,NZ,NI,NG,KP,NO,AR,PK,PG,PY,PE,UY,PH,PL,GB,QA,OM,RO,RU,RW,WS,SG,ST,ZA,KR,LK,SH,SD,SR,SZ,SE,CH,SY,TW,TJ,TZ,TH,TT,TN,TR,UG,UA,US,UZ,VU,VE,VN,ZM,ZW", currency = "AFN,DZD,ANG,AWG,AUD,AZN,BSD,BHD,BDT,BBD,BZD,BMD,BTN,BOB,BAM,BWP,BRL,BND,BGN,BIF,KHR,CAD,CVE,KYD,XOF,XAF,XPF,CLP,COP,KMF,CDF,CRC,EUR,CZK,DKK,DJF,DOP,XCD,EGP,SVC,ERN,ETB,EUR,FKP,FJD,GMD,GEL,GHS,GIP,GTQ,GNF,GYD,HTG,HNL,HKD,HUF,ISK,INR,IDR,IRR,IQD,ILS,JMD,JPY,JOD,KZT,KES,KWD,LAK,LBP,LSL,LRD,LYD,MOP,MKD,MGA,MWK,MYR,MVR,MRU,MUR,MXN,MDL,MNT,MAD,MZN,MMK,NAD,NPR,NZD,NIO,NGN,KPW,NOK,ARS,PKR,PAB,PGK,PYG,PEN,UYU,PHP,PLN,GBP,QAR,OMR,RON,RUB,RWF,WST,SAR,RSD,SCR,SLL,SGD,STN,SBD,SOS,ZAR,KRW,LKR,SHP,SDG,SRD,SZL,SEK,CHF,SYP,TWD,TJS,TZS,THB,TOP,TTD,TND,TRY,TMT,AED,UGX,UAH,USD,UZS,VUV,VND,YER,CNY,ZMW,ZWL" }
+google_pay = { country = "AF,DZ,AW,AU,AZ,BS,BH,BD,BB,BZ,BM,BT,BO,BA,BW,BR,BN,BG,BI,KH,CA,CV,KY,CL,CO,KM,CD,CR,CZ,DK,DJ,ST,DO,EC,EG,SV,ER,ET,FK,FJ,GM,GE,GH,GI,GT,GN,GY,HT,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IL,IT,JM,JP,JO,KZ,KE,KW,LA,LB,LS,LR,LY,LT,MO,MK,MG,MW,MY,MV,MR,MU,MX,MD,MN,MA,MZ,MM,NA,NZ,NI,NG,KP,NO,AR,PK,PG,PY,PE,UY,PH,PL,GB,QA,OM,RO,RU,RW,WS,SG,ST,ZA,KR,LK,SH,SD,SR,SZ,SE,CH,SY,TW,TJ,TZ,TH,TT,TN,TR,UG,UA,US,UZ,VU,VE,VN,ZM,ZW", currency = "AFN,DZD,ANG,AWG,AUD,AZN,BSD,BHD,BDT,BBD,BZD,BMD,BTN,BOB,BAM,BWP,BRL,BND,BGN,BIF,KHR,CAD,CVE,KYD,XOF,XAF,XPF,CLP,COP,KMF,CDF,CRC,EUR,CZK,DKK,DJF,DOP,XCD,EGP,SVC,ERN,ETB,EUR,FKP,FJD,GMD,GEL,GHS,GIP,GTQ,GNF,GYD,HTG,HNL,HKD,HUF,ISK,INR,IDR,IRR,IQD,ILS,JMD,JPY,JOD,KZT,KES,KWD,LAK,LBP,LSL,LRD,LYD,MOP,MKD,MGA,MWK,MYR,MVR,MRU,MUR,MXN,MDL,MNT,MAD,MZN,MMK,NAD,NPR,NZD,NIO,NGN,KPW,NOK,ARS,PKR,PAB,PGK,PYG,PEN,UYU,PHP,PLN,GBP,QAR,OMR,RON,RUB,RWF,WST,SAR,RSD,SCR,SLL,SGD,STN,SBD,SOS,ZAR,KRW,LKR,SHP,SDG,SRD,SZL,SEK,CHF,SYP,TWD,TJS,TZS,THB,TOP,TTD,TND,TRY,TMT,AED,UGX,UAH,USD,UZS,VUV,VND,YER,CNY,ZMW,ZWL" }
+apple_pay = { country = "AF,DZ,AW,AU,AZ,BS,BH,BD,BB,BZ,BM,BT,BO,BA,BW,BR,BN,BG,BI,KH,CA,CV,KY,CL,CO,KM,CD,CR,CZ,DK,DJ,ST,DO,EC,EG,SV,ER,ET,FK,FJ,GM,GE,GH,GI,GT,GN,GY,HT,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IL,IT,JM,JP,JO,KZ,KE,KW,LA,LB,LS,LR,LY,LT,MO,MK,MG,MW,MY,MV,MR,MU,MX,MD,MN,MA,MZ,MM,NA,NZ,NI,NG,KP,NO,AR,PK,PG,PY,PE,UY,PH,PL,GB,QA,OM,RO,RU,RW,WS,SG,ST,ZA,KR,LK,SH,SD,SR,SZ,SE,CH,SY,TW,TJ,TZ,TH,TT,TN,TR,UG,UA,US,UZ,VU,VE,VN,ZM,ZW", currency = "AFN,DZD,ANG,AWG,AUD,AZN,BSD,BHD,BDT,BBD,BZD,BMD,BTN,BOB,BAM,BWP,BRL,BND,BGN,BIF,KHR,CAD,CVE,KYD,XOF,XAF,XPF,CLP,COP,KMF,CDF,CRC,EUR,CZK,DKK,DJF,DOP,XCD,EGP,SVC,ERN,ETB,EUR,FKP,FJD,GMD,GEL,GHS,GIP,GTQ,GNF,GYD,HTG,HNL,HKD,HUF,ISK,INR,IDR,IRR,IQD,ILS,JMD,JPY,JOD,KZT,KES,KWD,LAK,LBP,LSL,LRD,LYD,MOP,MKD,MGA,MWK,MYR,MVR,MRU,MUR,MXN,MDL,MNT,MAD,MZN,MMK,NAD,NPR,NZD,NIO,NGN,KPW,NOK,ARS,PKR,PAB,PGK,PYG,PEN,UYU,PHP,PLN,GBP,QAR,OMR,RON,RUB,RWF,WST,SAR,RSD,SCR,SLL,SGD,STN,SBD,SOS,ZAR,KRW,LKR,SHP,SDG,SRD,SZL,SEK,CHF,SYP,TWD,TJS,TZS,THB,TOP,TTD,TND,TRY,TMT,AED,UGX,UAH,USD,UZS,VUV,VND,YER,CNY,ZMW,ZWL" }
+
+[pm_filters.worldpayvantiv]
+debit = { country = "AF,DZ,AW,AU,AZ,BS,BH,BD,BB,BZ,BM,BT,BO,BA,BW,BR,BN,BG,BI,KH,CA,CV,KY,CL,CO,KM,CD,CR,CZ,DK,DJ,ST,DO,EC,EG,SV,ER,ET,FK,FJ,GM,GE,GH,GI,GT,GN,GY,HT,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IL,IT,JM,JP,JO,KZ,KE,KW,LA,LB,LS,LR,LY,LT,MO,MK,MG,MW,MY,MV,MR,MU,MX,MD,MN,MA,MZ,MM,NA,NZ,NI,NG,KP,NO,AR,PK,PG,PY,PE,UY,PH,PL,GB,QA,OM,RO,RU,RW,WS,SG,ST,ZA,KR,LK,SH,SD,SR,SZ,SE,CH,SY,TW,TJ,TZ,TH,TT,TN,TR,UG,UA,US,UZ,VU,VE,VN,ZM,ZW", currency = "AFN,DZD,ANG,AWG,AUD,AZN,BSD,BHD,BDT,BBD,BZD,BMD,BTN,BOB,BAM,BWP,BRL,BND,BGN,BIF,KHR,CAD,CVE,KYD,XOF,XAF,XPF,CLP,COP,KMF,CDF,CRC,EUR,CZK,DKK,DJF,DOP,XCD,EGP,SVC,ERN,ETB,EUR,FKP,FJD,GMD,GEL,GHS,GIP,GTQ,GNF,GYD,HTG,HNL,HKD,HUF,ISK,INR,IDR,IRR,IQD,ILS,JMD,JPY,JOD,KZT,KES,KWD,LAK,LBP,LSL,LRD,LYD,MOP,MKD,MGA,MWK,MYR,MVR,MRU,MUR,MXN,MDL,MNT,MAD,MZN,MMK,NAD,NPR,NZD,NIO,NGN,KPW,NOK,ARS,PKR,PAB,PGK,PYG,PEN,UYU,PHP,PLN,GBP,QAR,OMR,RON,RUB,RWF,WST,SAR,RSD,SCR,SLL,SGD,STN,SBD,SOS,ZAR,KRW,LKR,SHP,SDG,SRD,SZL,SEK,CHF,SYP,TWD,TJS,TZS,THB,TOP,TTD,TND,TRY,TMT,AED,UGX,UAH,USD,UZS,VUV,VND,YER,CNY,ZMW,ZWL" }
+credit = { country = "AF,DZ,AW,AU,AZ,BS,BH,BD,BB,BZ,BM,BT,BO,BA,BW,BR,BN,BG,BI,KH,CA,CV,KY,CL,CO,KM,CD,CR,CZ,DK,DJ,ST,DO,EC,EG,SV,ER,ET,FK,FJ,GM,GE,GH,GI,GT,GN,GY,HT,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IL,IT,JM,JP,JO,KZ,KE,KW,LA,LB,LS,LR,LY,LT,MO,MK,MG,MW,MY,MV,MR,MU,MX,MD,MN,MA,MZ,MM,NA,NZ,NI,NG,KP,NO,AR,PK,PG,PY,PE,UY,PH,PL,GB,QA,OM,RO,RU,RW,WS,SG,ST,ZA,KR,LK,SH,SD,SR,SZ,SE,CH,SY,TW,TJ,TZ,TH,TT,TN,TR,UG,UA,US,UZ,VU,VE,VN,ZM,ZW", currency = "AFN,DZD,ANG,AWG,AUD,AZN,BSD,BHD,BDT,BBD,BZD,BMD,BTN,BOB,BAM,BWP,BRL,BND,BGN,BIF,KHR,CAD,CVE,KYD,XOF,XAF,XPF,CLP,COP,KMF,CDF,CRC,EUR,CZK,DKK,DJF,DOP,XCD,EGP,SVC,ERN,ETB,EUR,FKP,FJD,GMD,GEL,GHS,GIP,GTQ,GNF,GYD,HTG,HNL,HKD,HUF,ISK,INR,IDR,IRR,IQD,ILS,JMD,JPY,JOD,KZT,KES,KWD,LAK,LBP,LSL,LRD,LYD,MOP,MKD,MGA,MWK,MYR,MVR,MRU,MUR,MXN,MDL,MNT,MAD,MZN,MMK,NAD,NPR,NZD,NIO,NGN,KPW,NOK,ARS,PKR,PAB,PGK,PYG,PEN,UYU,PHP,PLN,GBP,QAR,OMR,RON,RUB,RWF,WST,SAR,RSD,SCR,SLL,SGD,STN,SBD,SOS,ZAR,KRW,LKR,SHP,SDG,SRD,SZL,SEK,CHF,SYP,TWD,TJS,TZS,THB,TOP,TTD,TND,TRY,TMT,AED,UGX,UAH,USD,UZS,VUV,VND,YER,CNY,ZMW,ZWL" }
+apple_pay = { country = "AF,DZ,AW,AU,AZ,BS,BH,BD,BB,BZ,BM,BT,BO,BA,BW,BR,BN,BG,BI,KH,CA,CV,KY,CL,CO,KM,CD,CR,CZ,DK,DJ,ST,DO,EC,EG,SV,ER,ET,FK,FJ,GM,GE,GH,GI,GT,GN,GY,HT,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IL,IT,JM,JP,JO,KZ,KE,KW,LA,LB,LS,LR,LY,LT,MO,MK,MG,MW,MY,MV,MR,MU,MX,MD,MN,MA,MZ,MM,NA,NZ,NI,NG,KP,NO,AR,PK,PG,PY,PE,UY,PH,PL,GB,QA,OM,RO,RU,RW,WS,SG,ST,ZA,KR,LK,SH,SD,SR,SZ,SE,CH,SY,TW,TJ,TZ,TH,TT,TN,TR,UG,UA,US,UZ,VU,VE,VN,ZM,ZW", currency = "AFN,DZD,ANG,AWG,AUD,AZN,BSD,BHD,BDT,BBD,BZD,BMD,BTN,BOB,BAM,BWP,BRL,BND,BGN,BIF,KHR,CAD,CVE,KYD,XOF,XAF,XPF,CLP,COP,KMF,CDF,CRC,EUR,CZK,DKK,DJF,DOP,XCD,EGP,SVC,ERN,ETB,EUR,FKP,FJD,GMD,GEL,GHS,GIP,GTQ,GNF,GYD,HTG,HNL,HKD,HUF,ISK,INR,IDR,IRR,IQD,ILS,JMD,JPY,JOD,KZT,KES,KWD,LAK,LBP,LSL,LRD,LYD,MOP,MKD,MGA,MWK,MYR,MVR,MRU,MUR,MXN,MDL,MNT,MAD,MZN,MMK,NAD,NPR,NZD,NIO,NGN,KPW,NOK,ARS,PKR,PAB,PGK,PYG,PEN,UYU,PHP,PLN,GBP,QAR,OMR,RON,RUB,RWF,WST,SAR,RSD,SCR,SLL,SGD,STN,SBD,SOS,ZAR,KRW,LKR,SHP,SDG,SRD,SZL,SEK,CHF,SYP,TWD,TJS,TZS,THB,TOP,TTD,TND,TRY,TMT,AED,UGX,UAH,USD,UZS,VUV,VND,YER,CNY,ZMW,ZWL" }
+google_pay = { country = "AF,DZ,AW,AU,AZ,BS,BH,BD,BB,BZ,BM,BT,BO,BA,BW,BR,BN,BG,BI,KH,CA,CV,KY,CL,CO,KM,CD,CR,CZ,DK,DJ,ST,DO,EC,EG,SV,ER,ET,FK,FJ,GM,GE,GH,GI,GT,GN,GY,HT,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IL,IT,JM,JP,JO,KZ,KE,KW,LA,LB,LS,LR,LY,LT,MO,MK,MG,MW,MY,MV,MR,MU,MX,MD,MN,MA,MZ,MM,NA,NZ,NI,NG,KP,NO,AR,PK,PG,PY,PE,UY,PH,PL,GB,QA,OM,RO,RU,RW,WS,SG,ST,ZA,KR,LK,SH,SD,SR,SZ,SE,CH,SY,TW,TJ,TZ,TH,TT,TN,TR,UG,UA,US,UZ,VU,VE,VN,ZM,ZW", currency = "AFN,DZD,ANG,AWG,AUD,AZN,BSD,BHD,BDT,BBD,BZD,BMD,BTN,BOB,BAM,BWP,BRL,BND,BGN,BIF,KHR,CAD,CVE,KYD,XOF,XAF,XPF,CLP,COP,KMF,CDF,CRC,EUR,CZK,DKK,DJF,DOP,XCD,EGP,SVC,ERN,ETB,EUR,FKP,FJD,GMD,GEL,GHS,GIP,GTQ,GNF,GYD,HTG,HNL,HKD,HUF,ISK,INR,IDR,IRR,IQD,ILS,JMD,JPY,JOD,KZT,KES,KWD,LAK,LBP,LSL,LRD,LYD,MOP,MKD,MGA,MWK,MYR,MVR,MRU,MUR,MXN,MDL,MNT,MAD,MZN,MMK,NAD,NPR,NZD,NIO,NGN,KPW,NOK,ARS,PKR,PAB,PGK,PYG,PEN,UYU,PHP,PLN,GBP,QAR,OMR,RON,RUB,RWF,WST,SAR,RSD,SCR,SLL,SGD,STN,SBD,SOS,ZAR,KRW,LKR,SHP,SDG,SRD,SZL,SEK,CHF,SYP,TWD,TJS,TZS,THB,TOP,TTD,TND,TRY,TMT,AED,UGX,UAH,USD,UZS,VUV,VND,YER,CNY,ZMW,ZWL" }
+
+[pm_filters.worldpaymodular]
+google_pay = { country = "AL, DZ, AS, AO, AG, AR, AU, AT, AZ, BH, BY, BE, BR, BG, CA, CL, CO, HR, CZ, DK, DO, EG, EE, FI, FR, DE, GR, HK, HU, IN, ID, IE, IL, IT, JP, JO, KZ, KE, KW, LV, LB, LT, LU, MY, MX, NL, NZ, NO, OM, PK, PA, PE, PH, PL, PT, QA, RO, RU, SA, SG, SK, ZA, ES, LK, SE, CH, TW, TH, TR, UA, AE, GB, US, UY, VN", currency = "DZD, AOA, USD, XCD, ARS, AUD, AZN, EUR, BHD, BYN, BRL, BGN, CAD, CLP, COP, CZK, DKK, DOP, EGP, HKD, HUF, INR, IDR, ILS, JPY, JOD, KZT, KES, KWD, LBP, MYR, MXN, NZD, NOK, OMR, PKR, PAB, PEN, PHP, PLN, QAR, RON, RUB, SAR, SGD, ZAR, LKR, SEK, CHF, TWD, THB, TRY, UAH, AED, GBP, UYU, VND" }
+apple_pay = { country = "EG, MA, ZA, AU, CN, HK, JP, MO, MY, MN, NZ, SG, TW, VN, AM, AT, AZ, BY, BE, BG, HR, CY, CZ, DK, EE, FO, FI, FR, GE, DE, GR, GL, GG, HU, IE, IS, IM, IT, KZ, JE, LV, LI, LT, LU, MT, MD, MC, ME, NL, NO, PL, PT, RO, SM, RS, SK, SI, ES, SE, CH, UA, GB, VA, AR, BR, CL, CO, CR, DO, EC, SV, GT, HN, MX, PA, PY, PE, BS, BH, IL, JO, KW, OM, PS, QA, SA, AE, CA, US, PR", currency = "EGP, MAD, ZAR, AUD, CNY, HKD, JPY, MOP, MYR, MNT, NZD, SGD, KRW, TWD, VND, EUR, AZN, BYN, BGN, CZK, DKK, GEL, GBP, HUF, ISK, KZT, CHF, MDL, NOK, PLN, RON, RSD, SEK, UAH, ARS, BRL, CLP, COP, CRC, DOP, USD, GTQ, HNL, MXN, PAB, PYG, PEN, BSD, UYU, BHD, ILS, JOD, KWD, OMR, QAR, SAR, AED, CAD" }
+
+[pm_filters.calida]
+bluecode = { country = "AT,BE,BG,HR,CY,CZ,DK,EE,FI,FR,DE,GR,HU,IE,IT,LV,LT,LU,MT,NL,PL,PT,RO,SK,SI,ES,SE,IS,LI,NO", currency = "EUR" }
+
+[file_upload_config]
+bucket_name = ""
+region = ""
+
+[pm_filters.forte]
+credit = { country = "US, CA", currency = "CAD,USD"}
+debit = { country = "US, CA", currency = "CAD,USD"}
+
+[pm_filters.nordea]
+sepa = { country = "DK,FI,NO,SE", currency = "DKK,EUR,NOK,SEK" }
+
+[pm_filters.fiuu]
+duit_now = { country = "MY", currency = "MYR" }
+apple_pay = { country = "MY", currency = "MYR" }
+google_pay = { country = "MY", currency = "MYR" }
+online_banking_fpx = { country = "MY", currency = "MYR" }
+credit = { country = "CN,HK,ID,MY,PH,SG,TH,TW,VN", currency = "CNY,HKD,IDR,MYR,PHP,SGD,THB,TWD,VND" }
+debit = { country = "CN,HK,ID,MY,PH,SG,TH,TW,VN", currency = "CNY,HKD,IDR,MYR,PHP,SGD,THB,TWD,VND" }
+
+[pm_filters.inespay]
+sepa = { country = "ES", currency = "EUR"}
+
+[pm_filters.bluesnap]
+credit = { country = "AD,AE,AG,AL,AM,AO,AR,AT,AU,AZ,BA,BB,BD,BE,BG,BH,BI,BJ,BN,BO,BR,BS,BT,BW,BY,BZ,CA,CD,CF,CG,CH,CI,CL,CM,CN,CO,CR,CV,CY,CZ,DE,DK,DJ,DM,DO,DZ,EC,EE,EG,ER,ES,ET,FI,FJ,FM,FR,GA,GB,GD,GE,GG,GH,GM,GN,GQ,GR,GT,GW,GY,HN,HR,HT,HU,ID,IE,IL,IN,IS,IT,JM,JP,JO,KE,KG,KH,KI,KM,KN,KR,KW,KZ,LA,LB,LC,LI,LK,LR,LS,LT,LU,LV,MA,MC,MD,ME,MG,MH,MK,ML,MM,MN,MR,MT,MU,MV,MW,MX,MY,MZ,NA,NE,NG,NI,NL,NO,NP,NR,NZ,OM,PA,PE,PG,PH,PK,PL,PS,PT,PW,PY,QA,RO,RS,RW,SA,SB,SC,SE,SG,SI,SK,SL,SM,SN,SO,SR,SS,ST,SV,SZ,TD,TG,TH,TJ,TL,TM,TN,TO,TR,TT,TV,TZ,UA,UG,US,UY,UZ,VA,VC,VE,VN,VU,WS,ZA,ZM,ZW", currency = "AED,AFN,ALL,AMD,ANG,ARS,AUD,AWG,BAM,BBD,BGN,BHD,BMD,BND,BOB,BRL,BSD,BWP,CAD,CHF,CLP,CNY,COP,CRC,CZK,DKK,DOP,DZD,EGP,EUR,FJD,GBP,GEL,GIP,GTQ,HKD,HUF,IDR,ILS,INR,ISK,JMD,JPY,KES,KHR,KRW,KWD,KYD,KZT,LBP,LKR,MAD,MDL,MKD,MUR,MWK,MXN,MYR,NAD,NGN,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PLN,PKR,QAR,RON,RSD,RUB,SAR,SCR,SDG,SEK,SGD,THB,TND,TRY,TTD,TWD,TZS,UAH,USD,UYU,UZS,VND,XAF,XCD,XOF,ZAR"}
+google_pay = { country = "AL, DZ, AS, AO, AG, AR, AU, AT, AZ, BH, BY, BE, BR, BG, CL, CO, HR, CZ, DK, DO, EG, EE, FI, FR, DE, GR, HK, HU, IN, ID, IE, IL, IT, JP, JO, KZ, KE, KW, LV, LB, LT, LU, MY, MX, NL, NZ, NO, OM, PK, PA, PE, PH, PL, PT, QA, RO, RU, SA, SG, SK, ZA, ES, LK, SE, CH, TW, TH, TR, UA, AE, GB, US, UY, VN", currency = "ALL, DZD, USD, XCD, ARS, AUD, EUR, BHD, BRL, BGN, CAD, CLP, COP, CZK, DKK, DOP, EGP, HKD, HUF, INR, IDR, ILS, JPY, KZT, KES, KWD, LBP, MYR, MXN, NZD, NOK, OMR, PKR, PAB, PEN, PHP, PLN, QAR, RON, RUB, SAR, SGD, ZAR, LKR, SEK, CHF, TWD, THB, TRY, UAH, AED, GBP, UYU, VND"}
+apple_pay = { country = "EG, MA, ZA, AU, HK, JP, MO, MY, MN, NZ, SG, KR, TW, VN, AM, AT, AZ, BY, BE, BG, HR, CY, DK, EE, FO, FI, FR, GE, DE, GR, GL, GG, HU, IS, IE, IM, IT , KZ, JE, LV, LI, LT, LU, MT, MD, MC, ME, NL, NO, PL, PT, RO, SM, RS, SI, ES, SE, CH, UA, GB, VA, AR, BR, CL, CO, CR, DO, EC, SV, GT, HN, MX, PA, PY, PE, BS, UY, BH, IL, JO, KW, OM, PS, QA, SA, AE, CA, US", currency = "EGP, MAD, ZAR, AUD, CNY, HKD, JPY, MYR, NZD, SGD, KRW, TWD, VND, AMD, EUR, BGN, CZK, DKK, GEL, GBP, HUF, ISK, KZT, CHF, MDL, NOK, PLN, RON, RSD, SEK, UAH, GBP, ARS, BRL, CLP, COP, CRC, DOP, USD, GTQ, MXN, PAB, PEN, BSD, UYU, BHD, ILS, KWD, OMR, QAR, SAR, AED, CAD"}
+
+[pm_filters.fiserv]
+credit = {country = "AU,NZ,CN,HK,IN,LK,KR,MY,SG,GB,BE,FR,DE,IT,ME,NL,PL,ES,ZA,AR,BR,CO,MX,PA,UY,US,CA", currency = "AFN,ALL,DZD,AOA,ARS,AMD,AWG,AUD,AZN,BSD,BHD,BDT,BBD,BYN,BZD,BMD,BTN,BOB,VES,BAM,BWP,BRL,BND,BGN,BIF,KHR,CAD,CVE,KYD,XAF,CLP,CNY,COP,KMF,CDF,CRC,HRK,CUP,CZK,DKK,DJF,DOP,XCD,EGP,ERN,ETB,EUR,FKP,FJD,XPF,GMD,GEL,GHS,GIP,GTQ,GNF,GYD,HTG,HNL,HKD,HUF,ISK,INR,IDR,IRR,IQD,ILS,JMD,JPY,JOD,KZT,KES,KGS,KWD,LAK,LBP,LSL,LRD,LYD,MOP,MKD,MGA,MWK,MYR,MVR,MRU,MUR,MXN,MDL,MNT,MAD,MZN,MMK,NAD,NPR,ANG,NZD,NIO,NGN,VUV,KPW,NOK,OMR,PKR,PAB,PGK,PYG,PEN,PHP,PLN,GBP,QAR,RON,RUB,RWF,SHP,SVC,WST,STN,SAR,RSD,SCR,SLL,SGD,SBD,SOS,ZAR,KRW,SSP,LKR,SDG,SRD,SZL,SEK,CHF,SYP,TWD,TJS,TZS,THB,TOP,TTD,TND,TRY,TMT,UGX,UAH,AED,USD,UYU,UZS,VND,XOF,YER,ZMW,ZWL"}
+debit = {country = "AU,NZ,CN,HK,IN,LK,KR,MY,SG,GB,BE,FR,DE,IT,ME,NL,PL,ES,ZA,AR,BR,CO,MX,PA,UY,US,CA", currency = "AFN,ALL,DZD,AOA,ARS,AMD,AWG,AUD,AZN,BSD,BHD,BDT,BBD,BYN,BZD,BMD,BTN,BOB,VES,BAM,BWP,BRL,BND,BGN,BIF,KHR,CAD,CVE,KYD,XAF,CLP,CNY,COP,KMF,CDF,CRC,HRK,CUP,CZK,DKK,DJF,DOP,XCD,EGP,ERN,ETB,EUR,FKP,FJD,XPF,GMD,GEL,GHS,GIP,GTQ,GNF,GYD,HTG,HNL,HKD,HUF,ISK,INR,IDR,IRR,IQD,ILS,JMD,JPY,JOD,KZT,KES,KGS,KWD,LAK,LBP,LSL,LRD,LYD,MOP,MKD,MGA,MWK,MYR,MVR,MRU,MUR,MXN,MDL,MNT,MAD,MZN,MMK,NAD,NPR,ANG,NZD,NIO,NGN,VUV,KPW,NOK,OMR,PKR,PAB,PGK,PYG,PEN,PHP,PLN,GBP,QAR,RON,RUB,RWF,SHP,SVC,WST,STN,SAR,RSD,SCR,SLL,SGD,SBD,SOS,ZAR,KRW,SSP,LKR,SDG,SRD,SZL,SEK,CHF,SYP,TWD,TJS,TZS,THB,TOP,TTD,TND,TRY,TMT,UGX,UAH,AED,USD,UYU,UZS,VND,XOF,YER,ZMW,ZWL"}
+paypal = { currency = "AUD,EUR,BRL,CAD,CNY,EUR,EUR,EUR,GBP,HKD,INR,EUR,JPY,MYR,EUR,NZD,PHP,PLN,SGD,USD", country = "AU, BE, BR, CA, CN, DE, ES, FR, GB, HK, IN, IT, JP, MY, NL, NZ, PH, PL, SG, US" }
+google_pay = { country = "AU,AT,BE,BR,CA,CN,HK,MY,NZ,SG,US", currency = "AUD,EUR,EUR,BRL,CAD,CNY,HKD,MYR,NZD,SGD,USD" }
+apple_pay = { country = "AU,NZ,CN,HK,JP,SG,MY,KR,TW,VN,GB,IE,FR,DE,IT,ES,PT,NL,BE,LU,AT,CH,SE,FI,DK,NO,PL,CZ,SK,HU,LT,LV,EE,GR,RO,BG,HR,SI,MT,CY,IS,LI,MC,SM,VA,US,CA,MX,BR,AR,CL,CO,PE,UY,CR,PA,DO,EC,SV,GT,HN,BS,PR,AE,SA,QA,KW,BH,OM,IL,JO,PS,EG,MA,ZA,GE,AM,AZ,MD,ME,MK,AL,BA,RS,UA", currency = "AUD,BRL,CAD,CHF,CZK,DKK,EUR,GBP,HKD,HUF,ILS,JPY,MXN,NOK,NZD,PHP,PLN,SEK,SGD,THB,TWD,USD" }
+
+
+[pm_filters.amazonpay]
+amazon_pay = { country = "US", currency = "USD" }
+
+[pm_filters.rapyd]
+apple_pay = { country = "BR, CA, CL, CO, DO, SV, MX, PE, PT, US, AT, BE, BG, HR, CY, CZ, DO, DK, EE, FI, FR, GE, DE, GR, GL, HU, IS, IE, IL, IT, LV, LI, LT, LU, MT, MD, MC, ME, NL, NO, PL, RO, SM, SK, SI, ZA, ES, SE, CH, GB, VA, AU, HK, JP, MY, NZ, SG, KR, TW, VN", currency = "AMD, AUD, BGN, BRL, BYN, CAD, CHF, CLP, CNY, COP, CRC, CZK, DKK, DOP, EUR, GBP, GEL, GTQ, HUF, ISK, JPY, KRW, MDL, MXN, MYR, NOK, PAB, PEN, PLN, PYG, RON, RSD, SEK, SGD, TWD, UAH, USD, UYU, VND, ZAR" }
+google_pay = { country = "BR, CA, CL, CO, DO, MX, PE, PT, US, AT, BE, BG, HR, CZ, DK, EE, FI, FR, DE, GR, HU, IE, IL, IT, LV, LT, LU, NZ, NO, GB, PL, RO, RU, SK, ZA, ES, SE, CH, TR, AU, HK, IN, ID, JP, MY, PH, SG, TW, TH, VN", currency = "AUD, BGN, BRL, BYN, CAD, CHF, CLP, COP, CZK, DKK, DOP, EUR, GBP, HUF, IDR, JPY, KES, MXN, MYR, NOK, PAB, PEN, PHP, PLN, RON, RUB, SEK, SGD, THB, TRY, TWD, UAH, USD, UYU, VND, ZAR" }
+credit = { country = "AE,AF,AG,AI,AL,AM,AO,AQ,AR,AS,AT,AU,AW,AX,AZ,BA,BB,BD,BE,BF,BG,BH,BI,BJ,BL,BM,BN,BO,BQ,BR,BS,BT,BV,BW,BY,BZ,CA,CC,CD,CF,CG,CH,CI,CK,CL,CM,CN,CO,CR,CU,CV,CW,CX,CY,CZ,DE,DJ,DK,DM,DO,DZ,EC,EE,EG,EH,ER,ES,ET,FI,FJ,FK,FM,FO,FR,GA,GB,GD,GE,GF,GG,GH,GI,GL,GM,GN,GP,GQ,GR,GT,GU,GW,GY,HK,HM,HN,HR,HT,HU,ID,IE,IL,IM,IN,IO,IQ,IR,IS,IT,JE,JM,JO,JP,KE,KG,KH,KI,KM,KN,KP,KR,KW,KY,KZ,LA,LB,LC,LI,LK,LR,LS,LT,LU,LV,LY,MA,MC,MD,ME,MF,MG,MH,MK,ML,MM,MN,MO,MP,MQ,MR,MS,MT,MU,MV,MW,MX,MY,MZ,NA,NC,NE,NF,NG,NI,NL,NO,NP,NR,NU,NZ,OM,PA,PE,PF,PG,PH,PK,PL,PM,PN,PR,PS,PT,PW,PY,QA,RE,RO,RS,RU,RW,SA,SB,SC,SD,SE,SG,SH,SI,SJ,SK,SL,SM,SN,SO,SR,SS,ST,SV,SX,SY,SZ,TC,TD,TF,TG,TH,TJ,TL,TM,TN,TO,TR,TT,TV,TW,TZ,UA,UG,UM,US,UY,UZ,VA,VC,VE,VG,VI,VN,VU,WF,WS,YE,YT,ZA,ZM,ZW", currency = "AED,AUD,BDT,BGN,BND,BOB,BRL,BWP,CAD,CHF,CNY,COP,CZK,DKK,EGP,EUR,FJD,GBP,GEL,GHS,HKD,HRK,HUF,IDR,ILS,INR,IQD,IRR,ISK,JPY,KES,KRW,KWD,KZT,LAK,LKR,MAD,MDL,MMK,MOP,MXN,MYR,MZN,NAD,NGN,NOK,NPR,NZD,PEN,PHP,PKR,PLN,QAR,RON,RSD,RUB,RWF,SAR,SCR,SEK,SGD,SLL,THB,TRY,TWD,TZS,UAH,UGX,USD,UYU,VND,XAF,XOF,ZAR,ZMW,MWK" }
+debit = { country = "AE,AF,AG,AI,AL,AM,AO,AQ,AR,AS,AT,AU,AW,AX,AZ,BA,BB,BD,BE,BF,BG,BH,BI,BJ,BL,BM,BN,BO,BQ,BR,BS,BT,BV,BW,BY,BZ,CA,CC,CD,CF,CG,CH,CI,CK,CL,CM,CN,CO,CR,CU,CV,CW,CX,CY,CZ,DE,DJ,DK,DM,DO,DZ,EC,EE,EG,EH,ER,ES,ET,FI,FJ,FK,FM,FO,FR,GA,GB,GD,GE,GF,GG,GH,GI,GL,GM,GN,GP,GQ,GR,GT,GU,GW,GY,HK,HM,HN,HR,HT,HU,ID,IE,IL,IM,IN,IO,IQ,IR,IS,IT,JE,JM,JO,JP,KE,KG,KH,KI,KM,KN,KP,KR,KW,KY,KZ,LA,LB,LC,LI,LK,LR,LS,LT,LU,LV,LY,MA,MC,MD,ME,MF,MG,MH,MK,ML,MM,MN,MO,MP,MQ,MR,MS,MT,MU,MV,MW,MX,MY,MZ,NA,NC,NE,NF,NG,NI,NL,NO,NP,NR,NU,NZ,OM,PA,PE,PF,PG,PH,PK,PL,PM,PN,PR,PS,PT,PW,PY,QA,RE,RO,RS,RU,RW,SA,SB,SC,SD,SE,SG,SH,SI,SJ,SK,SL,SM,SN,SO,SR,SS,ST,SV,SX,SY,SZ,TC,TD,TF,TG,TH,TJ,TL,TM,TN,TO,TR,TT,TV,TW,TZ,UA,UG,UM,US,UY,UZ,VA,VC,VE,VG,VI,VN,VU,WF,WS,YE,YT,ZA,ZM,ZW", currency = "AED,AUD,BDT,BGN,BND,BOB,BRL,BWP,CAD,CHF,CNY,COP,CZK,DKK,EGP,EUR,FJD,GBP,GEL,GHS,HKD,HRK,HUF,IDR,ILS,INR,IQD,IRR,ISK,JPY,KES,KRW,KWD,KZT,LAK,LKR,MAD,MDL,MMK,MOP,MXN,MYR,MZN,NAD,NGN,NOK,NPR,NZD,PEN,PHP,PKR,PLN,QAR,RON,RSD,RUB,RWF,SAR,SCR,SEK,SGD,SLL,THB,TRY,TWD,TZS,UAH,UGX,USD,UYU,VND,XAF,XOF,ZAR,ZMW,MWK" }
+
+[pm_filters.bamboraapac]
+credit = { country = "AD,AE,AG,AL,AM,AO,AR,AT,AU,AZ,BA,BB,BD,BE,BG,BH,BI,BJ,BN,BO,BR,BS,BT,BW,BY,BZ,CA,CD,CF,CG,CH,CI,CL,CM,CN,CO,CR,CV,CY,CZ,DE,DK,DJ,DM,DO,DZ,EC,EE,EG,ER,ES,ET,FI,FJ,FM,FR,GA,GB,GD,GE,GG,GH,GM,GN,GQ,GR,GT,GW,GY,HN,HR,HT,HU,ID,IE,IL,IN,IS,IT,JM,JP,JO,KE,KG,KH,KI,KM,KN,KR,KW,KZ,LA,LB,LC,LI,LK,LR,LS,LT,LU,LV,MA,MC,MD,ME,MG,MH,MK,ML,MM,MN,MR,MT,MU,MV,MW,MX,MY,MZ,NA,NE,NG,NI,NL,NO,NP,NR,NZ,OM,PA,PE,PG,PH,PK,PL,PS,PT,PW,PY,QA,RO,RS,RW,SA,SB,SC,SE,SG,SI,SK,SL,SM,SN,SO,SR,SS,ST,SV,SZ,TD,TG,TH,TJ,TL,TM,TN,TO,TR,TT,TV,TZ,UA,UG,US,UY,UZ,VA,VC,VE,VN,VU,WS,ZA,ZM,ZW", currency = "AED,AUD,BDT,BGN,BND,BOB,BRL,BWP,CAD,CHF,CNY,COP,CZK,DKK,EGP,EUR,FJD,GBP,GEL,GHS,HKD,HRK,HUF,IDR,ILS,INR,IQD,IRR,ISK,JPY,KES,KRW,KWD,KZT,LAK,LKR,MAD,MDL,MMK,MOP,MXN,MYR,MZN,NAD,NGN,NOK,NPR,NZD,PEN,PHP,PKR,PLN,QAR,RON,RSD,RUB,RWF,SAR,SCR,SEK,SGD,SLL,THB,TRY,TWD,TZS,UAH,UGX,USD,UYU,VND,XAF,XOF,ZAR,ZMW,MWK" }
+debit = { country = "AD,AE,AG,AL,AM,AO,AR,AT,AU,AZ,BA,BB,BD,BE,BG,BH,BI,BJ,BN,BO,BR,BS,BT,BW,BY,BZ,CA,CD,CF,CG,CH,CI,CL,CM,CN,CO,CR,CV,CY,CZ,DE,DK,DJ,DM,DO,DZ,EC,EE,EG,ER,ES,ET,FI,FJ,FM,FR,GA,GB,GD,GE,GG,GH,GM,GN,GQ,GR,GT,GW,GY,HN,HR,HT,HU,ID,IE,IL,IN,IS,IT,JM,JP,JO,KE,KG,KH,KI,KM,KN,KR,KW,KZ,LA,LB,LC,LI,LK,LR,LS,LT,LU,LV,MA,MC,MD,ME,MG,MH,MK,ML,MM,MN,MR,MT,MU,MV,MW,MX,MY,MZ,NA,NE,NG,NI,NL,NO,NP,NR,NZ,OM,PA,PE,PG,PH,PK,PL,PS,PT,PW,PY,QA,RO,RS,RW,SA,SB,SC,SE,SG,SI,SK,SL,SM,SN,SO,SR,SS,ST,SV,SZ,TD,TG,TH,TJ,TL,TM,TN,TO,TR,TT,TV,TZ,UA,UG,US,UY,UZ,VA,VC,VE,VN,VU,WS,ZA,ZM,ZW", currency = "AED,AUD,BDT,BGN,BND,BOB,BRL,BWP,CAD,CHF,CNY,COP,CZK,DKK,EGP,EUR,FJD,GBP,GEL,GHS,HKD,HRK,HUF,IDR,ILS,INR,IQD,IRR,ISK,JPY,KES,KRW,KWD,KZT,LAK,LKR,MAD,MDL,MMK,MOP,MXN,MYR,MZN,NAD,NGN,NOK,NPR,NZD,PEN,PHP,PKR,PLN,QAR,RON,RSD,RUB,RWF,SAR,SCR,SEK,SGD,SLL,THB,TRY,TWD,TZS,UAH,UGX,USD,UYU,VND,XAF,XOF,ZAR,ZMW,MWK" }
+
+[pm_filters.gocardless]
+ach = { country = "US", currency = "USD" }
+becs = { country = "AU", currency = "AUD" }
+sepa = { country = "AU,AT,BE,BG,CA,HR,CY,CZ,DK,FI,FR,DE,HU,IT,LU,MT,NL,NZ,NO,PL,PT,IE,RO,SK,SI,ZA,ES,SE,CH,GB", currency = "GBP,EUR,SEK,DKK,AUD,NZD,CAD" }
+
+[pm_filters.powertranz]
+credit = { country = "AE,AF,AG,AI,AL,AM,AO,AQ,AR,AS,AT,AU,AW,AX,AZ,BA,BB,BD,BE,BF,BG,BH,BI,BJ,BL,BM,BN,BO,BQ,BR,BS,BT,BV,BW,BY,BZ,CA,CC,CD,CF,CG,CH,CI,CK,CL,CM,CN,CO,CR,CU,CV,CW,CX,CY,CZ,DE,DJ,DK,DM,DO,DZ,EC,EE,EG,EH,ER,ES,ET,FI,FJ,FK,FM,FO,FR,GA,GB,GD,GE,GF,GG,GH,GI,GL,GM,GN,GP,GQ,GR,GT,GU,GW,GY,HK,HM,HN,HR,HT,HU,ID,IE,IL,IM,IN,IO,IQ,IR,IS,IT,JE,JM,JO,JP,KE,KG,KH,KI,KM,KN,KP,KR,KW,KY,KZ,LA,LB,LC,LI,LK,LR,LS,LT,LU,LV,LY,MA,MC,MD,ME,MF,MG,MH,MK,ML,MM,MN,MO,MP,MQ,MR,MS,MT,MU,MV,MW,MX,MY,MZ,NA,NC,NE,NF,NG,NI,NL,NO,NP,NR,NU,NZ,OM,PA,PE,PF,PG,PH,PK,PL,PM,PN,PR,PS,PT,PW,PY,QA,RE,RO,RS,RU,RW,SA,SB,SC,SD,SE,SG,SH,SI,SJ,SK,SL,SM,SN,SO,SR,SS,ST,SV,SX,SY,SZ,TC,TD,TF,TG,TH,TJ,TL,TM,TN,TO,TR,TT,TV,TW,TZ,UA,UG,UM,US,UY,UZ,VA,VC,VE,VG,VI,VN,VU,WF,WS,YE,YT,ZA,ZM,ZW", currency = "BBD,BMD,BSD,CRC,GTQ,HNL,JMD,KYD,TTD,USD" }
+debit = { country = "AE,AF,AG,AI,AL,AM,AO,AQ,AR,AS,AT,AU,AW,AX,AZ,BA,BB,BD,BE,BF,BG,BH,BI,BJ,BL,BM,BN,BO,BQ,BR,BS,BT,BV,BW,BY,BZ,CA,CC,CD,CF,CG,CH,CI,CK,CL,CM,CN,CO,CR,CU,CV,CW,CX,CY,CZ,DE,DJ,DK,DM,DO,DZ,EC,EE,EG,EH,ER,ES,ET,FI,FJ,FK,FM,FO,FR,GA,GB,GD,GE,GF,GG,GH,GI,GL,GM,GN,GP,GQ,GR,GT,GU,GW,GY,HK,HM,HN,HR,HT,HU,ID,IE,IL,IM,IN,IO,IQ,IR,IS,IT,JE,JM,JO,JP,KE,KG,KH,KI,KM,KN,KP,KR,KW,KY,KZ,LA,LB,LC,LI,LK,LR,LS,LT,LU,LV,LY,MA,MC,MD,ME,MF,MG,MH,MK,ML,MM,MN,MO,MP,MQ,MR,MS,MT,MU,MV,MW,MX,MY,MZ,NA,NC,NE,NF,NG,NI,NL,NO,NP,NR,NU,NZ,OM,PA,PE,PF,PG,PH,PK,PL,PM,PN,PR,PS,PT,PW,PY,QA,RE,RO,RS,RU,RW,SA,SB,SC,SD,SE,SG,SH,SI,SJ,SK,SL,SM,SN,SO,SR,SS,ST,SV,SX,SY,SZ,TC,TD,TF,TG,TH,TJ,TL,TM,TN,TO,TR,TT,TV,TW,TZ,UA,UG,UM,US,UY,UZ,VA,VC,VE,VG,VI,VN,VU,WF,WS,YE,YT,ZA,ZM,ZW", currency = "BBD,BMD,BSD,CRC,GTQ,HNL,JMD,KYD,TTD,USD" }
+
+[pm_filters.worldline]
+giropay = { country = "DE", currency = "EUR" }
+ideal = { country = "NL", currency = "EUR" }
+credit = { country = "AD,AE,AF,AG,AI,AL,AM,AO,AQ,AR,AS,AT,AU,AW,AX,AZ,BA,BB,BD,BE,BF,BG,BH,BI,BJ,BL,BM,BN,BO,BQ,BR,BS,BT,BV,BW,BY,BZ,CA,CC,CD,CF,CG,CH,CI,CK,CL,CM,CN,CO,CR,CU,CV,CW,CX,CY,CZ,DE,DJ,DK,DM,DO,DZ,EC,EE,EG,EH,ER,ES,ET,FI,FJ,FK,FM,FO,FR,GA,GB,GD,GE,GF,GG,GH,GI,GL,GM,GN,GP,GQ,GR,GT,GU,GW,GY,HK,HM,HN,HR,HT,HU,ID,IE,IL,IM,IN,IO,IQ,IR,IS,IT,JE,JM,JO,JP,KE,KG,KH,KI,KM,KN,KP,KR,KW,KY,KZ,LA,LB,LC,LI,LK,LR,LS,LT,LU,LV,LY,MA,MC,MD,ME,MF,MG,MH,MK,ML,MM,MN,MO,MP,MQ,MR,MS,MT,MU,MV,MW,MX,MY,MZ,NA,NC,NE,NF,NG,NI,NL,NO,NP,NR,NU,NZ,OM,PA,PE,PF,PG,PH,PK,PL,PM,PN,PR,PS,PT,PW,PY,QA,RE,RO,RS,RU,RW,SA,SB,SC,SD,SE,SG,SH,SI,SJ,SK,SL,SM,SN,SO,SR,SS,ST,SV,SX,SY,SZ,TC,TD,TF,TG,TH,TJ,TL,TM,TN,TO,TR,TT,TV,TW,TZ,UA,UG,UM,US,UY,UZ,VA,VC,VE,VG,VI,VN,VU,WF,WS,YE,YT,ZA,ZM,ZW", currency = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BYN,BZD,CAD,CDF,CHF,CLP,CNY,COP,CRC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLL,SOS,SRD,SSP,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL" }
+debit = { country = "AD,AE,AF,AG,AI,AL,AM,AO,AQ,AR,AS,AT,AU,AW,AX,AZ,BA,BB,BD,BE,BF,BG,BH,BI,BJ,BL,BM,BN,BO,BQ,BR,BS,BT,BV,BW,BY,BZ,CA,CC,CD,CF,CG,CH,CI,CK,CL,CM,CN,CO,CR,CU,CV,CW,CX,CY,CZ,DE,DJ,DK,DM,DO,DZ,EC,EE,EG,EH,ER,ES,ET,FI,FJ,FK,FM,FO,FR,GA,GB,GD,GE,GF,GG,GH,GI,GL,GM,GN,GP,GQ,GR,GT,GU,GW,GY,HK,HM,HN,HR,HT,HU,ID,IE,IL,IM,IN,IO,IQ,IR,IS,IT,JE,JM,JO,JP,KE,KG,KH,KI,KM,KN,KP,KR,KW,KY,KZ,LA,LB,LC,LI,LK,LR,LS,LT,LU,LV,LY,MA,MC,MD,ME,MF,MG,MH,MK,ML,MM,MN,MO,MP,MQ,MR,MS,MT,MU,MV,MW,MX,MY,MZ,NA,NC,NE,NF,NG,NI,NL,NO,NP,NR,NU,NZ,OM,PA,PE,PF,PG,PH,PK,PL,PM,PN,PR,PS,PT,PW,PY,QA,RE,RO,RS,RU,RW,SA,SB,SC,SD,SE,SG,SH,SI,SJ,SK,SL,SM,SN,SO,SR,SS,ST,SV,SX,SY,SZ,TC,TD,TF,TG,TH,TJ,TL,TM,TN,TO,TR,TT,TV,TW,TZ,UA,UG,UM,US,UY,UZ,VA,VC,VE,VG,VI,VN,VU,WF,WS,YE,YT,ZA,ZM,ZW", currency = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BYN,BZD,CAD,CDF,CHF,CLP,CNY,COP,CRC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLL,SOS,SRD,SSP,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL" }
+
+[pm_filters.shift4]
+eps = { country = "AT", currency = "EUR" }
+giropay = { country = "DE", currency = "EUR" }
+ideal = { country = "NL", currency = "EUR" }
+sofort = { country = "AT,BE,CH,DE,ES,FI,FR,GB,IT,NL,PL,SE", currency = "CHF,EUR" }
+credit = { country = "AD,AE,AF,AG,AI,AL,AM,AO,AQ,AR,AS,AT,AU,AW,AX,AZ,BA,BB,BD,BE,BF,BG,BH,BI,BJ,BL,BM,BN,BO,BQ,BR,BS,BT,BV,BW,BY,BZ,CA,CC,CD,CF,CG,CH,CI,CK,CL,CM,CN,CO,CR,CU,CV,CW,CX,CY,CZ,DE,DJ,DK,DM,DO,DZ,EC,EE,EG,EH,ER,ES,ET,FI,FJ,FK,FM,FO,FR,GA,GB,GD,GE,GF,GG,GH,GI,GL,GM,GN,GP,GQ,GR,GT,GU,GW,GY,HK,HM,HN,HR,HT,HU,ID,IE,IL,IM,IN,IO,IQ,IR,IS,IT,JE,JM,JO,JP,KE,KG,KH,KI,KM,KN,KP,KR,KW,KY,KZ,LA,LB,LC,LI,LK,LR,LS,LT,LU,LV,LY,MA,MC,MD,ME,MF,MG,MH,MK,ML,MM,MN,MO,MP,MQ,MR,MS,MT,MU,MV,MW,MX,MY,MZ,NA,NC,NE,NF,NG,NI,NL,NO,NP,NR,NU,NZ,OM,PA,PE,PF,PG,PH,PK,PL,PM,PN,PR,PS,PT,PW,PY,QA,RE,RO,RS,RU,RW,SA,SB,SC,SD,SE,SG,SH,SI,SJ,SK,SL,SM,SN,SO,SR,SS,ST,SV,SX,SY,SZ,TC,TD,TF,TG,TH,TJ,TL,TM,TN,TO,TR,TT,TV,TW,TZ,UA,UG,UM,US,UY,UZ,VA,VC,VE,VG,VI,VN,VU,WF,WS,YE,YT,ZA,ZM,ZW", currency = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BYN,BZD,CAD,CDF,CHF,CLP,CNY,COP,CRC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLL,SOS,SRD,SSP,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL" }
+debit = { country = "AD,AE,AF,AG,AI,AL,AM,AO,AQ,AR,AS,AT,AU,AW,AX,AZ,BA,BB,BD,BE,BF,BG,BH,BI,BJ,BL,BM,BN,BO,BQ,BR,BS,BT,BV,BW,BY,BZ,CA,CC,CD,CF,CG,CH,CI,CK,CL,CM,CN,CO,CR,CU,CV,CW,CX,CY,CZ,DE,DJ,DK,DM,DO,DZ,EC,EE,EG,EH,ER,ES,ET,FI,FJ,FK,FM,FO,FR,GA,GB,GD,GE,GF,GG,GH,GI,GL,GM,GN,GP,GQ,GR,GT,GU,GW,GY,HK,HM,HN,HR,HT,HU,ID,IE,IL,IM,IN,IO,IQ,IR,IS,IT,JE,JM,JO,JP,KE,KG,KH,KI,KM,KN,KP,KR,KW,KY,KZ,LA,LB,LC,LI,LK,LR,LS,LT,LU,LV,LY,MA,MC,MD,ME,MF,MG,MH,MK,ML,MM,MN,MO,MP,MQ,MR,MS,MT,MU,MV,MW,MX,MY,MZ,NA,NC,NE,NF,NG,NI,NL,NO,NP,NR,NU,NZ,OM,PA,PE,PF,PG,PH,PK,PL,PM,PN,PR,PS,PT,PW,PY,QA,RE,RO,RS,RU,RW,SA,SB,SC,SD,SE,SG,SH,SI,SJ,SK,SL,SM,SN,SO,SR,SS,ST,SV,SX,SY,SZ,TC,TD,TF,TG,TH,TJ,TL,TM,TN,TO,TR,TT,TV,TW,TZ,UA,UG,UM,US,UY,UZ,VA,VC,VE,VG,VI,VN,VU,WF,WS,YE,YT,ZA,ZM,ZW", currency = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BYN,BZD,CAD,CDF,CHF,CLP,CNY,COP,CRC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLL,SOS,SRD,SSP,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL" }
+boleto = { country = "BR", currency = "BRL" }
+trustly = { currency = "CZK,DKK,EUR,GBP,NOK,SEK" }
+ali_pay = { country = "CN", currency = "CNY" }
+we_chat_pay = { country = "CN", currency = "CNY" }
+klarna = { currency = "EUR,GBP,CHF,SEK" }
+blik = { country = "PL", currency = "PLN" }
+crypto_currency = { currency = "USD,GBP,AED" }
+paysera = { currency = "EUR" }
+skrill = { currency = "USD" }
+
+[pm_filters.placetopay]
+credit = { country = "BE,CH,CO,CR,EC,HN,MX,PA,PR,UY", currency = "CLP,COP,USD"}
+debit = { country = "BE,CH,CO,CR,EC,HN,MX,PA,PR,UY", currency = "CLP,COP,USD"}
+
+[pm_filters.coingate]
+crypto_currency = { country = "AL, AD, AT, BE, BA, BG, HR, CZ, DK, EE, FI, FR, DE, GR, HU, IS, IE, IT, LV, LT, LU, MT, MD, NL, NO, PL, PT, RO, RS, SK, SI, ES, SE, CH, UA, GB, AR, BR, CL, CO, CR, DO, SV, GD, MX, PE, LC, AU, NZ, CY, HK, IN, IL, JP, KR, QA, SA, SG, EG", currency = "EUR, USD, GBP" }
+
+[pm_filters.paystack]
+eft = { country = "NG, ZA, GH, KE, CI", currency = "NGN, GHS, ZAR, KES, USD" }
+
+[pm_filters.santander]
+pix = { country = "BR", currency = "BRL" }
+boleto = { country = "BR", currency = "BRL" }
+
+[pm_filters.boku]
+dana = { country = "ID", currency = "IDR" }
+gcash = { country = "PH", currency = "PHP" }
+go_pay = { country = "ID", currency = "IDR" }
+kakao_pay = { country = "KR", currency = "KRW" }
+momo = { country = "VN", currency = "VND" }
+
+[pm_filters.nmi]
+credit = { country = "EG,ZA,BH,CY,HK,IN,ID,IL,JP,JO,KW,MY,PK,PH,SA,SG,KR,TW,TH,TR,AE,VN,AL,AD,AM,AT,AZ,BY,BE,BA,BG,HR,CZ,DK,EE,FI,FR,GE,DE,GR,HU,IS,IE,IT,KZ,LV,LI,LT,LU,MT,MD,MC,ME,NL,MK,NO,PL,PT,RO,SM,RS,SK,SI,ES,SE,CH,TR,GB,VA,AG,BS,BB,BZ,CA,SV,GT,HN,MX,PA,KN,LC,TT,US,AU,NZ,AR,BO,BR,CL,CO,EC,GY,PY,PE,SR,UY,VE", currency = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BYN,BZD,CAD,CDF,CHF,CLF,CLP,CNY,COP,CRC,CUC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLE,SLL,SOS,SRD,SSP,STD,STN,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL" }
+debit = { country = "EG,ZA,BH,CY,HK,IN,ID,IL,JP,JO,KW,MY,PK,PH,SA,SG,KR,TW,TH,TR,AE,VN,AL,AD,AM,AT,AZ,BY,BE,BA,BG,HR,CZ,DK,EE,FI,FR,GE,DE,GR,HU,IS,IE,IT,KZ,LV,LI,LT,LU,MT,MD,MC,ME,NL,MK,NO,PL,PT,RO,SM,RS,SK,SI,ES,SE,CH,TR,GB,VA,AG,BS,BB,BZ,CA,SV,GT,HN,MX,PA,KN,LC,TT,US,AU,NZ,AR,BO,BR,CL,CO,EC,GY,PY,PE,SR,UY,VE", currency = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BYN,BZD,CAD,CDF,CHF,CLF,CLP,CNY,COP,CRC,CUC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLE,SLL,SOS,SRD,SSP,STD,STN,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL" }
+apple_pay = { country = "EG,ZA,BH,CY,HK,IN,ID,IL,JP,JO,KW,MY,PK,PH,SA,SG,KR,TW,TH,TR,AE,VN,AL,AD,AM,AT,AZ,BY,BE,BA,BG,HR,CZ,DK,EE,FI,FR,GE,DE,GR,HU,IS,IE,IT,KZ,LV,LI,LT,LU,MT,MD,MC,ME,NL,MK,NO,PL,PT,RO,SM,RS,SK,SI,ES,SE,CH,TR,GB,VA,AG,BS,BB,BZ,CA,SV,GT,HN,MX,PA,KN,LC,TT,US,AU,NZ,AR,BO,BR,CL,CO,EC,GY,PY,PE,SR,UY,VE", currency = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BYN,BZD,CAD,CDF,CHF,CLF,CLP,CNY,COP,CRC,CUC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLE,SLL,SOS,SRD,SSP,STD,STN,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL" }
+google_pay = { country = "EG,ZA,BH,CY,HK,IN,ID,IL,JP,JO,KW,MY,PK,PH,SA,SG,KR,TW,TH,TR,AE,VN,AL,AD,AM,AT,AZ,BY,BE,BA,BG,HR,CZ,DK,EE,FI,FR,GE,DE,GR,HU,IS,IE,IT,KZ,LV,LI,LT,LU,MT,MD,MC,ME,NL,MK,NO,PL,PT,RO,SM,RS,SK,SI,ES,SE,CH,TR,GB,VA,AG,BS,BB,BZ,CA,SV,GT,HN,MX,PA,KN,LC,TT,US,AU,NZ,AR,BO,BR,CL,CO,EC,GY,PY,PE,SR,UY,VE", currency = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BYN,BZD,CAD,CDF,CHF,CLF,CLP,CNY,COP,CRC,CUC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLE,SLL,SOS,SRD,SSP,STD,STN,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL" }
+
+[pm_filters.paypal]
+credit = { country = "DZ,AO,BJ,BW,BF,BI,CM,CV,TD,KM,CI,CD,DJ,EG,ER,ET,GA,GM,GN,GW,KE,LS,MG,MW,ML,MR,MU,MA,MZ,NA,NE,NG,CG,RW,SH,ST,SN,SC,SL,SO,ZA,SZ,TZ,TG,TN,UG,ZM,ZW,AI,AG,AR,AW,BS,BB,BZ,BM,BO,BR,VG,CA,KY,CL,CO,CR,DM,DO,EC,SV,FK,GL,GD,GT,GY,HN,JM,MX,MS,NI,PA,PY,PE,KN,LC,PM,VC,SR,TT,TC,US,UY,VE,AM,AU,BH,BT,BN,KH,CN,CK,FJ,PF,HK,IN,ID,IL,JP,JO,KZ,KI,KW,KG,LA,MY,MV,MH,FM,MN,NR,NP,NC,NZ,NU,NF,OM,PW,PG,PH,PN,QA,WS,SA,SG,SB,KR,LK,TW,TJ,TH,TO,TM,TV,AE,VU,VN,WF,YE,AL,AD,AT,AZ,BY,BE,BA,BG,HR,CY,CZ,DK,EE,FO,FI,FR,GE,DE,GR,HU,IS,IE,IT,LV,LI,LT,LU,MK,MT,MD,MC,ME,NL,NO,PL,PT,RO,RU,SM,RS,SK,SI,ES,SJ,SE,CH,UA,GB,VA", currency = "AUD,BRL,CAD,CNY,CZK,DKK,EUR,HKD,HUF,ILS,JPY,MYR,MXN,TWD,NZD,NOK,PHP,PLN,GBP,SGD,SEK,CHF,THB,USD" }
+debit = { country = "DZ,AO,BJ,BW,BF,BI,CM,CV,TD,KM,CI,CD,DJ,EG,ER,ET,GA,GM,GN,GW,KE,LS,MG,MW,ML,MR,MU,MA,MZ,NA,NE,NG,CG,RW,SH,ST,SN,SC,SL,SO,ZA,SZ,TZ,TG,TN,UG,ZM,ZW,AI,AG,AR,AW,BS,BB,BZ,BM,BO,BR,VG,CA,KY,CL,CO,CR,DM,DO,EC,SV,FK,GL,GD,GT,GY,HN,JM,MX,MS,NI,PA,PY,PE,KN,LC,PM,VC,SR,TT,TC,US,UY,VE,AM,AU,BH,BT,BN,KH,CN,CK,FJ,PF,HK,IN,ID,IL,JP,JO,KZ,KI,KW,KG,LA,MY,MV,MH,FM,MN,NR,NP,NC,NZ,NU,NF,OM,PW,PG,PH,PN,QA,WS,SA,SG,SB,KR,LK,TW,TJ,TH,TO,TM,TV,AE,VU,VN,WF,YE,AL,AD,AT,AZ,BY,BE,BA,BG,HR,CY,CZ,DK,EE,FO,FI,FR,GE,DE,GR,HU,IS,IE,IT,LV,LI,LT,LU,MK,MT,MD,MC,ME,NL,NO,PL,PT,RO,RU,SM,RS,SK,SI,ES,SJ,SE,CH,UA,GB,VA", currency = "AUD,BRL,CAD,CNY,CZK,DKK,EUR,HKD,HUF,ILS,JPY,MYR,MXN,TWD,NZD,NOK,PHP,PLN,GBP,SGD,SEK,CHF,THB,USD" }
+paypal = { country = "DZ,AO,BJ,BW,BF,BI,CM,CV,TD,KM,CI,CD,DJ,EG,ER,ET,GA,GM,GN,GW,KE,LS,MG,MW,ML,MR,MU,MA,MZ,NA,NE,NG,CG,RW,SH,ST,SN,SC,SL,SO,ZA,SZ,TZ,TG,TN,UG,ZM,ZW,AI,AG,AR,AW,BS,BB,BZ,BM,BO,BR,VG,CA,KY,CL,CO,CR,DM,DO,EC,SV,FK,GL,GD,GT,GY,HN,JM,MX,MS,NI,PA,PY,PE,KN,LC,PM,VC,SR,TT,TC,US,UY,VE,AM,AU,BH,BT,BN,KH,CN,CK,FJ,PF,HK,IN,ID,IL,JP,JO,KZ,KI,KW,KG,LA,MY,MV,MH,FM,MN,NR,NP,NC,NZ,NU,NF,OM,PW,PG,PH,PN,QA,WS,SA,SG,SB,KR,LK,TW,TJ,TH,TO,TM,TV,AE,VU,VN,WF,YE,AL,AD,AT,AZ,BY,BE,BA,BG,HR,CY,CZ,DK,EE,FO,FI,FR,GE,DE,GR,HU,IS,IE,IT,LV,LI,LT,LU,MK,MT,MD,MC,ME,NL,NO,PL,PT,RO,RU,SM,RS,SK,SI,ES,SJ,SE,CH,UA,GB,VA", currency = "AUD,BRL,CAD,CNY,CZK,DKK,EUR,HKD,HUF,ILS,JPY,MYR,MXN,TWD,NZD,NOK,PHP,PLN,GBP,SGD,SEK,CHF,THB,USD" }
+eps = { country = "DZ,AO,BJ,BW,BF,BI,CM,CV,TD,KM,CI,CD,DJ,EG,ER,ET,GA,GM,GN,GW,KE,LS,MG,MW,ML,MR,MU,MA,MZ,NA,NE,NG,CG,RW,SH,ST,SN,SC,SL,SO,ZA,SZ,TZ,TG,TN,UG,ZM,ZW,AI,AG,AR,AW,BS,BB,BZ,BM,BO,BR,VG,CA,KY,CL,CO,CR,DM,DO,EC,SV,FK,GL,GD,GT,GY,HN,JM,MX,MS,NI,PA,PY,PE,KN,LC,PM,VC,SR,TT,TC,US,UY,VE,AM,AU,BH,BT,BN,KH,CN,CK,FJ,PF,HK,IN,ID,IL,JP,JO,KZ,KI,KW,KG,LA,MY,MV,MH,FM,MN,NR,NP,NC,NZ,NU,NF,OM,PW,PG,PH,PN,QA,WS,SA,SG,SB,KR,LK,TW,TJ,TH,TO,TM,TV,AE,VU,VN,WF,YE,AL,AD,AT,AZ,BY,BE,BA,BG,HR,CY,CZ,DK,EE,FO,FI,FR,GE,DE,GR,HU,IS,IE,IT,LV,LI,LT,LU,MK,MT,MD,MC,ME,NL,NO,PL,PT,RO,RU,SM,RS,SK,SI,ES,SJ,SE,CH,UA,GB,VA", currency = "AUD,BRL,CAD,CNY,CZK,DKK,EUR,HKD,HUF,ILS,JPY,MYR,MXN,TWD,NZD,NOK,PHP,PLN,GBP,SGD,SEK,CHF,THB,USD" }
+giropay = { currency = "EUR" }
+ideal = { currency = "EUR" }
+sofort = { country = "DZ,AO,BJ,BW,BF,BI,CM,CV,TD,KM,CI,CD,DJ,EG,ER,ET,GA,GM,GN,GW,KE,LS,MG,MW,ML,MR,MU,MA,MZ,NA,NE,NG,CG,RW,SH,ST,SN,SC,SL,SO,ZA,SZ,TZ,TG,TN,UG,ZM,ZW,AI,AG,AR,AW,BS,BB,BZ,BM,BO,BR,VG,CA,KY,CL,CO,CR,DM,DO,EC,SV,FK,GL,GD,GT,GY,HN,JM,MX,MS,NI,PA,PY,PE,KN,LC,PM,VC,SR,TT,TC,US,UY,VE,AM,AU,BH,BT,BN,KH,CN,CK,FJ,PF,HK,IN,ID,IL,JP,JO,KZ,KI,KW,KG,LA,MY,MV,MH,FM,MN,NR,NP,NC,NZ,NU,NF,OM,PW,PG,PH,PN,QA,WS,SA,SG,SB,KR,LK,TW,TJ,TH,TO,TM,TV,AE,VU,VN,WF,YE,AL,AD,AT,AZ,BY,BE,BA,BG,HR,CY,CZ,DK,EE,FO,FI,FR,GE,DE,GR,HU,IS,IE,IT,LV,LI,LT,LU,MK,MT,MD,MC,ME,NL,NO,PL,PT,RO,RU,SM,RS,SK,SI,ES,SJ,SE,CH,UA,GB,VA", currency = "AUD,BRL,CAD,CNY,CZK,DKK,EUR,HKD,HUF,ILS,JPY,MYR,MXN,TWD,NZD,NOK,PHP,PLN,GBP,SGD,SEK,CHF,THB,USD" }
+
+[pm_filters.datatrans]
+credit = { country = "AL,AD,AM,AT,AZ,BY,BE,BA,BG,CH,CY,CZ,DE,DK,EE,ES,FI,FR,GB,GE,GR,HR,HU,IE,IS,IT,KZ,LI,LT,LU,LV,MC,MD,ME,MK,MT,NL,NO,PL,PT,RO,RU,SE,SI,SK,SM,TR,UA,VA", currency = "BHD,BIF,CHF,DJF,EUR,GBP,GNF,IQD,ISK,JPY,JOD,KMF,KRW,KWD,LYD,OMR,PYG,RWF,TND,UGX,USD,VND,VUV,XAF,XOF,XPF" }
+debit = { country = "AL,AD,AM,AT,AZ,BY,BE,BA,BG,CH,CY,CZ,DE,DK,EE,ES,FI,FR,GB,GE,GR,HR,HU,IE,IS,IT,KZ,LI,LT,LU,LV,MC,MD,ME,MK,MT,NL,NO,PL,PT,RO,RU,SE,SI,SK,SM,TR,UA,VA", currency = "BHD,BIF,CHF,DJF,EUR,GBP,GNF,IQD,ISK,JPY,JOD,KMF,KRW,KWD,LYD,OMR,PYG,RWF,TND,UGX,USD,VND,VUV,XAF,XOF,XPF" }
+
+[pm_filters.payme]
+credit = { country = "US,CA,IL,GB", currency = "ILS,USD,EUR" }
+debit = { country = "US,CA,IL,GB", currency = "ILS,USD,EUR" }
+apple_pay = { country = "US,CA,IL,GB", currency = "ILS,USD,EUR" }
+
+[pm_filters.paysafe]
+apple_pay = {country = "AF,AX,AL,DZ,AS,AD,AO,AI,AQ,AG,AR,AM,AW,AU,AT,AZ,BS,BH,BD,BB,BY,BE,BZ,BJ,BM,BT,BO,BQ,BA,BW,BV,BR,IO,BN,BG,BF,BI,KH,CM,CA,CV,KY,CF,TD,CL,CN,CX,CC,CO,KM,CG,CD,CK,CR,CI,HR,CU,CW,CY,CZ,DK,DJ,DM,DO,EC,EG,SV,GQ,ER,EE,ET,FK,FO,FJ,FI,FR,GF,PF,TF,GA,GM,GE,DE,GH,GI,GR,GL,GD,GP,GU,GT,GG,GN,GW,GY,HT,HM,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IM,IL,IT,JM,JP,JE,JO,KZ,KE,KI,KP,KR,KW,KG,LA,LV,LB,LS,LR,LY,LI,LT,LU,MO,MK,MG,MW,MY,MV,ML,MT,MH,MQ,MR,MU,YT,MX,FM,MD,MC,MN,ME,MS,MA,MZ,MM,NA,NR,NP,NC,NZ,NI,NE,NG,NU,NF,MP,NO,OM,PK,PW,PS,PA,PG,PY,PE,PH,PN,PL,PT,PR,QA,RE,RO,RU,RW,BL,SH,KN,LC,MF,VC,WS,SM,ST,SA,SN,RS,SC,SL,SG,SX,SK,SI,SB,SO,ZA,GS,SS,ES,LK,PM,SD,SR,SJ,SZ,SE,CH,SY,TW,TJ,TZ,TH,NL,TL,TG,TK,TO,TT,TN,TR,TM,TC,TV,UG,UA,AE,GB,US,UM,UY,UZ,VU,VA,VE,VN,VG,VI,WF,EH,YE,ZM,ZW", currency = "ARS,AUD,AZN,BHD,BOB,BAM,BRL,BGN,CAD,CLP,CNY,COP,CRC,HRK,CZK,DKK,DOP,XCD,EGP,ETB,EUR,FJD,GEL,GTQ,HTG,HNL,HKD,HUF,INR,IDR,JMD,JPY,JOD,KZT,KES,KRW,KWD,LBP,LYD,MWK,MUR,MXN,MDL,MAD,ILS,NZD,NGN,NOK,OMR,PKR,PAB,PYG,PEN,PHP,PLN,GBP,QAR,RON,RUB,RWF,SAR,RSD,SGD,ZAR,LKR,SEK,CHF,SYP,TWD,THB,TTD,TND,TRY,UAH,AED,UYU,USD,VND" }
+
+[pm_filters.payjustnow]
+payjustnow = { country = "ZA", currency = "ZAR" }
+
+[pm_filters.payjustnowinstore]
+payjustnow = { country = "ZA", currency = "ZAR" }
diff --git a/config/docker-configuration.toml b/config/docker-configuration.toml
index 71a2d164..f6444b3a 100644
--- a/config/docker-configuration.toml
+++ b/config/docker-configuration.toml
@@ -1,7 +1,7 @@
[log.console]
enabled = true
level = "DEBUG"
-log_format = "default"
+log_format = "json"
[server]
host = "0.0.0.0"
@@ -9,7 +9,7 @@ port = 8080
[metrics]
host = "0.0.0.0"
-port = 9090
+port = 9094
[limit]
request_count = 1
@@ -49,6 +49,29 @@ max_feed_count = 200
tti = 7200 # i.e. 2 hours
max_capacity = 5000
+[cache_config]
+service_config_redis_prefix = "DE_service_config_"
+service_config_ttl = 300 # 5 minutes
+
+[analytics]
+enabled = false
+
+[analytics.kafka]
+brokers = ["kafka:29092"]
+topic_prefix = "decision-engine"
+batch_size = 100
+batch_timeout_ms = 1000
+max_consecutive_failures = 5
+
+[analytics.clickhouse]
+host = "http://clickhouse:8123"
+username = "analytics_user"
+password = "analytics_pass"
+database = "decision_engine_analytics"
+
+[secrets]
+open_router_private_key = ""
+
[tenant_secrets]
public = { schema = "public" }
@@ -65,125 +88,659 @@ pool_max_idle_per_host = 10
identity = ""
[routing_config.keys]
-payment_method = { type = "enum", values = "card, bank_debit, bank_transfer" }
-amount = { type = "integer" }
+amount = { type = "integer", min = 0 }
+authentication_type = { type = "enum", values = "three_ds, no_three_ds" }
+bank_debit = { type = "enum", values = "ach, sepa, bacs, becs" }
+bank_redirect = { type = "enum", values = "giropay, ideal, sofort, eft, eps, bancontact_card, blik, local_bank_redirect, online_banking_thailand, online_banking_czech_republic, online_banking_finland, online_banking_fpx, online_banking_poland, online_banking_slovakia, przelewy24, trustly, bizum, interac, open_banking_uk, open_banking_pis" }
+bank_transfer = { type = "enum", values = "ach, sepa, sepa_bank_transfer, bacs, multibanco, pix, pse, permata_bank_transfer, bca_bank_transfer, bni_va, bri_va, cimb_va, danamon_va, mandiri_va, local_bank_transfer, instant_bank_transfer" }
+billing_country = { type = "enum", values = "Afghanistan, AlandIslands, Albania, Algeria, AmericanSamoa, Andorra, Angola, Anguilla, Antarctica, AntiguaAndBarbuda, Argentina, Armenia, Aruba, Australia, Austria, Azerbaijan, Bahamas, Bahrain, Bangladesh, Barbados, Belarus, Belgium, Belize, Benin, Bermuda, Bhutan, BoliviaPlurinationalState, BonaireSintEustatiusAndSaba, BosniaAndHerzegovina, Botswana, BouvetIsland, Brazil, BritishIndianOceanTerritory, BruneiDarussalam, Bulgaria, BurkinaFaso, Burundi, CaboVerde, Cambodia, Cameroon, Canada, CaymanIslands, CentralAfricanRepublic, Chad, Chile, China, ChristmasIsland, CocosKeelingIslands, Colombia, Comoros, Congo, CongoDemocraticRepublic, CookIslands, CostaRica, CotedIvoire, Croatia, Cuba, Curacao, Cyprus, Czechia, Denmark, Djibouti, Dominica, DominicanRepublic, Ecuador, Egypt, ElSalvador, EquatorialGuinea, Eritrea, Estonia, Ethiopia, FalklandIslandsMalvinas, FaroeIslands, Fiji, Finland, France, FrenchGuiana, FrenchPolynesia, FrenchSouthernTerritories, Gabon, Gambia, Georgia, Germany, Ghana, Gibraltar, Greece, Greenland, Grenada, Guadeloupe, Guam, Guatemala, Guernsey, Guinea, GuineaBissau, Guyana, Haiti, HeardIslandAndMcDonaldIslands, HolySee, Honduras, HongKong, Hungary, Iceland, India, Indonesia, IranIslamicRepublic, Iraq, Ireland, IsleOfMan, Israel, Italy, Jamaica, Japan, Jersey, Jordan, Kazakhstan, Kenya, Kiribati, KoreaDemocraticPeoplesRepublic, KoreaRepublic, Kuwait, Kyrgyzstan, LaoPeoplesDemocraticRepublic, Latvia, Lebanon, Lesotho, Liberia, Libya, Liechtenstein, Lithuania, Luxembourg, Macao, MacedoniaTheFormerYugoslavRepublic, Madagascar, Malawi, Malaysia, Maldives, Mali, Malta, MarshallIslands, Martinique, Mauritania, Mauritius, Mayotte, Mexico, MicronesiaFederatedStates, MoldovaRepublic, Monaco, Mongolia, Montenegro, Montserrat, Morocco, Mozambique, Myanmar, Namibia, Nauru, Nepal, Netherlands, NewCaledonia, NewZealand, Nicaragua, Niger, Nigeria, Niue, NorfolkIsland, NorthernMarianaIslands, Norway, Oman, Pakistan, Palau, PalestineState, Panama, PapuaNewGuinea, Paraguay, Peru, Philippines, Pitcairn, Poland, Portugal, PuertoRico, Qatar, Reunion, Romania, RussianFederation, Rwanda, SaintBarthelemy, SaintHelenaAscensionAndTristandaCunha, SaintKittsAndNevis, SaintLucia, SaintMartinFrenchpart, SaintPierreAndMiquelon, SaintVincentAndTheGrenadines, Samoa, SanMarino, SaoTomeAndPrincipe, SaudiArabia, Senegal, Serbia, Seychelles, SierraLeone, Singapore, SintMaartenDutchpart, Slovakia, Slovenia, SolomonIslands, Somalia, SouthAfrica, SouthGeorgiaAndTheSouthSandwichIslands, SouthSudan, Spain, SriLanka, Sudan, Suriname, SvalbardAndJanMayen, Swaziland, Sweden, Switzerland, SyrianArabRepublic, TaiwanProvinceOfChina, Tajikistan, TanzaniaUnitedRepublic, Thailand, TimorLeste, Togo, Tokelau, Tonga, TrinidadAndTobago, Tunisia, Turkey, Turkmenistan, TurksAndCaicosIslands, Tuvalu, Uganda, Ukraine, UnitedArabEmirates, UnitedKingdomOfGreatBritainAndNorthernIreland, UnitedStatesOfAmerica, UnitedStatesMinorOutlyingIslands, Uruguay, Uzbekistan, Vanuatu, VenezuelaBolivarianRepublic, Vietnam, VirginIslandsBritish, VirginIslandsUS, WallisAndFutuna, WesternSahara, Yemen, Zambia, Zimbabwe" }
+business_country = { type = "enum", values = "Afghanistan, AlandIslands, Albania, Algeria, AmericanSamoa, Andorra, Angola, Anguilla, Antarctica, AntiguaAndBarbuda, Argentina, Armenia, Aruba, Australia, Austria, Azerbaijan, Bahamas, Bahrain, Bangladesh, Barbados, Belarus, Belgium, Belize, Benin, Bermuda, Bhutan, BoliviaPlurinationalState, BonaireSintEustatiusAndSaba, BosniaAndHerzegovina, Botswana, BouvetIsland, Brazil, BritishIndianOceanTerritory, BruneiDarussalam, Bulgaria, BurkinaFaso, Burundi, CaboVerde, Cambodia, Cameroon, Canada, CaymanIslands, CentralAfricanRepublic, Chad, Chile, China, ChristmasIsland, CocosKeelingIslands, Colombia, Comoros, Congo, CongoDemocraticRepublic, CookIslands, CostaRica, CotedIvoire, Croatia, Cuba, Curacao, Cyprus, Czechia, Denmark, Djibouti, Dominica, DominicanRepublic, Ecuador, Egypt, ElSalvador, EquatorialGuinea, Eritrea, Estonia, Ethiopia, FalklandIslandsMalvinas, FaroeIslands, Fiji, Finland, France, FrenchGuiana, FrenchPolynesia, FrenchSouthernTerritories, Gabon, Gambia, Georgia, Germany, Ghana, Gibraltar, Greece, Greenland, Grenada, Guadeloupe, Guam, Guatemala, Guernsey, Guinea, GuineaBissau, Guyana, Haiti, HeardIslandAndMcDonaldIslands, HolySee, Honduras, HongKong, Hungary, Iceland, India, Indonesia, IranIslamicRepublic, Iraq, Ireland, IsleOfMan, Israel, Italy, Jamaica, Japan, Jersey, Jordan, Kazakhstan, Kenya, Kiribati, KoreaDemocraticPeoplesRepublic, KoreaRepublic, Kuwait, Kyrgyzstan, LaoPeoplesDemocraticRepublic, Latvia, Lebanon, Lesotho, Liberia, Libya, Liechtenstein, Lithuania, Luxembourg, Macao, MacedoniaTheFormerYugoslavRepublic, Madagascar, Malawi, Malaysia, Maldives, Mali, Malta, MarshallIslands, Martinique, Mauritania, Mauritius, Mayotte, Mexico, MicronesiaFederatedStates, MoldovaRepublic, Monaco, Mongolia, Montenegro, Montserrat, Morocco, Mozambique, Myanmar, Namibia, Nauru, Nepal, Netherlands, NewCaledonia, NewZealand, Nicaragua, Niger, Nigeria, Niue, NorfolkIsland, NorthernMarianaIslands, Norway, Oman, Pakistan, Palau, PalestineState, Panama, PapuaNewGuinea, Paraguay, Peru, Philippines, Pitcairn, Poland, Portugal, PuertoRico, Qatar, Reunion, Romania, RussianFederation, Rwanda, SaintBarthelemy, SaintHelenaAscensionAndTristandaCunha, SaintKittsAndNevis, SaintLucia, SaintMartinFrenchpart, SaintPierreAndMiquelon, SaintVincentAndTheGrenadines, Samoa, SanMarino, SaoTomeAndPrincipe, SaudiArabia, Senegal, Serbia, Seychelles, SierraLeone, Singapore, SintMaartenDutchpart, Slovakia, Slovenia, SolomonIslands, Somalia, SouthAfrica, SouthGeorgiaAndTheSouthSandwichIslands, SouthSudan, Spain, SriLanka, Sudan, Suriname, SvalbardAndJanMayen, Swaziland, Sweden, Switzerland, SyrianArabRepublic, TaiwanProvinceOfChina, Tajikistan, TanzaniaUnitedRepublic, Thailand, TimorLeste, Togo, Tokelau, Tonga, TrinidadAndTobago, Tunisia, Turkey, Turkmenistan, TurksAndCaicosIslands, Tuvalu, Uganda, Ukraine, UnitedArabEmirates, UnitedKingdomOfGreatBritainAndNorthernIreland, UnitedStatesOfAmerica, UnitedStatesMinorOutlyingIslands, Uruguay, Uzbekistan, Vanuatu, VenezuelaBolivarianRepublic, Vietnam, VirginIslandsBritish, VirginIslandsUS, WallisAndFutuna, WesternSahara, Yemen, Zambia, Zimbabwe" }
+business_label = { type = "str_value" }
+capture_method = { type = "enum", values = "automatic, manual, manual_multiple, scheduled, sequential_automatic" }
+card = { type = "enum", values = "debit, credit" }
+card_bin = { type = "str_value", exact_length = 6, regex = "^[0-9]{6}$" }
+card_discovery = { type = "enum", values = "manual, saved_card, click_to_pay" }
+card_network = { type = "enum", values = "visa, VISA, Visa, visaCard, mastercard, MASTERCARD, MasterCard, masterCard, mastercardCard, master_card, Master_card, Master_Card, Master Card, Mastercard, american_express, AMERICANEXPRESS, AmericanExpress, americanExpress, americanExpressCard, amex, AMEX, Amex, jcb, JCB, Jcb, diners_club, DINERSCLUB, DinersClub, dinersClub, dinersClubCard, discover, DISCOVER, Discover, discoverCard, cartes_bancaires, CARTESBANCAIRES, CartesBancaires, cartesBancaires, union_pay, UNIONPAY, UnionPay, unionPay, interac, INTERAC, Interac, rupay, RUPAY, RuPay, ruPay, maestro, MAESTRO, Maestro, star, STAR, Star, pulse, PULSE, Pulse, accel, ACCEL, Accel, nyce, NYCE, Nyce" }
+card_redirect = { type = "enum", values = "knet, benefit, momo_atm, card_redirect" }
+card_type = { type = "enum", values = "debit, credit" }
+crypto = { type = "enum", values = "crypto_currency" }
+currency = { type = "enum", values = "AED, AFN, ALL, AMD, ANG, AOA, ARS, AUD, AWG, AZN, BAM, BBD, BDT, BGN, BHD, BIF, BMD, BND, BOB, BRL, BSD, BTN, BWP, BYN, BZD, CAD, CDF, CHF, CLF, CLP, CNY, COP, CRC, CUC, CUP, CVE, CZK, DJF, DKK, DOP, DZD, EGP, ERN, ETB, EUR, FJD, FKP, GBP, GEL, GHS, GIP, GMD, GNF, GTQ, GYD, HKD, HNL, HRK, HTG, HUF, IDR, ILS, INR, IQD, IRR, ISK, JMD, JOD, JPY, KES, KGS, KHR, KMF, KPW, KRW, KWD, KYD, KZT, LAK, LBP, LKR, LRD, LSL, LYD, MAD, MDL, MGA, MKD, MMK, MNT, MOP, MRU, MUR, MVR, MWK, MXN, MYR, MZN, NAD, NGN, NIO, NOK, NPR, NZD, OMR, PAB, PEN, PGK, PHP, PKR, PLN, PYG, QAR, RON, RSD, RUB, RWF, SAR, SBD, SCR, SDG, SEK, SGD, SHP, SLE, SLL, SOS, SRD, SSP, STD, STN, SVC, SYP, SZL, THB, TJS, TMT, TND, TOP, TRY, TTD, TWD, TZS, UAH, UGX, USD, UYU, UZS, VES, VND, VUV, WST, XAF, XCD, XOF, XPF, YER, ZAR, ZMW, ZWL" }
+extended_card_bin = { type = "str_value", exact_length = 8, regex = "^[0-9]{8}$" }
+gift_card = { type = "enum", values = "givex, pay_safe_card" }
+issuer_country = { type = "enum", values = "Afghanistan, AlandIslands, Albania, Algeria, AmericanSamoa, Andorra, Angola, Anguilla, Antarctica, AntiguaAndBarbuda, Argentina, Armenia, Aruba, Australia, Austria, Azerbaijan, Bahamas, Bahrain, Bangladesh, Barbados, Belarus, Belgium, Belize, Benin, Bermuda, Bhutan, BoliviaPlurinationalState, BonaireSintEustatiusAndSaba, BosniaAndHerzegovina, Botswana, BouvetIsland, Brazil, BritishIndianOceanTerritory, BruneiDarussalam, Bulgaria, BurkinaFaso, Burundi, CaboVerde, Cambodia, Cameroon, Canada, CaymanIslands, CentralAfricanRepublic, Chad, Chile, China, ChristmasIsland, CocosKeelingIslands, Colombia, Comoros, Congo, CongoDemocraticRepublic, CookIslands, CostaRica, CotedIvoire, Croatia, Cuba, Curacao, Cyprus, Czechia, Denmark, Djibouti, Dominica, DominicanRepublic, Ecuador, Egypt, ElSalvador, EquatorialGuinea, Eritrea, Estonia, Ethiopia, FalklandIslandsMalvinas, FaroeIslands, Fiji, Finland, France, FrenchGuiana, FrenchPolynesia, FrenchSouthernTerritories, Gabon, Gambia, Georgia, Germany, Ghana, Gibraltar, Greece, Greenland, Grenada, Guadeloupe, Guam, Guatemala, Guernsey, Guinea, GuineaBissau, Guyana, Haiti, HeardIslandAndMcDonaldIslands, HolySee, Honduras, HongKong, Hungary, Iceland, India, Indonesia, IranIslamicRepublic, Iraq, Ireland, IsleOfMan, Israel, Italy, Jamaica, Japan, Jersey, Jordan, Kazakhstan, Kenya, Kiribati, KoreaDemocraticPeoplesRepublic, KoreaRepublic, Kuwait, Kyrgyzstan, LaoPeoplesDemocraticRepublic, Latvia, Lebanon, Lesotho, Liberia, Libya, Liechtenstein, Lithuania, Luxembourg, Macao, MacedoniaTheFormerYugoslavRepublic, Madagascar, Malawi, Malaysia, Maldives, Mali, Malta, MarshallIslands, Martinique, Mauritania, Mauritius, Mayotte, Mexico, MicronesiaFederatedStates, MoldovaRepublic, Monaco, Mongolia, Montenegro, Montserrat, Morocco, Mozambique, Myanmar, Namibia, Nauru, Nepal, Netherlands, NewCaledonia, NewZealand, Nicaragua, Niger, Nigeria, Niue, NorfolkIsland, NorthernMarianaIslands, Norway, Oman, Pakistan, Palau, PalestineState, Panama, PapuaNewGuinea, Paraguay, Peru, Philippines, Pitcairn, Poland, Portugal, PuertoRico, Qatar, Reunion, Romania, RussianFederation, Rwanda, SaintBarthelemy, SaintHelenaAscensionAndTristandaCunha, SaintKittsAndNevis, SaintLucia, SaintMartinFrenchpart, SaintPierreAndMiquelon, SaintVincentAndTheGrenadines, Samoa, SanMarino, SaoTomeAndPrincipe, SaudiArabia, Senegal, Serbia, Seychelles, SierraLeone, Singapore, SintMaartenDutchpart, Slovakia, Slovenia, SolomonIslands, Somalia, SouthAfrica, SouthGeorgiaAndTheSouthSandwichIslands, SouthSudan, Spain, SriLanka, Sudan, Suriname, SvalbardAndJanMayen, Swaziland, Sweden, Switzerland, SyrianArabRepublic, TaiwanProvinceOfChina, Tajikistan, TanzaniaUnitedRepublic, Thailand, TimorLeste, Togo, Tokelau, Tonga, TrinidadAndTobago, Tunisia, Turkey, Turkmenistan, TurksAndCaicosIslands, Tuvalu, Uganda, Ukraine, UnitedArabEmirates, UnitedKingdomOfGreatBritainAndNorthernIreland, UnitedStatesOfAmerica, UnitedStatesMinorOutlyingIslands, Uruguay, Uzbekistan, Vanuatu, VenezuelaBolivarianRepublic, Vietnam, VirginIslandsBritish, VirginIslandsUS, WallisAndFutuna, WesternSahara, Yemen, Zambia, Zimbabwe" }
+issuer_name = { type = "str_value", min_length = 1 }
+mandate_acceptance_type = { type = "enum", values = "online, offline" }
+mandate_type = { type = "enum", values = "single_use, multi_use" }
metadata = { type = "udf" }
-currency = { type = "enum", values = "USD, EUR, GBP, JPY, CAD, AUD" }
-order_udf1 = { type = "global_ref" }
-payment_methodType = { type = "enum", values = "CARD, UPI, NB" }
-payment_cardBrand = { type = "enum", values = "VISA, MASTERCARD, AMEX, RUPAY, DINERS" }
-payment_cardBin = { type = "global_ref" }
-payment_cardType = { type = "enum", values = "CREDIT, DEBIT" }
-payment_cardIssuerCountry = { type = "enum", values = "INDIA, US, UK, SINGAPORE" }
-payment_paymentMethod = { type = "enum", values = "NB_HDFC, NB_ICICI, NB_SBI" }
-payment_paymentSource = { type = "enum", values = "net.one97.paytm, @paytm" }
-txn_isEmi = { type = "enum", values = "true, false" }
-
-[routing_config.default]
-output = ["stripe", "adyen"]
-
-[[routing_config.constraint_graph.nodes]]
-preds = []
-succs = [0]
-
-[routing_config.constraint_graph.nodes.kind]
-kind = "value"
-
-[routing_config.constraint_graph.nodes.kind.data]
-kind = "value"
-
-[routing_config.constraint_graph.nodes.kind.data.data]
-key = "payment_method"
-comparison = "equal"
-
-[routing_config.constraint_graph.nodes.kind.data.data.value]
-type = "enum_variant"
-value = "card"
-
-[[routing_config.constraint_graph.nodes]]
-preds = []
-succs = [1]
-
-[routing_config.constraint_graph.nodes.kind]
-kind = "value"
-
-[routing_config.constraint_graph.nodes.kind.data]
-kind = "value"
-
-[routing_config.constraint_graph.nodes.kind.data.data]
-key = "payment_method"
-comparison = "equal"
-
-[routing_config.constraint_graph.nodes.kind.data.data.value]
-type = "enum_variant"
-value = "bank_debit"
-
-[[routing_config.constraint_graph.nodes]]
-preds = [0]
-succs = []
-
-[routing_config.constraint_graph.nodes.kind]
-kind = "value"
-
-[routing_config.constraint_graph.nodes.kind.data]
-kind = "value"
-
-[routing_config.constraint_graph.nodes.kind.data.data]
-key = "output"
-comparison = "equal"
-
-[routing_config.constraint_graph.nodes.kind.data.data.value]
-type = "enum_variant"
-value = "stripe"
-
-[[routing_config.constraint_graph.nodes]]
-preds = [1]
-succs = []
-
-[routing_config.constraint_graph.nodes.kind]
-kind = "value"
-
-[routing_config.constraint_graph.nodes.kind.data]
-kind = "value"
-
-[routing_config.constraint_graph.nodes.kind.data.data]
-key = "output"
-comparison = "equal"
-
-[routing_config.constraint_graph.nodes.kind.data.data.value]
-type = "enum_variant"
-value = "adyen"
-
-[[routing_config.constraint_graph.edges]]
-strength = "strong"
-relation = "positive"
-pred = 0
-succ = 2
-
-[[routing_config.constraint_graph.edges]]
-strength = "strong"
-relation = "positive"
-pred = 1
-succ = 3
+mobile_payment = { type = "enum", values = "direct_carrier_billing" }
+network_token = { type = "enum", values = "network_token" }
+open_banking = { type = "enum", values = "open_banking_pis" }
+pay_later = { type = "enum", values = "affirm, alma, afterpay_clearpay, klarna, pay_bright, atome, walley" }
+payment_method = { type = "enum", values = "card, card_redirect, pay_later, wallet, bank_redirect, bank_transfer, crypto, bank_debit, reward, real_time_payment, upi, voucher, gift_card, open_banking, mobile_payment" }
+payment_method_type = { type = "enum", values = "ach, affirm, afterpay_clearpay, alfamart, ali_pay, ali_pay_hk, alma, amazon_pay, apple_pay, atome, bacs, bancontact_card, becs, benefit, bizum, blik, boleto, bca_bank_transfer, bni_va, bri_va, card, card_redirect, cimb_va, classic_reward, credit, crypto_currency, cashapp, dana, danamon_va, debit, duit_now, efecty, eft, eps, fps, evoucher, giropay, givex, google_pay, go_pay, gcash, ideal, interac, indomaret, klarna, kakao_pay, local_bank_redirect, mandiri_va, knet, mb_way, mobile_pay, momo, momo_atm, multibanco, online_banking_thailand, online_banking_czech_republic, online_banking_finland, online_banking_fpx, online_banking_poland, online_banking_slovakia, oxxo, pago_efectivo, permata_bank_transfer, open_banking_uk, pay_bright, paypal, paze, pix, pay_safe_card, przelewy24, prompt_pay, pse, red_compra, red_pagos, samsung_pay, sepa, sepa_bank_transfer, sofort, swish, touch_n_go, trustly, twint, upi_collect, upi_intent, vipps, viet_qr, venmo, walley, we_chat_pay, seven_eleven, lawson, mini_stop, family_mart, seicomart, pay_easy, local_bank_transfer, mifinity, open_banking_pis, direct_carrier_billing, instant_bank_transfer" }
+payment_type = { type = "enum", values = "normal, new_mandate, setup_mandate, recurring_mandate, non_mandate" }
+real_time_payment = { type = "enum", values = "fps, duit_now, prompt_pay, viet_qr" }
+reward = { type = "enum", values = "evoucher, classic_reward" }
+setup_future_usage = { type = "enum", values = "on_session, off_session" }
+transaction_initiator = { type = "enum", values = "customer, merchant" }
+upi = { type = "enum", values = "upi_collect, upi_intent" }
+voucher = { type = "enum", values = "boleto, efecty, pago_efectivo, red_compra, red_pagos, indomaret, alfamart, oxxo, seven_eleven, lawson, mini_stop, family_mart, seicomart, pay_easy" }
+wallet = { type = "enum", values = "amazon_pay, apple_pay, google_pay, paypal, ali_pay, ali_pay_hk, dana, mb_way, mobile_pay, samsung_pay, twint, vipps, touch_n_go, swish, we_chat_pay, go_pay, gcash, momo, kakao_pay, cashapp, mifinity, paze" }
[debit_routing_config]
-fraud_check_fee = 0.01
+fraud_check_fee = 1.0
[debit_routing_config.network_fee]
-visa = { percentage = 0.1375, fixed_amount = 0.020 }
-mastercard = { percentage = 0.15, fixed_amount = 0.040 }
-accel = { percentage = 0.0, fixed_amount = 0.040 }
-nyce = { percentage = 0.10, fixed_amount = 0.015 }
-pulse = { percentage = 0.10, fixed_amount = 0.03 }
-star = { percentage = 0.10, fixed_amount = 0.015 }
+visa = { percentage = 0.1375, fixed_amount = 2.0 }
+mastercard = { percentage = 0.15, fixed_amount = 4.0 }
+accel = { percentage = 0.0, fixed_amount = 4.0 }
+nyce = { percentage = 0.10, fixed_amount = 1.5 }
+pulse = { percentage = 0.10, fixed_amount = 3.0 }
+star = { percentage = 0.10, fixed_amount = 1.5 }
[debit_routing_config.interchange_fee]
regulated = { percentage = 0.05, fixed_amount = 0.21 }
[debit_routing_config.interchange_fee.non_regulated]
-merchant_category_code_0001.visa = { percentage = 1.65, fixed_amount = 0.15 }
-merchant_category_code_0001.mastercard = { percentage = 1.65, fixed_amount = 0.15 }
-merchant_category_code_0001.accel = { percentage = 1.55, fixed_amount = 0.04 }
-merchant_category_code_0001.nyce = { percentage = 1.30, fixed_amount = 0.213125 }
-merchant_category_code_0001.pulse = { percentage = 1.60, fixed_amount = 0.15 }
-merchant_category_code_0001.star = { percentage = 1.63, fixed_amount = 0.15 }
+merchant_category_code_0001.visa = { percentage = 1.65, fixed_amount = 15.0 }
+merchant_category_code_0001.mastercard = { percentage = 1.65, fixed_amount = 15.0 }
+merchant_category_code_0001.accel = { percentage = 1.55, fixed_amount = 4.0 }
+merchant_category_code_0001.nyce = { percentage = 1.30, fixed_amount = 21.3125 }
+merchant_category_code_0001.pulse = { percentage = 1.60, fixed_amount = 15.0 }
+merchant_category_code_0001.star = { percentage = 1.63, fixed_amount = 15.0 }
+
+[pm_filters.default]
+google_pay = { country = "AL,DZ,AS,AO,AG,AR,AU,AT,AZ,BH,BY,BE,BR,BG,CA,CL,CO,HR,CZ,DK,DO,EG,EE,FI,FR,DE,GR,HK,HU,IN,ID,IE,IL,IT,JP,JO,KZ,KE,KW,LV,LB,LT,LU,MY,MX,NL,NZ,NO,OM,PK,PA,PE,PH,PL,PT,QA,RO,RU,SA,SG,SK,ZA,ES,LK,SE,CH,TW,TH,TR,UA,AE,GB,US,UY,VN" }
+apple_pay = { country = "AU,CN,HK,JP,MO,MY,NZ,SG,TW,AM,AT,AZ,BY,BE,BG,HR,CY,CZ,DK,EE,FO,FI,FR,GE,DE,GR,GL,GG,HU,IS,IE,IM,IT,KZ,JE,LV,LI,LT,LU,MT,MD,MC,ME,NL,NO,PL,PT,RO,SM,RS,SK,SI,ES,SE,CH,UA,GB,AR,CO,CR,BR,MX,PE,BH,IL,JO,KW,PS,QA,SA,AE,CA,UM,US,KR,VN,MA,ZA,VA,CL,SV,GT,HN,PA", currency = "AED,AUD,CHF,CAD,EUR,GBP,HKD,SGD,USD" }
+paypal = { currency = "AUD,BRL,CAD,CHF,CNY,CZK,DKK,EUR,GBP,HKD,HUF,ILS,JPY,MXN,MYR,NOK,NZD,PHP,PLN,SEK,SGD,THB,TWD,USD" }
+klarna = { country = "AT,BE,DK,FI,FR,DE,IE,IT,NL,NO,ES,SE,GB,US,CA", currency = "USD,GBP,EUR,CHF,DKK,SEK,NOK,AUD,PLN,CAD" }
+affirm = { country = "US", currency = "USD" }
+afterpay_clearpay = { country = "US,CA,GB,AU,NZ", currency = "GBP,AUD,NZD,CAD,USD" }
+giropay = { country = "DE", currency = "EUR" }
+eps = { country = "AT", currency = "EUR" }
+sofort = { country = "ES,GB,SE,AT,NL,DE,CH,BE,FR,FI,IT,PL", currency = "EUR" }
+ideal = { country = "NL", currency = "EUR" }
+
+[pm_filters.stripe]
+google_pay = { country = "AU, AT, BE, BR, BG, CA, HR, CZ, DK, EE, FI, FR, DE, GR, HK, HU, IN, ID, IE, IT, JP, LV, KE, LT, LU, MY, MX, NL, NZ, NO, PL, PT, RO, SG, SK, ZA, ES, SE, CH, TH, AE, GB, US, GI, LI, MT, CY, PH, IS, AR, CL, KR, IL"}
+apple_pay = { country = "AU, AT, BE, BR, BG, CA, HR, CY, CZ, DK, EE, FI, FR, DE, GR, HU, HK, IE, IT, JP, LV, LI, LT, LU, MT, MY, MX, NL, NZ, NO, PL, PT, RO, SK, SG, SI, ZA, ES, SE, CH, GB, AE, US" }
+klarna = { country = "AU,AT,BE,CA,CZ,DK,FI,FR,DE,GR,IE,IT,NL,NZ,NO,PL,PT,ES,SE,CH,GB,US", currency = "AUD,CAD,CHF,CZK,DKK,EUR,GBP,NOK,NZD,PLN,SEK,USD" }
+credit = { country = "AF,AX,AL,DZ,AS,AD,AO,AI,AQ,AG,AR,AM,AW,AU,AT,AZ,BS,BH,BD,BB,BY,BE,BZ,BJ,BM,BT,BO,BQ,BA,BW,BV,BR,IO,BN,BG,BF,BI,KH,CM,CA,CV,KY,CF,TD,CL,CN,CX,CC,CO,KM,CG,CD,CK,CR,CI,HR,CU,CW,CY,CZ,DK,DJ,DM,DO,EC,EG,SV,GQ,ER,EE,ET,FK,FO,FJ,FI,FR,GF,PF,TF,GA,GM,GE,DE,GH,GI,GR,GL,GD,GP,GU,GT,GG,GN,GW,GY,HT,HM,VA,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IM,IL,IT,JM,JP,JE,JO,KZ,KE,KI,KP,KR,KW,KG,LA,LV,LB,LS,LR,LY,LI,LT,LU,MO,MK,MG,MW,MY,MV,ML,MT,MH,MQ,MR,MU,YT,MX,FM,MD,MC,MN,ME,MS,MA,MZ,MM,NA,NR,NP,NL,NC,NZ,NI,NE,NG,NU,NF,MP,NO,OM,PK,PW,PS,PA,PG,PY,PE,PH,PN,PL,PT,PR,QA,RE,RO,RU,RW,BL,SH,KN,LC,MF,PM,VC,WS,SM,ST,SA,SN,RS,SC,SL,SG,SX,SK,SI,SB,SO,ZA,GS,SS,ES,LK,SD,SR,SJ,SZ,SE,CH,SY,TW,TJ,TZ,TH,TL,TG,TK,TO,TT,TN,TR,TM,TC,TV,UG,UA,AE,GB,UM,UY,UZ,VU,VE,VN,VG,VI,WF,EH,YE,ZM,ZW,US", currency = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BYN,BZD,CAD,CDF,CHF,CLF,CLP,CNY,COP,CRC,CUC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLE,SLL,SOS,SRD,SSP,STD,STN,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL"}
+debit = { country = "AF,AX,AL,DZ,AS,AD,AO,AI,AQ,AG,AR,AM,AW,AU,AT,AZ,BS,BH,BD,BB,BY,BE,BZ,BJ,BM,BT,BO,BQ,BA,BW,BV,BR,IO,BN,BG,BF,BI,KH,CM,CA,CV,KY,CF,TD,CL,CN,CX,CC,CO,KM,CG,CD,CK,CR,CI,HR,CU,CW,CY,CZ,DK,DJ,DM,DO,EC,EG,SV,GQ,ER,EE,ET,FK,FO,FJ,FI,FR,GF,PF,TF,GA,GM,GE,DE,GH,GI,GR,GL,GD,GP,GU,GT,GG,GN,GW,GY,HT,HM,VA,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IM,IL,IT,JM,JP,JE,JO,KZ,KE,KI,KP,KR,KW,KG,LA,LV,LB,LS,LR,LY,LI,LT,LU,MO,MK,MG,MW,MY,MV,ML,MT,MH,MQ,MR,MU,YT,MX,FM,MD,MC,MN,ME,MS,MA,MZ,MM,NA,NR,NP,NL,NC,NZ,NI,NE,NG,NU,NF,MP,NO,OM,PK,PW,PS,PA,PG,PY,PE,PH,PN,PL,PT,PR,QA,RE,RO,RU,RW,BL,SH,KN,LC,MF,PM,VC,WS,SM,ST,SA,SN,RS,SC,SL,SG,SX,SK,SI,SB,SO,ZA,GS,SS,ES,LK,SD,SR,SJ,SZ,SE,CH,SY,TW,TJ,TZ,TH,TL,TG,TK,TO,TT,TN,TR,TM,TC,TV,UG,UA,AE,GB,UM,UY,UZ,VU,VE,VN,VG,VI,WF,EH,YE,ZM,ZW,US", currency = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BYN,BZD,CAD,CDF,CHF,CLF,CLP,CNY,COP,CRC,CUC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLE,SLL,SOS,SRD,SSP,STD,STN,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL"}
+affirm = { country = "US", currency = "USD" }
+afterpay_clearpay = { country = "US,CA,GB,AU,NZ,FR,ES", currency = "USD,CAD,GBP,AUD,NZD" }
+cashapp = { country = "US", currency = "USD" }
+eps = { country = "AT", currency = "EUR" }
+giropay = { country = "DE", currency = "EUR" }
+ideal = { country = "NL", currency = "EUR" }
+multibanco = { country = "AT,BE,BG,HR,CY,CZ,DK,EE,FI,FR,DE,GI,GR,HU,IE,IT,LV,LI,LT,LU,MT,NL,NO,PL,PT,RO,SK,SI,ES,SE,CH,GB", currency = "EUR" }
+ach = { country = "US", currency = "USD" }
+revolut_pay = { currency = "EUR,GBP" }
+sepa = {country = "AT,BE,BG,HR,CY,CZ,DK,EE,FI,FR,DE,GI,GR,HU,IE,IT,LV,LI,LT,LU,MT,NL,NO,PL,PT,RO,SK,SI,ES,SE,CH,GB,IS,LI", currency="EUR"}
+bacs = { country = "GB", currency = "GBP" }
+becs = { country = "AU", currency = "AUD" }
+sofort = {country = "AT,BE,BG,HR,CY,CZ,DK,EE,FI,FR,DE,GR,HU,IS,IE,IT,LV,LI,LT,LU,MT,NL,NO,PL,PT,RO,SK,SI,ES,SE", currency = "EUR" }
+blik = {country="PL", currency = "PLN"}
+bancontact_card = { country = "BE", currency = "EUR" }
+przelewy24 = { country = "PL", currency = "EUR,PLN" }
+online_banking_fpx = { country = "MY", currency = "MYR" }
+amazon_pay = { country = "AF,AX,AL,DZ,AS,AD,AO,AI,AQ,AG,AR,AM,AW,AU,AT,AZ,BS,BH,BD,BB,BY,BE,BZ,BJ,BM,BT,BO,BQ,BA,BW,BV,BR,IO,BN,BG,BF,BI,KH,CM,CA,CV,KY,CF,TD,CL,CN,CX,CC,CO,KM,CG,CD,CK,CR,CI,HR,CU,CW,CY,CZ,DK,DJ,DM,DO,EC,EG,SV,GQ,ER,EE,ET,FK,FO,FJ,FI,FR,GF,PF,TF,GA,GM,GE,DE,GH,GI,GR,GL,GD,GP,GU,GT,GG,GN,GW,GY,HT,HM,VA,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IM,IL,IT,JM,JP,JE,JO,KZ,KE,KI,KP,KR,KW,KG,LA,LV,LB,LS,LR,LY,LI,LT,LU,MO,MK,MG,MW,MY,MV,ML,MT,MH,MQ,MR,MU,YT,MX,FM,MD,MC,MN,ME,MS,MA,MZ,MM,NA,NR,NP,NL,NC,NZ,NI,NE,NG,NU,NF,MP,NO,OM,PK,PW,PS,PA,PG,PY,PE,PH,PN,PL,PT,PR,QA,RE,RO,RU,RW,BL,SH,KN,LC,MF,PM,VC,WS,SM,ST,SA,SN,RS,SC,SL,SG,SX,SK,SI,SB,SO,ZA,GS,SS,ES,LK,SD,SR,SJ,SZ,SE,CH,SY,TW,TJ,TZ,TH,TL,TG,TK,TO,TT,TN,TR,TM,TC,TV,UG,UA,AE,GB,UM,UY,UZ,VU,VE,VN,VG,VI,WF,EH,YE,ZM,ZW,US", currency = "USD,AUD,GBP,DKK,EUR,HKD,JPY,NZD,NOK,ZAR,SEK,CHF" }
+we_chat_pay = { country = "CN", currency = "CNY,AUD,CAD,EUR,GBP,HKD,JPY,SGD,USD,DKK,NOK,SEK,CHF" }
+ali_pay = {country = "CN", currency = "AUD,CAD,CNY,EUR,GBP,HKD,JPY,MYR,NZD,SGD,USD"}
+
+[pm_filters.volt]
+open_banking = { country = "DE,GB,AT,BE,CY,EE,ES,FI,FR,GR,HR,IE,IT,LT,LU,LV,MT,NL,PT,SI,SK,BG,CZ,DK,HU,NO,PL,RO,SE,AU,BR", currency = "GBP,EUR,DKK,NOK,PLN,SEK" }
+open_banking_uk = { country = "DE,GB,AT,BE,CY,EE,ES,FI,FR,GR,HR,IE,IT,LT,LU,LV,MT,NL,PT,SI,SK,BG,CZ,DK,HU,NO,PL,RO,SE,AU,BR", currency = "GBP" }
+
+[pm_filters.razorpay]
+upi_collect = { country = "IN", currency = "INR" }
+
+[pm_filters.phonepe]
+upi_collect = { country = "IN", currency = "INR" }
+upi_intent = { country = "IN", currency = "INR" }
+
+[pm_filters.paytm]
+upi_collect = { country = "IN", currency = "INR" }
+upi_intent = { country = "IN", currency = "INR" }
+
+[pm_filters.hyperpg]
+credit = { currency = "INR,USD,GBP,EUR" }
+debit = { currency = "INR,USD,GBP,EUR" }
+
+[pm_filters.plaid]
+open_banking_pis = { currency = "EUR,GBP" }
+
+[pm_filters.adyen]
+google_pay = { country = "AT, AU, BE, BG, CA, HR, CZ, EE, FI, FR, DE, GR, HK, DK, HU, IE, IT, LV, LT, LU, NL, NO, PL, PT, RO, SK, ES, SE, CH, GB, US, NZ, SG", currency = "ALL, DZD, USD, AOA, XCD, ARS, AUD, EUR, AZN, BHD, BYN, BRL, BGN, CAD, CLP, COP, CZK, DKK, DOP, EGP, HKD, HUF, INR, IDR, ILS, JPY, JOD, KZT, KES, KWD, LBP, MYR, MXN, NZD, NOK, OMR, PKR, PAB, PEN, PHP, PLN, QAR, RON, RUB, SAR, SGD, ZAR, LKR, SEK, CHF, TWD, THB, TRY, UAH, AED, GBP, UYU, VND" }
+apple_pay = { country = "AT, BE, BG, HR, CY, CZ, DK, EE, FI, FR, DE, GR, GG, HU, IE, IM, IT, LV, LI, LT, LU, MT, NL, NO, PL, PT, RO, SK, SI, SE, ES, CH, GB, US, PR, CA, AU, HK, NZ, SG", currency = "EGP, MAD, ZAR, AUD, CNY, HKD, JPY, MOP, MYR, MNT, NZD, SGD, KRW, TWD, VND, AMD, EUR, AZN, BYN, BGN, CZK, DKK, GEL, GBP, HUF, ISK, KZT, CHF, MDL, NOK, PLN, RON, RSD, SEK, CHF, UAH, ARS, BRL, CLP, COP, CRC, DOP, GTQ, HNL, MXN, PAB, USD, PYG, PEN, BSD, UYU, BHD, ILS, JOD, KWD, OMR, ILS, QAR, SAR, AED, CAD" }
+paypal = { country = "AU,NZ,CN,JP,HK,MY,TH,KR,PH,ID,AE,KW,BR,ES,GB,SE,NO,SK,AT,NL,DE,HU,CY,LU,CH,BE,FR,DK,FI,RO,HR,UA,MT,SI,GI,PT,IE,CZ,EE,LT,LV,IT,PL,IS,CA,US", currency = "AUD,BRL,CAD,CZK,DKK,EUR,HKD,HUF,INR,JPY,MYR,MXN,NZD,NOK,PHP,PLN,RUB,GBP,SGD,SEK,CHF,THB,USD" }
+mobile_pay = { country = "DK,FI", currency = "DKK,SEK,NOK,EUR" }
+ali_pay = { country = "AU,JP,HK,SG,MY,TH,ES,GB,SE,NO,AT,NL,DE,CY,CH,BE,FR,DK,FI,RO,MT,SI,GR,PT,IE,IT,CA,US", currency = "USD,EUR,GBP,JPY,AUD,SGD,CHF,SEK,NOK,NZD,THB,HKD,CAD" }
+we_chat_pay = { country = "AU,NZ,CN,JP,HK,SG,ES,GB,SE,NO,AT,NL,DE,CY,CH,BE,FR,DK,LI,MT,SI,GR,PT,IT,CA,US", currency = "AUD,CAD,CNY,EUR,GBP,HKD,JPY,NZD,SGD,USD" }
+mb_way = { country = "PT", currency = "EUR" }
+klarna = { country = "AU,AT,BE,CA,CZ,DK,FI,FR,DE,GR,IE,IT,NO,PL,PT,RO,ES,SE,CH,NL,GB,US", currency = "AUD,EUR,CAD,CZK,DKK,NOK,PLN,RON,SEK,CHF,GBP,USD" }
+affirm = { country = "US", currency = "USD" }
+afterpay_clearpay = { country = "AU,NZ,ES,GB,FR,IT,CA,US", currency = "GBP" }
+pay_bright = { country = "CA", currency = "CAD" }
+walley = { country = "SE,NO,DK,FI", currency = "DKK,EUR,NOK,SEK" }
+giropay = { country = "DE", currency = "EUR" }
+eps = { country = "AT", currency = "EUR" }
+sofort = { not_available_flows = { capture_method = "manual" }, country = "AT,BE,DE,ES,CH,NL", currency = "CHF,EUR" }
+ideal = { not_available_flows = { capture_method = "manual" }, country = "NL", currency = "EUR" }
+blik = { country = "PL", currency = "PLN" }
+trustly = { country = "ES,GB,SE,NO,AT,NL,DE,DK,FI,EE,LT,LV", currency = "CZK,DKK,EUR,GBP,NOK,SEK" }
+online_banking_czech_republic = { country = "CZ", currency = "EUR,CZK" }
+online_banking_finland = { country = "FI", currency = "EUR" }
+online_banking_poland = { country = "PL", currency = "PLN" }
+online_banking_slovakia = { country = "SK", currency = "EUR,CZK" }
+bancontact_card = { country = "BE", currency = "EUR" }
+ach = { country = "US", currency = "USD" }
+bacs = { country = "GB", currency = "GBP" }
+sepa = { country = "ES,SK,AT,NL,DE,BE,FR,FI,PT,IE,EE,LT,LV,IT", currency = "EUR" }
+ali_pay_hk = { country = "HK", currency = "HKD" }
+bizum = { country = "ES", currency = "EUR" }
+go_pay = { country = "ID", currency = "IDR" }
+kakao_pay = { country = "KR", currency = "KRW" }
+momo = { country = "VN", currency = "VND" }
+gcash = { country = "PH", currency = "PHP" }
+online_banking_fpx = { country = "MY", currency = "MYR" }
+online_banking_thailand = { country = "TH", currency = "THB" }
+touch_n_go = { country = "MY", currency = "MYR" }
+atome = { country = "MY,SG", currency = "MYR,SGD" }
+swish = { country = "SE", currency = "SEK" }
+permata_bank_transfer = { country = "ID", currency = "IDR" }
+bca_bank_transfer = { country = "ID", currency = "IDR" }
+bni_va = { country = "ID", currency = "IDR" }
+bri_va = { country = "ID", currency = "IDR" }
+cimb_va = { country = "ID", currency = "IDR" }
+danamon_va = { country = "ID", currency = "IDR" }
+mandiri_va = { country = "ID", currency = "IDR" }
+alfamart = { country = "ID", currency = "IDR" }
+indomaret = { country = "ID", currency = "IDR" }
+open_banking_uk = { country = "GB", currency = "GBP" }
+oxxo = { country = "MX", currency = "MXN" }
+pay_safe_card = { country = "AT,AU,BE,BR,BE,CA,HR,CY,CZ,DK,FI,FR,GE,DE,GI,HU,IS,IE,KW,LV,IE,LI,LT,LU,MT,MX,MD,ME,NL,NZ,NO,PY,PE,PL,PT,RO,SA,RS,SK,SI,ES,SE,CH,TR,AE,GB,US,UY", currency = "EUR,AUD,BRL,CAD,CZK,DKK,GEL,GIP,HUF,KWD,CHF,MXN,MDL,NZD,NOK,PYG,PEN,PLN,RON,SAR,RSD,SEK,TRY,AED,GBP,USD,UYU" }
+seven_eleven = { country = "JP", currency = "JPY" }
+lawson = { country = "JP", currency = "JPY" }
+mini_stop = { country = "JP", currency = "JPY" }
+family_mart = { country = "JP", currency = "JPY" }
+seicomart = { country = "JP", currency = "JPY" }
+pay_easy = { country = "JP", currency = "JPY" }
+pix = { country = "BR", currency = "BRL" }
+boleto = { country = "BR", currency = "BRL" }
+
+[pm_filters.affirm]
+affirm = { country = "CA,US", currency = "CAD,USD" }
+
+[pm_filters.airwallex]
+credit = { country = "AU,HK,SG,NZ,US", currency = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BYN,BZD,CAD,CDF,CHF,CLP,CNY,COP,CRC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLE,SLL,SOS,SRD,SSP,STN,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL" }
+debit = { country = "AU,HK,SG,NZ,US", currency = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BYN,BZD,CAD,CDF,CHF,CLP,CNY,COP,CRC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLE,SLL,SOS,SRD,SSP,STN,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL" }
+google_pay = { country = "AL, DZ, AS, AO, AG, AR, AU, AZ, BH, BR, BG, CA, CL, CO, CZ, DK, DO, EG, HK, HU, ID, IL, JP, JO, KZ, KE, KW, LB, MY, MX, OM, PK, PA, PE, PH, PL, QA, RO, SA, SG, ZA, LK, SE, TW, TH, TR, UA, AE, UY, VN, AT, BE, HR, EE, FI, FR, DE, GR, IE, IT, LV, LT, LU, NL, PL, PT, SK, ES, SE, RO, BG", currency = "ALL, DZD, USD, AOA, XCD, ARS, AUD, EUR, AZN, BHD, BRL, BGN, CAD, CLP, COP, CZK, DKK, DOP, EGP, HKD, HUF, INR, IDR, ILS, JPY, JOD, KZT, KES, KWD, LBP, MYR, MXN, NZD, NOK, OMR, PKR, PAB, PEN, PHP, PLN, QAR, RON, SAR, SGD, ZAR, LKR, SEK, CHF, TWD, THB, TRY, UAH, AED, GBP, UYU, VND" }
+paypal = { currency = "AUD,BRL,CAD,CZK,DKK,EUR,HKD,HUF,JPY,MYR,MXN,NOK,NZD,PHP,PLN,GBP,RUB,SGD,SEK,CHF,THB,USD" }
+klarna = { currency = "EUR, DKK, NOK, PLN, SEK, CHF, GBP, USD, CZK" }
+trustly = {currency="DKK, EUR, GBP, NOK, PLN, SEK" }
+blik = { country="PL" , currency = "PLN" }
+ideal = { country="NL" , currency = "EUR" }
+atome = { country = "SG, MY" , currency = "SGD, MYR" }
+skrill = { country="AL, DZ, AD, AR, AM, AW, AU, AT, AZ, BS, BD, BE, BJ, BO, BA, BW, BR, BN, BG, KH, CM, CA, CL, CN, CX, CO, CR , HR, CW, CY, CZ, DK, DM, DO, EC, EG, EE , FK, FI, GE, DE, GH, GI, GR, GP, GU, GT, GG, HK, HU, IS, IN, ID , IQ, IE, IM, IL, IT, JE , KZ, KE , KR, KW, KG, LV , LS, LI, LT, LU , MK, MG, MY, MV, MT, MU, YT, MX, MD, MC, MN, ME, MA, NA, NP, NZ, NI, NE, NO, PK , PA, PY, PE, PH, PL, PT, PR, QA, RO , SM , SA, SN , SG, SX, SK, SI, ZA, SS, ES, LK, SE, CH, TW, TZ, TH, TN, AE, GB, UM, UY, VN, VG, VI, US" , currency = "EUR, GBP, USD" }
+indonesian_bank_transfer = { country="ID" , currency = "IDR" }
+
+[pm_filters.elavon]
+credit = { country = "US", currency = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BYN,BZD,CAD,CDF,CHF,CLP,CNY,COP,CRC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLE,SLL,SOS,SRD,SSP,STN,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL" }
+debit = { country = "US", currency = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BYN,BZD,CAD,CDF,CHF,CLP,CNY,COP,CRC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLE,SLL,SOS,SRD,SSP,STN,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL" }
+
+[pm_filters.xendit]
+credit = { country = "ID,PH", currency = "IDR,PHP,USD,SGD,MYR" }
+debit = { country = "ID,PH", currency = "IDR,PHP,USD,SGD,MYR" }
+qris = {currency = "IDR" }
+
+[pm_filters.tsys]
+credit = { country = "NA", currency = "AED, AFN, ALL, AMD, ANG, AOA, ARS, AUD, AWG, AZN, BAM, BBD, BDT, BGN, BHD, BIF, BMD, BND, BOB, BRL, BSD, BTN, BWP, BZD, CAD, CDF, CHF, CLP, CNY, COP, CRC, CUP, CVE, CZK, DJF, DKK, DOP, DZD, EGP, ERN, ETB, EUR, FJD, FKP, GBP, GEL, GHS, GIP, GMD, GNF, GTQ, GYD, HKD, HNL, HRK, HTG, HUF, IDR, ILS, INR, IQD, IRR, ISK, JMD, JOD, JPY, KES, KGS, KHR, KMF, KRW, KWD, KYD, KZT, LAK, LBP, LKR, LRD, LSL, LYD, MAD, MDL, MGA, MKD, MMK, MNT, MOP, MUR, MVR, MWK, MXN, MYR, MZN, NAD, NGN, NIO, NOK, NPR, NZD, OMR, PAB, PEN, PGK, PHP, PKR, PLN, PYG, QAR, RON, RSD, RUB, RWF, SAR, SBD, SCR, SDG, SEK, SGD, SHP, SLE, SOS, SRD, SSP, SVC, SYP, SZL, THB, TJS, TMT, TND, TOP, TRY, TTD, TWD, TZS, UAH, UGX, USD, UYU, UZS, VND, VUV, WST, XAF, XCD, XOF, XPF, YER, ZAR, ZMW, ZWL, BYN, KPW, STN, MRU, VES" }
+debit = { country = "NA", currency = "AED, AFN, ALL, AMD, ANG, AOA, ARS, AUD, AWG, AZN, BAM, BBD, BDT, BGN, BHD, BIF, BMD, BND, BOB, BRL, BSD, BTN, BWP, BZD, CAD, CDF, CHF, CLP, CNY, COP, CRC, CUP, CVE, CZK, DJF, DKK, DOP, DZD, EGP, ERN, ETB, EUR, FJD, FKP, GBP, GEL, GHS, GIP, GMD, GNF, GTQ, GYD, HKD, HNL, HRK, HTG, HUF, IDR, ILS, INR, IQD, IRR, ISK, JMD, JOD, JPY, KES, KGS, KHR, KMF, KRW, KWD, KYD, KZT, LAK, LBP, LKR, LRD, LSL, LYD, MAD, MDL, MGA, MKD, MMK, MNT, MOP, MUR, MVR, MWK, MXN, MYR, MZN, NAD, NGN, NIO, NOK, NPR, NZD, OMR, PAB, PEN, PGK, PHP, PKR, PLN, PYG, QAR, RON, RSD, RUB, RWF, SAR, SBD, SCR, SDG, SEK, SGD, SHP, SLE, SOS, SRD, SSP, SVC, SYP, SZL, THB, TJS, TMT, TND, TOP, TRY, TTD, TWD, TZS, UAH, UGX, USD, UYU, UZS, VND, VUV, WST, XAF, XCD, XOF, XPF, YER, ZAR, ZMW, ZWL, BYN, KPW, STN, MRU, VES" }
+
+[pm_filters.billwerk]
+credit = { country = "DE, DK, FR, SE", currency = "DKK, NOK" }
+debit = { country = "DE, DK, FR, SE", currency = "DKK, NOK" }
+
+[pm_filters.fiservemea]
+credit = { country = "DE, FR, IT, NL, PL, ES, ZA, GB, AE", currency = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BYN,BZD,CAD,CDF,CHF,CLP,CNY,COP,CRC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLE,SLL,SOS,SRD,SSP,STN,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL" }
+debit = { country = "DE, FR, IT, NL, PL, ES, ZA, GB, AE", currency = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BYN,BZD,CAD,CDF,CHF,CLP,CNY,COP,CRC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLE,SLL,SOS,SRD,SSP,STN,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL" }
+
+[pm_filters.getnet]
+credit = { country = "AR, BR, CL, MX, UY, ES, PT, DE, IT, FR, NL, BE, AT, PL, CH, GB, IE, LU, DK, SE, NO, FI, IN, AE", currency = "ARS, BRL, CLP, MXN, UYU, EUR, PLN, CHF, GBP, DKK, SEK, NOK, INR, AED" }
+
+[pm_filters.hipay]
+credit = { country = "GB, CH, SE, DK, NO, PL, CZ, US, CA, JP, HK, AU, ZA", currency = "EUR, GBP, CHF, SEK, DKK, NOK, PLN, CZK, USD, CAD, JPY, HKD, AUD, ZAR" }
+debit = { country = "GB, CH, SE, DK, NO, PL, CZ, US, CA, JP, HK, AU, ZA", currency = "EUR, GBP, CHF, SEK, DKK, NOK, PLN, CZK, USD, CAD, JPY, HKD, AUD, ZAR" }
+
+[pm_filters.moneris]
+credit = { country = "AE, AF, AL, AO, AR, AT, AU, AW, AZ, BA, BB, BD, BE, BG, BH, BI, BM, BN, BO, BR, BT, BY, BZ, CH, CL, CN, CO, CR, CU, CV, CY, CZ, DE, DJ, DK, DO, DZ, EE, EG, ES, FI, FJ, FR, GB, GE, GI, GM, GN, GR, GT, GY, HK, HN, HR, HT, HU, ID, IE, IL, IN, IS, IT, JM, JO, JP, KE, KM, KR, KW, KY, KZ, LA, LK, LR, LS, LV, LT, LU, MA, MD, MG, MK, MO, MR, MT, MU, MV, MW, MX, MY, MZ, NA, NG, NI, NL, NO, NP, NZ, OM, PE, PG, PK, PL, PT, PY, QA, RO, RS, RU, RW, SA, SB, SC, SE, SG, SH, SI, SK, SL, SR, SV, SZ, TH, TJ, TM, TN, TR, TT, TW, TZ, UG, US, UY, UZ, VN, VU, WS, ZA, ZM", currency = "AED, AFN, ALL, ANG, AOA, ARS, AUD, AWG, AZN, BAM, BBD, BDT, BGN, BHD, BIF, BMD, BND, BOB, BRL, BTN, BYN, BZD, CHF, CLP, CNY, COP, CRC, CUP, CVE, CZK, DJF, DKK, DOP, DZD, EGP, EUR, FJD, GBP, GEL, GIP, GMD, GNF, GTQ, GYD, HKD, HNL, HRK, HTG, HUF, IDR, ILS, INR, ISK, JMD, JOD, JPY, KES, KMF, KRW, KWD, KYD, KZT, LAK, LKR, LRD, LSL, MAD, MDL, MGA, MKD, MOP, MRU, MUR, MVR, MWK, MXN, MYR, MZN, NAD, NGN, NIO, NOK, NPR, NZD, OMR, PEN, PGK, PHP, PKR, PLN, PYG, QAR, RON, RSD, RUB, RWF, SAR, SBD, SCR, SEK, SGD, SHP, SLL, SRD, SVC, SZL, THB, TJS, TMT, TND, TRY, TTD, TWD, TZS, UGX, USD, UYU, UZS, VND, VUV, WST, XCD, XOF, XPF, ZAR, ZMW" }
+debit = { country = "AE, AF, AL, AO, AR, AT, AU, AW, AZ, BA, BB, BD, BE, BG, BH, BI, BM, BN, BO, BR, BT, BY, BZ, CH, CL, CN, CO, CR, CU, CV, CY, CZ, DE, DJ, DK, DO, DZ, EE, EG, ES, FI, FJ, FR, GB, GE, GI, GM, GN, GR, GT, GY, HK, HN, HR, HT, HU, ID, IE, IL, IN, IS, IT, JM, JO, JP, KE, KM, KR, KW, KY, KZ, LA, LK, LR, LS, LV, LT, LU, MA, MD, MG, MK, MO, MR, MT, MU, MV, MW, MX, MY, MZ, NA, NG, NI, NL, NO, NP, NZ, OM, PE, PG, PK, PL, PT, PY, QA, RO, RS, RU, RW, SA, SB, SC, SE, SG, SH, SI, SK, SL, SR, SV, SZ, TH, TJ, TM, TN, TR, TT, TW, TZ, UG, US, UY, UZ, VN, VU, WS, ZA, ZM", currency = "AED, AFN, ALL, ANG, AOA, ARS, AUD, AWG, AZN, BAM, BBD, BDT, BGN, BHD, BIF, BMD, BND, BOB, BRL, BTN, BYN, BZD, CHF, CLP, CNY, COP, CRC, CUP, CVE, CZK, DJF, DKK, DOP, DZD, EGP, EUR, FJD, GBP, GEL, GIP, GMD, GNF, GTQ, GYD, HKD, HNL, HRK, HTG, HUF, IDR, ILS, INR, ISK, JMD, JOD, JPY, KES, KMF, KRW, KWD, KYD, KZT, LAK, LKR, LRD, LSL, MAD, MDL, MGA, MKD, MOP, MRU, MUR, MVR, MWK, MXN, MYR, MZN, NAD, NGN, NIO, NOK, NPR, NZD, OMR, PEN, PGK, PHP, PKR, PLN, PYG, QAR, RON, RSD, RUB, RWF, SAR, SBD, SCR, SEK, SGD, SHP, SLL, SRD, SVC, SZL, THB, TJS, TMT, TND, TRY, TTD, TWD, TZS, UGX, USD, UYU, UZS, VND, VUV, WST, XCD, XOF, XPF, ZAR, ZMW" }
+
+[pm_filters.opennode]
+crypto_currency = { country = "US, CA, GB, AU, BR, MX, SG, PH, NZ, ZA, JP, AT, BE, HR, CY, EE, FI, FR, DE, GR, IE, IT, LV, LT, LU, MT, NL, PT, SK, SI, ES", currency = "USD, CAD, GBP, AUD, BRL, MXN, SGD, PHP, NZD, ZAR, JPY, EUR" }
+
+[pm_filters.bambora]
+credit = { country = "US,CA", currency = "USD" }
+debit = { country = "US,CA", currency = "USD" }
+
+[pm_filters.bankofamerica]
+credit = { country = "AF,AL,DZ,AD,AO,AI,AG,AR,AM,AW,AU,AT,AZ,BS,BH,BD,BB,BY,BE,BZ,BJ,BM,BT,BO,BA,BW,BN,BG,BF,BI,KH,CM,CA,CV,KY,CF,TD,CL,CN,CO,KM,CD,CG,CK,CR,HR,CU,CW,CY,CZ,DK,DJ,DM,DO,EC,SV,GQ,ER,EE,ET,FK,FO,FJ,FI,FR,GF,PF,TF,GA,GM,GE,DE,GH,GI,GR,GL,GD,GP,GU,GT,GG,GN,GW,GY,HT,HM,VA,HN,HK,HU,IS,ID,IR,IQ,IE,IM,IL,IT,JM,JP,JE,JO,KZ,KE,KI,KR,KW,KG,LA,LV,LB,LS,LR,LY,LI,LT,LU,MO,MG,MW,MY,MV,ML,MT,MH,MR,MU,MX,FM,MD,MC,MN,ME,MS,MA,MZ,MM,NA,NR,NP,NL,NC,NZ,NI,NE,NG,NU,NO,OM,PK,PW,PS,PA,PG,PY,PE,PH,PL,PT,PR,QA,CG,RO,RW,KN,LC,VC,WS,SM,ST,SA,SN,RS,SC,SL,SG,SX,SK,SI,SO,ZA,GS,ES,LK,SR,SJ,SZ,SE,CH,TW,TJ,TZ,TH,TL,TG,TO,TT,TN,TR,TM,TC,TV,UG,UA,AE,GB,US,UY,UZ,VU,VE,VN,VG,WF,YE,ZM,ZW", currency = "USD" }
+debit = { country = "AF,AL,DZ,AD,AO,AI,AG,AR,AM,AW,AU,AT,AZ,BS,BH,BD,BB,BY,BE,BZ,BJ,BM,BT,BO,BA,BW,BN,BG,BF,BI,KH,CM,CA,CV,KY,CF,TD,CL,CN,CO,KM,CD,CG,CK,CR,HR,CU,CW,CY,CZ,DK,DJ,DM,DO,EC,SV,GQ,ER,EE,ET,FK,FO,FJ,FI,FR,GF,PF,TF,GA,GM,GE,DE,GH,GI,GR,GL,GD,GP,GU,GT,GG,GN,GW,GY,HT,HM,VA,HN,HK,HU,IS,ID,IR,IQ,IE,IM,IL,IT,JM,JP,JE,JO,KZ,KE,KI,KR,KW,KG,LA,LV,LB,LS,LR,LY,LI,LT,LU,MO,MG,MW,MY,MV,ML,MT,MH,MR,MU,MX,FM,MD,MC,MN,ME,MS,MA,MZ,MM,NA,NR,NP,NL,NC,NZ,NI,NE,NG,NU,NO,OM,PK,PW,PS,PA,PG,PY,PE,PH,PL,PT,PR,QA,CG,RO,RW,KN,LC,VC,WS,SM,ST,SA,SN,RS,SC,SL,SG,SX,SK,SI,SO,ZA,GS,ES,LK,SR,SJ,SZ,SE,CH,TW,TJ,TZ,TH,TL,TG,TO,TT,TN,TR,TM,TC,TV,UG,UA,AE,GB,US,UY,UZ,VU,VE,VN,VG,WF,YE,ZM,ZW", currency = "USD" }
+apple_pay = { country = "AU,AT,BH,BE,BR,BG,CA,CL,CN,CO,CR,HR,CY,CZ,DK,DO,EC,EE,SV,FI,FR,DE,GR,GT,HN,HK,HU,IS,IN,IE,IL,IT,JP,JO,KZ,KW,LV,LI,LT,LU,MY,MT,MX,MC,ME,NL,NZ,NO,OM,PA,PY,PE,PL,PT,QA,RO,SA,SG,SK,SI,ZA,KR,ES,SE,CH,TW,AE,GB,US,UY,VN,VA", currency = "USD" }
+google_pay = { country = "AU,AT,BE,BR,CA,CL,CO,CR,CY,CZ,DK,DO,EC,EE,SV,FI,FR,DE,GR,GT,HN,HK,HU,IS,IN,IE,IL,IT,JP,JO,KZ,KW,LV,LI,LT,LU,MY,MT,MX,NL,NZ,NO,OM,PA,PY,PE,PL,PT,QA,RO,SA,SG,SK,SI,ZA,KR,ES,SE,CH,TW,AE,GB,US,UY,VN,VA", currency = "USD" }
+samsung_pay = { country = "AU,BH,BR,CA,CN,DK,FI,FR,DE,HK,IN,IT,JP,KZ,KR,KW,MY,NZ,NO,OM,QA,SA,SG,ZA,ES,SE,CH,TW,AE,GB,US", currency = "USD" }
+
+[pm_filters.cybersource]
+credit = { currency = "USD,GBP,EUR,PLN,SEK,XOF,CAD,KWD,QAR" }
+debit = { currency = "USD,GBP,EUR,PLN,SEK,XOF,CAD,KWD,QAR" }
+apple_pay = { currency = "ARS, CAD, CLP, COP, CNY, EUR, HKD, KWD, MYR, MXN, NZD, PEN, QAR, SAR, SGD, ZAR, UAH, GBP, AED, USD, PLN, SEK" }
+google_pay = { currency = "ARS, AUD, CAD, CLP, COP, EUR, HKD, INR, KWD, MYR, MXN, NZD, PEN, QAR, SAR, SGD, ZAR, UAH, AED, GBP, USD, PLN, SEK" }
+samsung_pay = { currency = "USD,GBP,EUR,SEK" }
+paze = { currency = "USD,SEK" }
+
+[pm_filters.barclaycard]
+credit = { currency = "USD,GBP,EUR,PLN,SEK" }
+debit = { currency = "USD,GBP,EUR,PLN,SEK" }
+google_pay = { currency = "ARS, AUD, CAD, CLP, COP, EUR, HKD, INR, KWD, MYR, MXN, NZD, PEN, QAR, SAR, SGD, ZAR, UAH, AED, GBP, USD, PLN, SEK" }
+apple_pay = { currency = "ARS, CAD, CLP, COP, CNY, EUR, HKD, KWD, MYR, MXN, NZD, PEN, QAR, SAR, SGD, ZAR, UAH, GBP, AED, USD, PLN, SEK" }
+
+
+[pm_filters.globepay]
+ali_pay = { country = "GB",currency = "GBP,CNY" }
+we_chat_pay = { country = "GB",currency = "GBP,CNY" }
+
+
+[pm_filters.itaubank]
+pix = { country = "BR", currency = "BRL" }
+
+[pm_filters.nexinets]
+credit = { country = "DE",currency = "EUR" }
+debit = { country = "DE",currency = "EUR" }
+ideal = { country = "DE",currency = "EUR" }
+giropay = { country = "DE",currency = "EUR" }
+sofort = { country = "DE",currency = "EUR" }
+eps = { country = "DE",currency = "EUR" }
+apple_pay = { country = "DE",currency = "EUR" }
+paypal = { country = "DE",currency = "EUR" }
+
+
+[pm_filters.nuvei]
+credit = { country = "AF,AX,AL,DZ,AS,AD,AO,AI,AQ,AG,AR,AM,AW,AU,AT,AZ,BS,BH,BD,BB,BY,BE,BZ,BJ,BM,BT,BO,BQ,BA,BW,BV,BR,IO,BN,BG,BF,BI,KH,CM,CA,CV,KY,CF,TD,CL,CN,CX,CC,CO,KM,CG,CD,CK,CR,CI,HR,CU,CW,CY,CZ,DK,DJ,DM,DO,EC,EG,SV,GQ,ER,EE,ET,FK,FO,FJ,FI,FR,GF,PF,TF,GA,GM,GE,DE,GH,GI,GR,GL,GD,GP,GU,GT,GG,GN,GW,GY,HT,HM,VA,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IM,IL,IT,JM,JP,JE,JO,KZ,KE,KI,KP,KR,KW,KG,LA,LV,LB,LS,LR,LY,LI,LT,LU,MO,MK,MG,MW,MY,MV,ML,MT,MH,MQ,MR,MU,YT,MX,FM,MD,MC,MN,ME,MS,MA,MZ,MM,NA,NR,NP,NL,NC,NZ,NI,NE,NG,NU,NF,MP,NO,OM,PK,PW,PS,PA,PG,PY,PE,PH,PN,PL,PT,PR,QA,RE,RO,RU,RW,BL,SH,KN,LC,MF,PM,VC,WS,SM,ST,SA,SN,RS,SC,SL,SG,SX,SK,SI,SB,SO,ZA,GS,SS,ES,LK,SD,SR,SJ,SZ,SE,CH,SY,TW,TJ,TZ,TH,TL,TG,TK,TO,TT,TN,TR,TM,TC,TV,UG,UA,AE,GB,UM,UY,UZ,VU,VE,VN,VG,VI,WF,EH,YE,ZM,ZW,US",currency = "AED,ALL,AMD,ARS,AUD,AZN,BAM,BDT,BGN,BHD,BMD,BND,BRL,BYN,CAD,CHF,CLP,CNY,COP,CRC,CZK,DKK,DOP,DZD,EGP,EUR,GBP,GEL,GHS,GTQ,HKD,HUF,IDR,INR,IQD,ISK,JOD,JPY,KES,KGS,KRW,KWD,KYD,KZT,LBP,LKR,MAD,MDL,MKD,MMK,MNT,MUR,MWK,MXN,MYR,MZN,NAD,NGN,NOK,NZD,OMR,PEN,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,SAR,SEK,SGD,SOS,THB,TND,TOP,TRY,TTD,TWD,UAH,UGX,USD,UYU,UZS,VND,XAF,XOF,YER,ZAR" }
+debit = { country = "AF,AX,AL,DZ,AS,AD,AO,AI,AQ,AG,AR,AM,AW,AU,AT,AZ,BS,BH,BD,BB,BY,BE,BZ,BJ,BM,BT,BO,BQ,BA,BW,BV,BR,IO,BN,BG,BF,BI,KH,CM,CA,CV,KY,CF,TD,CL,CN,CX,CC,CO,KM,CG,CD,CK,CR,CI,HR,CU,CW,CY,CZ,DK,DJ,DM,DO,EC,EG,SV,GQ,ER,EE,ET,FK,FO,FJ,FI,FR,GF,PF,TF,GA,GM,GE,DE,GH,GI,GR,GL,GD,GP,GU,GT,GG,GN,GW,GY,HT,HM,VA,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IM,IL,IT,JM,JP,JE,JO,KZ,KE,KI,KP,KR,KW,KG,LA,LV,LB,LS,LR,LY,LI,LT,LU,MO,MK,MG,MW,MY,MV,ML,MT,MH,MQ,MR,MU,YT,MX,FM,MD,MC,MN,ME,MS,MA,MZ,MM,NA,NR,NP,NL,NC,NZ,NI,NE,NG,NU,NF,MP,NO,OM,PK,PW,PS,PA,PG,PY,PE,PH,PN,PL,PT,PR,QA,RE,RO,RU,RW,BL,SH,KN,LC,MF,PM,VC,WS,SM,ST,SA,SN,RS,SC,SL,SG,SX,SK,SI,SB,SO,ZA,GS,SS,ES,LK,SD,SR,SJ,SZ,SE,CH,SY,TW,TJ,TZ,TH,TL,TG,TK,TO,TT,TN,TR,TM,TC,TV,UG,UA,AE,GB,UM,UY,UZ,VU,VE,VN,VG,VI,WF,EH,YE,ZM,ZW,US",currency = "AED,ALL,AMD,ARS,AUD,AZN,BAM,BDT,BGN,BHD,BMD,BND,BRL,BYN,CAD,CHF,CLP,CNY,COP,CRC,CZK,DKK,DOP,DZD,EGP,EUR,GBP,GEL,GHS,GTQ,HKD,HUF,IDR,INR,IQD,ISK,JOD,JPY,KES,KGS,KRW,KWD,KYD,KZT,LBP,LKR,MAD,MDL,MKD,MMK,MNT,MUR,MWK,MXN,MYR,MZN,NAD,NGN,NOK,NZD,OMR,PEN,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,SAR,SEK,SGD,SOS,THB,TND,TOP,TRY,TTD,TWD,UAH,UGX,USD,UYU,UZS,VND,XAF,XOF,YER,ZAR" }
+klarna = { country = "AU,CA,GB,IN,JP,NZ,PH,SG,TH,US",currency = "AED,ALL,AMD,ARS,AUD,AZN,BAM,BDT,BGN,BHD,BMD,BND,BRL,BYN,CAD,CHF,CLP,CNY,COP,CRC,CZK,DKK,DOP,DZD,EGP,EUR,GBP,GEL,GHS,GTQ,HKD,HUF,IDR,INR,IQD,ISK,JOD,JPY,KES,KGS,KRW,KWD,KYD,KZT,LBP,LKR,MAD,MDL,MKD,MMK,MNT,MUR,MWK,MXN,MYR,MZN,NAD,NGN,NOK,NZD,OMR,PEN,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,SAR,SEK,SGD,SOS,THB,TND,TOP,TRY,TTD,TWD,UAH,UGX,USD,UYU,UZS,VND,XAF,XOF,YER,ZAR" }
+afterpay_clearpay = { country = "AU,CA,GB,IN,JP,NZ,PH,SG,TH,US",currency = "AED,ALL,AMD,ARS,AUD,AZN,BAM,BDT,BGN,BHD,BMD,BND,BRL,BYN,CAD,CHF,CLP,CNY,COP,CRC,CZK,DKK,DOP,DZD,EGP,EUR,GBP,GEL,GHS,GTQ,HKD,HUF,IDR,INR,IQD,ISK,JOD,JPY,KES,KGS,KRW,KWD,KYD,KZT,LBP,LKR,MAD,MDL,MKD,MMK,MNT,MUR,MWK,MXN,MYR,MZN,NAD,NGN,NOK,NZD,OMR,PEN,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,SAR,SEK,SGD,SOS,THB,TND,TOP,TRY,TTD,TWD,UAH,UGX,USD,UYU,UZS,VND,XAF,XOF,YER,ZAR" }
+giropay = { currency = "EUR" }
+ideal = { currency = "EUR" }
+sofort = { country = "AU,CA,GB,IN,JP,NZ,PH,SG,TH,US",currency = "AED,ALL,AMD,ARS,AUD,AZN,BAM,BDT,BGN,BHD,BMD,BND,BRL,BYN,CAD,CHF,CLP,CNY,COP,CRC,CZK,DKK,DOP,DZD,EGP,EUR,GBP,GEL,GHS,GTQ,HKD,HUF,IDR,INR,IQD,ISK,JOD,JPY,KES,KGS,KRW,KWD,KYD,KZT,LBP,LKR,MAD,MDL,MKD,MMK,MNT,MUR,MWK,MXN,MYR,MZN,NAD,NGN,NOK,NZD,OMR,PEN,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,SAR,SEK,SGD,SOS,THB,TND,TOP,TRY,TTD,TWD,UAH,UGX,USD,UYU,UZS,VND,XAF,XOF,YER,ZAR" }
+eps = { country = "AU,CA,GB,IN,JP,NZ,PH,SG,TH,US",currency = "AED,ALL,AMD,ARS,AUD,AZN,BAM,BDT,BGN,BHD,BMD,BND,BRL,BYN,CAD,CHF,CLP,CNY,COP,CRC,CZK,DKK,DOP,DZD,EGP,EUR,GBP,GEL,GHS,GTQ,HKD,HUF,IDR,INR,IQD,ISK,JOD,JPY,KES,KGS,KRW,KWD,KYD,KZT,LBP,LKR,MAD,MDL,MKD,MMK,MNT,MUR,MWK,MXN,MYR,MZN,NAD,NGN,NOK,NZD,OMR,PEN,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,SAR,SEK,SGD,SOS,THB,TND,TOP,TRY,TTD,TWD,UAH,UGX,USD,UYU,UZS,VND,XAF,XOF,YER,ZAR" }
+apple_pay = { country = "AU,AT,BY,BE,BR,BG,CA,CN,HR,CY,CZ,DK,EE,FO,FI,FR,GE,DE,GR,GL,GG,HK,HU,IS,IE,IM,IL,IT,JP,JE,KZ,LV,LI,LT,LU,MO,MT,MC,NL,NZ,NO,PL,PT,RO,RU,SM,SA,SG,SK,SI,ES,SE,CH,TW,UA,AE,GB,US,VA",currency = "AED,ALL,AMD,ARS,AUD,AZN,BAM,BDT,BGN,BHD,BMD,BND,BRL,BYN,CAD,CHF,CLP,CNY,COP,CRC,CZK,DKK,DOP,DZD,EGP,EUR,GBP,GEL,GHS,GTQ,HKD,HUF,IDR,INR,IQD,ISK,JOD,JPY,KES,KGS,KRW,KWD,KYD,KZT,LBP,LKR,MAD,MDL,MKD,MMK,MNT,MUR,MWK,MXN,MYR,MZN,NAD,NGN,NOK,NZD,OMR,PEN,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,SAR,SEK,SGD,SOS,THB,TND,TOP,TRY,TTD,TWD,UAH,UGX,USD,UYU,UZS,VND,XAF,XOF,YER,ZAR" }
+google_pay = { country = "AF,AX,AL,DZ,AD,AO,AI,AQ,AG,AR,AM,AW,AU,AT,AZ,BS,BH,BD,BB,BY,BE,BZ,BJ,BM,BT,BO,BQ,BA,BW,BV,BR,IO,BN,BG,BF,KH,CM,CA,CV,KY,CF,TD,CL,CN,TW,CX,CC,CO,KM,CG,CK,CR,CI,HR,CW,CY,CZ,DK,DJ,DM,DO,EC,EG,SV,GQ,ER,EE,ET,FK,FO,FJ,FI,FR,GF,PF,TF,GA,GM,GE,DE,GH,GI,GR,GL,GD,GP,GU,GT,GG,GN,GW,GY,HT,HM,HN,HK,HU,IS,IN,ID,IQ,IE,IM,IL,IT,JM,JP,JE,JO,KZ,KE,KI,KW,KG,LA,LV,LB,LS,LR,LY,LI,LT,LU,MO,MK,MG,MW,MY,MV,ML,MT,MH,MQ,MR,MU,YT,MX,FM,MD,MC,MN,ME,MS,MA,MZ,MM,NA,NR,NP,NL,NC,NZ,NI,NE,NG,NU,NF,MP,NO,OM,PK,PW,PS,PA,PG,PY,PE,PH,PN,PL,PT,PR,QA,RE,RO,RU,RW,BL,SH,KN,LC,MF,PM,VI,VC,WS,SM,ST,SA,SN,RS,SC,SL,SG,SK,SI,SB,SO,ZA,GS,KR,ES,LK,SR,SJ,SZ,SE,CH,TW,TJ,TZ,TH,TL,TG,TK,TO,TT,TN,TR,TM,TC,TV,UG,UA,AE,GB,UY,UZ,VU,VA,VE,VN,VI,WF,EH,YE,ZM,ZW,US",currency = "AED,ALL,AMD,ARS,AUD,AZN,BAM,BDT,BGN,BHD,BMD,BND,BRL,BYN,CAD,CHF,CLP,CNY,COP,CRC,CZK,DKK,DOP,DZD,EGP,EUR,GBP,GEL,GHS,GTQ,HKD,HUF,IDR,INR,IQD,ISK,JOD,JPY,KES,KGS,KRW,KWD,KYD,KZT,LBP,LKR,MAD,MDL,MKD,MMK,MNT,MUR,MWK,MXN,MYR,MZN,NAD,NGN,NOK,NZD,OMR,PEN,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,SAR,SEK,SGD,SOS,THB,TND,TOP,TRY,TTD,TWD,UAH,UGX,USD,UYU,UZS,VND,XAF,XOF,YER,ZAR" }
+paypal = { country = "AU,CA,GB,IN,JP,NZ,PH,SG,TH,US",currency = "AED,ALL,AMD,ARS,AUD,AZN,BAM,BDT,BGN,BHD,BMD,BND,BRL,BYN,CAD,CHF,CLP,CNY,COP,CRC,CZK,DKK,DOP,DZD,EGP,EUR,GBP,GEL,GHS,GTQ,HKD,HUF,IDR,INR,IQD,ISK,JOD,JPY,KES,KGS,KRW,KWD,KYD,KZT,LBP,LKR,MAD,MDL,MKD,MMK,MNT,MUR,MWK,MXN,MYR,MZN,NAD,NGN,NOK,NZD,OMR,PEN,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,SAR,SEK,SGD,SOS,THB,TND,TOP,TRY,TTD,TWD,UAH,UGX,USD,UYU,UZS,VND,XAF,XOF,YER,ZAR" }
+
+[payout_method_filters.nuvei]
+credit = { country = "AF,AX,AL,DZ,AS,AD,AO,AI,AQ,AG,AR,AM,AW,AU,AT,AZ,BS,BH,BD,BB,BY,BE,BZ,BJ,BM,BT,BO,BQ,BA,BW,BV,BR,IO,BN,BG,BF,BI,KH,CM,CA,CV,KY,CF,TD,CL,CN,CX,CC,CO,KM,CG,CD,CK,CR,CI,HR,CU,CW,CY,CZ,DK,DJ,DM,DO,EC,EG,SV,GQ,ER,EE,ET,FK,FO,FJ,FI,FR,GF,PF,TF,GA,GM,GE,DE,GH,GI,GR,GL,GD,GP,GU,GT,GG,GN,GW,GY,HT,HM,VA,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IM,IL,IT,JM,JP,JE,JO,KZ,KE,KI,KP,KR,KW,KG,LA,LV,LB,LS,LR,LY,LI,LT,LU,MO,MK,MG,MW,MY,MV,ML,MT,MH,MQ,MR,MU,YT,MX,FM,MD,MC,MN,ME,MS,MA,MZ,MM,NA,NR,NP,NL,NC,NZ,NI,NE,NG,NU,NF,MP,NO,OM,PK,PW,PS,PA,PG,PY,PE,PH,PN,PL,PT,PR,QA,RE,RO,RU,RW,BL,SH,KN,LC,MF,PM,VC,WS,SM,ST,SA,SN,RS,SC,SL,SG,SX,SK,SI,SB,SO,ZA,GS,SS,ES,LK,SD,SR,SJ,SZ,SE,CH,SY,TW,TJ,TZ,TH,TL,TG,TK,TO,TT,TN,TR,TM,TC,TV,UG,UA,AE,GB,UM,UY,UZ,VU,VE,VN,VG,VI,WF,EH,YE,ZM,ZW,US",currency = "AED,ALL,AMD,ARS,AUD,AZN,BAM,BDT,BGN,BHD,BMD,BND,BRL,BYN,CAD,CHF,CLP,CNY,COP,CRC,CZK,DKK,DOP,DZD,EGP,EUR,GBP,GEL,GHS,GTQ,HKD,HUF,IDR,INR,IQD,ISK,JOD,JPY,KES,KGS,KRW,KWD,KYD,KZT,LBP,LKR,MAD,MDL,MKD,MMK,MNT,MUR,MWK,MXN,MYR,MZN,NAD,NGN,NOK,NZD,OMR,PEN,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,SAR,SEK,SGD,SOS,THB,TND,TOP,TRY,TTD,TWD,UAH,UGX,USD,UYU,UZS,VND,XAF,XOF,YER,ZAR" }
+debit = { country = "AF,AX,AL,DZ,AS,AD,AO,AI,AQ,AG,AR,AM,AW,AU,AT,AZ,BS,BH,BD,BB,BY,BE,BZ,BJ,BM,BT,BO,BQ,BA,BW,BV,BR,IO,BN,BG,BF,BI,KH,CM,CA,CV,KY,CF,TD,CL,CN,CX,CC,CO,KM,CG,CD,CK,CR,CI,HR,CU,CW,CY,CZ,DK,DJ,DM,DO,EC,EG,SV,GQ,ER,EE,ET,FK,FO,FJ,FI,FR,GF,PF,TF,GA,GM,GE,DE,GH,GI,GR,GL,GD,GP,GU,GT,GG,GN,GW,GY,HT,HM,VA,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IM,IL,IT,JM,JP,JE,JO,KZ,KE,KI,KP,KR,KW,KG,LA,LV,LB,LS,LR,LY,LI,LT,LU,MO,MK,MG,MW,MY,MV,ML,MT,MH,MQ,MR,MU,YT,MX,FM,MD,MC,MN,ME,MS,MA,MZ,MM,NA,NR,NP,NL,NC,NZ,NI,NE,NG,NU,NF,MP,NO,OM,PK,PW,PS,PA,PG,PY,PE,PH,PN,PL,PT,PR,QA,RE,RO,RU,RW,BL,SH,KN,LC,MF,PM,VC,WS,SM,ST,SA,SN,RS,SC,SL,SG,SX,SK,SI,SB,SO,ZA,GS,SS,ES,LK,SD,SR,SJ,SZ,SE,CH,SY,TW,TJ,TZ,TH,TL,TG,TK,TO,TT,TN,TR,TM,TC,TV,UG,UA,AE,GB,UM,UY,UZ,VU,VE,VN,VG,VI,WF,EH,YE,ZM,ZW,US",currency = "AED,ALL,AMD,ARS,AUD,AZN,BAM,BDT,BGN,BHD,BMD,BND,BRL,BYN,CAD,CHF,CLP,CNY,COP,CRC,CZK,DKK,DOP,DZD,EGP,EUR,GBP,GEL,GHS,GTQ,HKD,HUF,IDR,INR,IQD,ISK,JOD,JPY,KES,KGS,KRW,KWD,KYD,KZT,LBP,LKR,MAD,MDL,MKD,MMK,MNT,MUR,MWK,MXN,MYR,MZN,NAD,NGN,NOK,NZD,OMR,PEN,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,SAR,SEK,SGD,SOS,THB,TND,TOP,TRY,TTD,TWD,UAH,UGX,USD,UYU,UZS,VND,XAF,XOF,YER,ZAR" }
+
+[pm_filters.checkout]
+debit = { country = "AT,BE,BG,HR,CY,CZ,DK,EE,FI,FR,DE,GR,HU,IS,IE,IT,LV,LI,LT,LU,MT,NL,NO,PL,PT,RO,SK,SI,ES,SE,CH,GB,US,AU,HK,SG,SA,AE,BH,MX,AR,CL,CO,PE", currency = "AED,AFN,ALL,AMD,ANG,AOA,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BYN,BZD,CAD,CDF,CHF,CLP,CNY,COP,CRC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLE,SLL,SOS,SRD,SSP,STN,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL" }
+credit = { country = "AT,BE,BG,HR,CY,CZ,DK,EE,FI,FR,DE,GR,HU,IS,IE,IT,LV,LI,LT,LU,MT,NL,NO,PL,PT,RO,SK,SI,ES,SE,CH,GB,US,AU,HK,SG,SA,AE,BH,MX,AR,CL,CO,PE", currency = "AED,AFN,ALL,AMD,ANG,AOA,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BYN,BZD,CAD,CDF,CHF,CLP,CNY,COP,CRC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLE,SLL,SOS,SRD,SSP,STN,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL" }
+google_pay = { country = "AL,DZ, AS, AO, AG, AR, AU, AT, AZ, BH, BY, BE, BR, CA, BG, CL, CO, HR, DK, DO, EE, EG, FI, FR, DE, GR, HK, HU, IN, ID, IE, IL, IT, JP, JO, KZ, KE, KW, LV, LB, LT, LU, MY, MX, NL, NZ, NO, OM, PK, PA, PE, PH, PL, PT, QA, RO, SA, SG, SK, ZA, ES, LK, SE, CH, TH, TW, TR, UA, AE, US, UY, VN", currency = "AED, ALL, AOA, AUD, AZN, BGN, BHD, BRL, CAD, CHF, CLP, COP, CZK, DKK, DOP, DZD, EGP, EUR, GBP, HKD, HUF, IDR, ILS, INR, JPY, KES, KWD, KZT, LKR, MXN, MYR, NOK, NZD, OMR, PAB, PEN, PHP, PKR, PLN, QAR, RON, SAR, SEK, SGD, THB, TRY, TWD, UAH, USD, UYU, VND, XCD, ZAR" }
+apple_pay = { country = "AM,US, AT, AZ, BY, BE, BG, HR, CY, DK, EE, FO, FI, FR, GE, DE, GR, GL, GG, HU, IS, IE, IM, IT, KZ, JE, LV, LI, LT, LU, MT, MD, MC, ME, NL, NO, PL, PT, RO, SM, RS, SK, SI, ES, SE, CH, UA, GB, VA, AU , HK, JP , MY , MN, NZ, SG, TW, VN, EG , MA, ZA, AR, BR, CL, CO, CR, DO, EC, SV, GT, HN, MX, PA, PY, PE, UY, BH, IL, JO, KW, OM,QA, SA, AE, CA", currency = "EGP, MAD, ZAR, AUD, CNY, HKD, JPY, MOP, MYR, MNT, NZD, SGD, KRW, TWD, VND, AMD, EUR, BGN, CZK, DKK, GEL, GBP, HUF, ISK, KZT, CHF, MDL, NOK, PLN, RON, RSD, SEK, UAH, BRL, COP, CRC, DOP, GTQ, HNL, MXN, PAB, PYG, PEN, BSD, UYU, BHD, ILS, JOD, KWD, OMR, QAR, SAR, AED, CAD, USD" }
+
+[pm_filters.checkbook]
+ach = { country = "US", currency = "USD" }
+
+[pm_filters.nexixpay]
+credit = { country = "AT,BE,CY,EE,FI,FR,DE,GR,IE,IT,LV,LT,LU,MT,NL,PT,SK,SI,ES,BG,HR,DK,GB,NO,PL,CZ,RO,SE,CH,HU,AU,BR,US", currency = "ARS,AUD,BHD,CAD,CLP,CNY,COP,HRK,CZK,DKK,HKD,HUF,INR,JPY,KZT,JOD,KRW,KWD,MYR,MXN,NGN,NOK,PHP,QAR,RUB,SAR,SGD,VND,ZAR,SEK,CHF,THB,AED,EGP,GBP,USD,TWD,BYN,RSD,AZN,RON,TRY,AOA,BGN,EUR,UAH,PLN,BRL" }
+debit = { country = "AT,BE,CY,EE,FI,FR,DE,GR,IE,IT,LV,LT,LU,MT,NL,PT,SK,SI,ES,BG,HR,DK,GB,NO,PL,CZ,RO,SE,CH,HU,AU,BR,US", currency = "ARS,AUD,BHD,CAD,CLP,CNY,COP,HRK,CZK,DKK,HKD,HUF,INR,JPY,KZT,JOD,KRW,KWD,MYR,MXN,NGN,NOK,PHP,QAR,RUB,SAR,SGD,VND,ZAR,SEK,CHF,THB,AED,EGP,GBP,USD,TWD,BYN,RSD,AZN,RON,TRY,AOA,BGN,EUR,UAH,PLN,BRL" }
+
+[pm_filters.square]
+credit = { country = "AU,CA,FR,IE,JP,ES,GB,US", currency = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BZD,CAD,CDF,CHF,CLP,CNY,COP,CRC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLE,SLL,SOS,SRD,SSP,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW" }
+debit = { country = "AU,CA,FR,IE,JP,ES,GB,US", currency = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BZD,CAD,CDF,CHF,CLP,CNY,COP,CRC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLE,SLL,SOS,SRD,SSP,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW" }
+
+[pm_filters.iatapay]
+upi_collect = { country = "IN", currency = "INR" }
+upi_intent = { country = "IN", currency = "INR" }
+ideal = { country = "NL", currency = "EUR" }
+local_bank_redirect = { country = "AT,BE,EE,FI,FR,DE,IE,IT,LV,LT,LU,NL,PT,ES,GB,IN,HK,SG,TH,BR,MX,GH,VN,MY,PH,JO,AU,CO", currency = "EUR,GBP,INR,HKD,SGD,THB,BRL,MXN,GHS,VND,MYR,PHP,JOD,AUD,COP" }
+duit_now = { country = "MY", currency = "MYR" }
+fps = { country = "GB", currency = "GBP" }
+prompt_pay = { country = "TH", currency = "THB" }
+viet_qr = { country = "VN", currency = "VND" }
+
+[pm_filters.coinbase]
+crypto_currency = { country = "ZA,US,BR,CA,TR,SG,VN,GB,DE,FR,ES,PT,IT,NL,AU" }
+
+[pm_filters.novalnet]
+credit = { country = "AD,AE,AL,AM,AR,AT,AU,AZ,BA,BB,BD,BE,BG,BH,BI,BM,BN,BO,BR,BS,BW,BY,BZ,CA,CD,CH,CL,CN,CO,CR,CU,CY,CZ,DE,DJ,DK,DO,DZ,EE,EG,ET,ES,FI,FJ,FR,GB,GE,GH,GI,GM,GR,GT,GY,HK,HN,HR,HU,ID,IE,IL,IN,IS,IT,JM,JO,JP,KE,KH,KR,KW,KY,KZ,LB,LK,LT,LV,LY,MA,MC,MD,ME,MG,MK,MN,MO,MT,MV,MW,MX,MY,NG,NI,NO,NP,NL,NZ,OM,PA,PE,PG,PH,PK,PL,PT,PY,QA,RO,RS,RU,RW,SA,SB,SC,SE,SG,SH,SI,SK,SL,SO,SM,SR,ST,SV,SY,TH,TJ,TN,TO,TR,TW,TZ,UA,UG,US,UY,UZ,VE,VA,VN,VU,WS,CF,AG,DM,GD,KN,LC,VC,YE,ZA,ZM", currency = "AED,ALL,AMD,ARS,AUD,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BWP,BYN,BZD,CAD,CDF,CHF,CLP,CNY,COP,CRC,CUP,CZK,DJF,DKK,DOP,DZD,EGP,ETB,EUR,FJD,GBP,GEL,GHS,GIP,GMD,GTQ,GYD,HKD,HNL,HRK,HUF,IDR,ILS,INR,ISK,JMD,JOD,JPY,KES,KHR,KRW,KWD,KYD,KZT,LBP,LKR,LYD,MAD,MDL,MGA,MKD,MNT,MOP,MVR,MWK,MXN,MYR,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SEK,SGD,SHP,SLL,SOS,SRD,STN,SVC,SYP,THB,TJS,TND,TOP,TRY,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,YER,ZAR,ZMW" }
+debit = { country = "AD,AE,AL,AM,AR,AT,AU,AZ,BA,BB,BD,BE,BG,BH,BI,BM,BN,BO,BR,BS,BW,BY,BZ,CA,CD,CH,CL,CN,CO,CR,CU,CY,CZ,DE,DJ,DK,DO,DZ,EE,EG,ET,ES,FI,FJ,FR,GB,GE,GH,GI,GM,GR,GT,GY,HK,HN,HR,HU,ID,IE,IL,IN,IS,IT,JM,JO,JP,KE,KH,KR,KW,KY,KZ,LB,LK,LT,LV,LY,MA,MC,MD,ME,MG,MK,MN,MO,MT,MV,MW,MX,MY,NG,NI,NO,NP,NL,NZ,OM,PA,PE,PG,PH,PK,PL,PT,PY,QA,RO,RS,RU,RW,SA,SB,SC,SE,SG,SH,SI,SK,SL,SO,SM,SR,ST,SV,SY,TH,TJ,TN,TO,TR,TW,TZ,UA,UG,US,UY,UZ,VE,VA,VN,VU,WS,CF,AG,DM,GD,KN,LC,VC,YE,ZA,ZM", currency = "AED,ALL,AMD,ARS,AUD,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BWP,BYN,BZD,CAD,CDF,CHF,CLP,CNY,COP,CRC,CUP,CZK,DJF,DKK,DOP,DZD,EGP,ETB,EUR,FJD,GBP,GEL,GHS,GIP,GMD,GTQ,GYD,HKD,HNL,HRK,HUF,IDR,ILS,INR,ISK,JMD,JOD,JPY,KES,KHR,KRW,KWD,KYD,KZT,LBP,LKR,LYD,MAD,MDL,MGA,MKD,MNT,MOP,MVR,MWK,MXN,MYR,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SEK,SGD,SHP,SLL,SOS,SRD,STN,SVC,SYP,THB,TJS,TND,TOP,TRY,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,YER,ZAR,ZMW" }
+apple_pay = { country = "EG, MA, ZA, CN, HK, JP, MY, MN, SG, KR, VN, AT, BE, BG, HR, CY, CZ, DK, EE, FI, FR, GE, DE, GR, GL, HU, IS, IE, IT, LV, LI, LT, LU, MT, MD, MC, ME, NL, NO, PL, PT, RO, SM, RS, SK, SI, ES, SE, CH, UA, GB, VA, CA, US, BH, IL, JO, KW, OM, QA, SA, AE, AR, BR, CL, CO, CR, SV, GT, MX, PY, PE, UY, BS, DO, AM, KZ, NZ", currency = "EGP, MAD, ZAR, AUD, CNY, HKD, JPY, MOP, MYR, MNT, NZD, SGD, KRW, TWD, VND, AMD, EUR, AZN, BGN, CZK, DKK, GEL, GBP, HUF, ISK, KZT, CHF, MDL, NOK, PLN, RON, RSD, SEK, UAH, ARS, BRL, CLP, COP, CRC, DOP, USD, GTQ, HNL, MXN, PAB, PYG, PEN, BSD, UYU, BHD, ILS, JOD, KWD, OMR, QAR, SAR, AED, CAD" }
+google_pay = { country = "AO, EG, KE, ZA, AR, BR, CL, CO, MX, PE, UY, AG, DO, AE, TR, SA, QA, OM, LB, KW, JO, IL, BH, KZ, VN, TH, SG, MY, JP, HK, LK, IN, US, CA, GB, UA, CH, SE, ES, SK, PT, RO, PL, NO, NL, LU, LT, LV, IE, IT, HU, GR, DE, FR, FI, EE, DK, CZ, HR, BG, BE, AT, AL", currency = "ALL, DZD, USD, XCD, ARS, AUD, EUR, AZN, BHD, BRL, BGN, CAD, CLP, COP, CZK, DKK, DOP, EGP, HKD, HUF, INR, IDR, ILS, JPY, JOD, KZT, KES, KWD, LBP, MYR, MXN, NZD, NOK, OMR, PKR, PAB, PEN, PHP, PLN, QAR, RON, RUB, SAR, SGD, ZAR, LKR, SEK, CHF, TWD, THB, TRY, UAH, AED, GBP, UYU, VND" }
+paypal = { country = "AD,AE,AL,AM,AR,AT,AU,AZ,BA,BB,BD,BE,BG,BH,BI,BM,BN,BO,BR,BS,BW,BY,BZ,CA,CD,CH,CL,CN,CO,CR,CU,CY,CZ,DE,DJ,DK,DO,DZ,EE,EG,ET,ES,FI,FJ,FR,GB,GE,GH,GI,GM,GR,GT,GY,HK,HN,HR,HU,ID,IE,IL,IN,IS,IT,JM,JO,JP,KE,KH,KR,KW,KY,KZ,LB,LK,LT,LV,LY,MA,MC,MD,ME,MG,MK,MN,MO,MT,MV,MW,MX,MY,NG,NI,NO,NP,NL,NZ,OM,PA,PE,PG,PH,PK,PL,PT,PY,QA,RO,RS,RU,RW,SA,SB,SC,SE,SG,SH,SI,SK,SL,SO,SM,SR,ST,SV,SY,TH,TJ,TN,TO,TR,TW,TZ,UA,UG,US,UY,UZ,VE,VA,VN,VU,WS,CF,AG,DM,GD,KN,LC,VC,YE,ZA,ZM", currency = "AED,ALL,AMD,ARS,AUD,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BWP,BYN,BZD,CAD,CDF,CHF,CLP,CNY,COP,CRC,CUP,CZK,DJF,DKK,DOP,DZD,EGP,ETB,EUR,FJD,GBP,GEL,GHS,GIP,GMD,GTQ,GYD,HKD,HNL,HRK,HUF,IDR,ILS,INR,ISK,JMD,JOD,JPY,KES,KHR,KRW,KWD,KYD,KZT,LBP,LKR,LYD,MAD,MDL,MGA,MKD,MNT,MOP,MVR,MWK,MXN,MYR,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SEK,SGD,SHP,SLL,SOS,SRD,STN,SVC,SYP,THB,TJS,TND,TOP,TRY,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,YER,ZAR,ZMW" }
+sepa = {country = "FR, IT, GR, BE, BG, FI, EE, HR, IE, DE, DK, LT, LV, MT, LU, AT, NL, PT, RO, PL, SK, SE, ES, SI, HU, CZ, CY, GB, LI, NO, IS, MC, CH, YT, PM, SM", currency="EUR"}
+sepa_guaranteed_debit = {country = "AT, CH, DE", currency="EUR"}
+
+[pm_filters.braintree]
+credit = { country = "AD,AT,AU,BE,BG,CA,CH,CY,CZ,DE,DK,EE,ES,FI,FR,GB,GG,GI,GR,HK,HR,HU,IE,IM,IT,JE,LI,LT,LU,LV,MT,MC,MY,NL,NO,NZ,PL,PT,RO,SE,SG,SI,SK,SM,US", currency = "AED,AMD,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BIF,BMD,BND,BOB,BRL,BSD,BWP,BYN,BZD,CAD,CHF,CLP,CNY,COP,CRC,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,ISK,JMD,JPY,KES,KGS,KHR,KMF,KRW,KYD,KZT,LAK,LBP,LKR,LRD,LSL,MAD,MDL,MKD,MNT,MOP,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SEK,SGD,SHP,SLL,SOS,SRD,STD,SVC,SYP,SZL,THB,TJS,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL"}
+debit = { country = "AD,AT,AU,BE,BG,CA,CH,CY,CZ,DE,DK,EE,ES,FI,FR,GB,GG,GI,GR,HK,HR,HU,IE,IM,IT,JE,LI,LT,LU,LV,MT,MC,MY,NL,NO,NZ,PL,PT,RO,SE,SG,SI,SK,SM,US", currency = "AED,AMD,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BIF,BMD,BND,BOB,BRL,BSD,BWP,BYN,BZD,CAD,CHF,CLP,CNY,COP,CRC,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,ISK,JMD,JPY,KES,KGS,KHR,KMF,KRW,KYD,KZT,LAK,LBP,LKR,LRD,LSL,MAD,MDL,MKD,MNT,MOP,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SEK,SGD,SHP,SLL,SOS,SRD,STD,SVC,SYP,SZL,THB,TJS,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL"}
+
+[pm_filters.facilitapay]
+pix = { country = "BR", currency = "BRL" }
+
+[pm_filters.finix]
+credit = { country = "AF,AX,AL,DZ,AS,AD,AO,AI,AQ,AG,AR,AM,AW,AU,AT,AZ,BS,BH,BD,BB,BY,BE,BZ,BJ,BM,BT,BO,BQ,BA,BW,BV,BR,IO,BN,BG,BF,BI,KH,CM,CA,CV,KY,CF,TD,CL,CN,CX,CC,CO,KM,CG,CD,CK,CR,CI,HR,CU,CW,CY,CZ,DK,DJ,DM,DO,EC,EG,SV,GQ,ER,EE,ET,FK,FO,FJ,FI,FR,GF,PF,TF,GA,GM,GE,DE,GH,GI,GR,GL,GD,GP,GU,GT,GG,GN,GW,GY,HT,HM,VA,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IM,IL,IT,JM,JP,JE,JO,KZ,KE,KI,KP,KR,KW,KG,LA,LV,LB,LS,LR,LY,LI,LT,LU,MO,MK,MG,MW,MY,MV,ML,MT,MH,MQ,MR,MU,YT,MX,FM,MD,MC,MN,ME,MS,MA,MZ,MM,NA,NR,NP,NL,NC,NZ,NI,NE,NG,NU,NF,MP,NO,OM,PK,PW,PS,PA,PG,PY,PE,PH,PN,PL,PT,PR,QA,RE,RO,RU,RW,BL,SH,KN,LC,MF,PM,VC,WS,SM,ST,SA,SN,RS,SC,SL,SG,SX,SK,SI,SB,SO,ZA,GS,SS,ES,LK,SD,SR,SJ,SZ,SE,CH,SY,TW,TJ,TZ,TH,TL,TG,TK,TO,TT,TN,TR,TM,TC,TV,UG,UA,AE,GB,UM,UY,UZ,VU,VE,VN,VG,VI,WF,EH,YE,ZM,ZW,US", currency = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BYN,BZD,CAD,CDF,CHF,CLF,CLP,CNY,COP,CRC,CUC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLE,SLL,SOS,SRD,SSP,STD,STN,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL"}
+debit = { country = "AF,AX,AL,DZ,AS,AD,AO,AI,AQ,AG,AR,AM,AW,AU,AT,AZ,BS,BH,BD,BB,BY,BE,BZ,BJ,BM,BT,BO,BQ,BA,BW,BV,BR,IO,BN,BG,BF,BI,KH,CM,CA,CV,KY,CF,TD,CL,CN,CX,CC,CO,KM,CG,CD,CK,CR,CI,HR,CU,CW,CY,CZ,DK,DJ,DM,DO,EC,EG,SV,GQ,ER,EE,ET,FK,FO,FJ,FI,FR,GF,PF,TF,GA,GM,GE,DE,GH,GI,GR,GL,GD,GP,GU,GT,GG,GN,GW,GY,HT,HM,VA,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IM,IL,IT,JM,JP,JE,JO,KZ,KE,KI,KP,KR,KW,KG,LA,LV,LB,LS,LR,LY,LI,LT,LU,MO,MK,MG,MW,MY,MV,ML,MT,MH,MQ,MR,MU,YT,MX,FM,MD,MC,MN,ME,MS,MA,MZ,MM,NA,NR,NP,NL,NC,NZ,NI,NE,NG,NU,NF,MP,NO,OM,PK,PW,PS,PA,PG,PY,PE,PH,PN,PL,PT,PR,QA,RE,RO,RU,RW,BL,SH,KN,LC,MF,PM,VC,WS,SM,ST,SA,SN,RS,SC,SL,SG,SX,SK,SI,SB,SO,ZA,GS,SS,ES,LK,SD,SR,SJ,SZ,SE,CH,SY,TW,TJ,TZ,TH,TL,TG,TK,TO,TT,TN,TR,TM,TC,TV,UG,UA,AE,GB,UM,UY,UZ,VU,VE,VN,VG,VI,WF,EH,YE,ZM,ZW,US", currency = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BYN,BZD,CAD,CDF,CHF,CLF,CLP,CNY,COP,CRC,CUC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLE,SLL,SOS,SRD,SSP,STD,STN,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL"}
+google_pay = { country = "AD, AE, AG, AI, AM, AO, AQ, AR, AS, AT, AU, AW, AX, AZ, BA, BB, BD, BE, BF, BG, BH, BI, BJ, BM, BN, BO, BQ, BR, BS, BT, BV, BW, BZ, CA, CC, CG, CH, CI, CK, CL, CM, CN, CO, CR, CV, CW, CX, CY, CZ, DE, DJ, DK, DM, DO, DZ, EC, EE, EG, EH, ER, ES, FI, FJ, FK, FM, FO, FR, GA, GB, GD, GE, GF, GG, GH, GI, GL, GM, GN, GP, GQ, GR, GS, GT, GU, GW, GY, HK, HM, HN, HR, HT, HU, ID, IE, IL, IM, IN, IO, IS, IT, JE, JM, JO, JP, KE, KG, KH, KI, KM, KN, KR, KW, KY, KZ, LA, LC, LI, LK, LR, LS, LT, LU, LV, MA, MC, MD, ME, MF, MG, MH, MK, MN, MO, MP, MQ, MR, MS, MT, MU, MV, MW, MX, MY, MZ, NA, NC, NE, NF, NG, NL, NO, NP, NR, NU, NZ, OM, PA, PE, PF, PG, PH, PK, PL, PM, PN, PR, PT, PW, PY, QA, RE, RO, RS, RW, SA, SB, SC, SE, SG, SH, SI, SJ, SK, SL, SM, SN, SR, ST, SV, SX, SZ, TC, TD, TF, TG, TH, TJ, TK, TL, TM, TN, TO, TT, TV, TZ, UG, UM, UY, UZ, VA, VC, VG, VI, VN, VU, WF, WS, YT, ZA, ZM, US", currency = "USD, CAD" }
+apple_pay = { currency = "USD, CAD" }
+
+[pm_filters.helcim]
+credit = { country = "US, CA", currency = "USD, CAD" }
+debit = { country = "US, CA", currency = "USD, CAD" }
+
+[pm_filters.globalpay]
+credit = { country = "AF,AX,AL,DZ,AS,AD,AO,AI,AQ,AG,AR,AM,AW,AU,AT,AZ,BS,BH,BD,BB,BY,BE,BZ,BJ,BM,BT,BO,BQ,BA,BW,BV,BR,IO,BN,BG,BF,BI,KH,CM,CA,CV,KY,CF,TD,CL,CN,CX,CC,CO,KM,CG,CD,CK,CR,CI,HR,CU,CW,CY,CZ,DK,DJ,DM,DO,EC,EG,SV,GQ,ER,EE,SZ,ET,FK,FO,FJ,FI,FR,GF,PF,TF,GA,GM,GE,DE,GH,GI,GR,GL,GD,GP,GU,GT,GG,GN,GW,GY,HT,HM,VA,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IM,IL,IT,JM,JP,JE,JO,KZ,KE,KI,KP,KR,KW,KG,LA,LV,LB,LS,LR,LY,LI,LT,LU,MO,MK,MG,MW,MY,MV,ML,MT,MH,MQ,MR,MU,YT,MX,FM,MD,MC,MN,ME,MS,MA,MZ,MM,NA,NR,NP,NL,NC,NZ,NI,NE,NG,NU,NF,MP,NO,OM,PK,PW,PS,PA,PG,PY,PE,PH,PN,PL,PT,PR,QA,RE,RO,RU,RW,BL,SH,KN,LC,MF,PM,VC,WS,SM,ST,SA,SN,RS,SC,SL,SG,SX,SK,SI,SB,SO,ZA,GS,SS,ES,LK,SD,SR,SJ,SE,CH,SY,TW,TJ,TZ,TH,TL,TG,TK,TO,TT,TN,TR,TM,TC,TV,UG,UA,AE,GB,US,UM,UY,UZ,VU,VE,VN,VG,VI,WF,EH,YE,ZM,ZW", currency = "AFN,DZD,ARS,AMD,AWG,AUD,AZN,BSD,BHD,THB,PAB,BBD,BYN,BZD,BMD,BOB,BRL,BND,BGN,BIF,CVE,CAD,CLP,COP,KMF,CDF,NIO,CRC,CUP,CZK,GMD,DKK,MKD,DJF,DOP,VND,XCD,EGP,SVC,ETB,EUR,FKP,FJD,HUF,GHS,GIP,HTG,PYG,GNF,GYD,HKD,UAH,ISK,INR,IRR,IQD,JMD,JOD,KES,PGK,HRK,KWD,AOA,MMK,LAK,GEL,LBP,ALL,HNL,SLL,LRD,LYD,SZL,LSL,MGA,MWK,MYR,MUR,MXN,MDL,MAD,MZN,NGN,ERN,NAD,NPR,ANG,ILS,TWD,NZD,BTN,KPW,NOK,TOP,PKR,MOP,UYU,PHP,GBP,BWP,QAR,GTQ,ZAR,OMR,KHR,RON,MVR,IDR,RUB,RWF,SHP,SAR,RSD,SCR,SGD,PEN,SBD,KGS,SOS,TJS,SSP,LKR,SDG,SRD,SEK,CHF,SYP,BDT,WST,TZS,KZT,TTD,MNT,TND,TRY,TMT,AED,UGX,USD,UZS,VUV,KRW,YER,JPY,CNY,ZMW,ZWL,PLN,CLF,STD,CUC" }
+debit = { country = "AF,AX,AL,DZ,AS,AD,AO,AI,AQ,AG,AR,AM,AW,AU,AT,AZ,BS,BH,BD,BB,BY,BE,BZ,BJ,BM,BT,BO,BQ,BA,BW,BV,BR,IO,BN,BG,BF,BI,KH,CM,CA,CV,KY,CF,TD,CL,CN,CX,CC,CO,KM,CG,CD,CK,CR,CI,HR,CU,CW,CY,CZ,DK,DJ,DM,DO,EC,EG,SV,GQ,ER,EE,SZ,ET,FK,FO,FJ,FI,FR,GF,PF,TF,GA,GM,GE,DE,GH,GI,GR,GL,GD,GP,GU,GT,GG,GN,GW,GY,HT,HM,VA,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IM,IL,IT,JM,JP,JE,JO,KZ,KE,KI,KP,KR,KW,KG,LA,LV,LB,LS,LR,LY,LI,LT,LU,MO,MK,MG,MW,MY,MV,ML,MT,MH,MQ,MR,MU,YT,MX,FM,MD,MC,MN,ME,MS,MA,MZ,MM,NA,NR,NP,NL,NC,NZ,NI,NE,NG,NU,NF,MP,NO,OM,PK,PW,PS,PA,PG,PY,PE,PH,PN,PL,PT,PR,QA,RE,RO,RU,RW,BL,SH,KN,LC,MF,PM,VC,WS,SM,ST,SA,SN,RS,SC,SL,SG,SX,SK,SI,SB,SO,ZA,GS,SS,ES,LK,SD,SR,SJ,SE,CH,SY,TW,TJ,TZ,TH,TL,TG,TK,TO,TT,TN,TR,TM,TC,TV,UG,UA,AE,GB,US,UM,UY,UZ,VU,VE,VN,VG,VI,WF,EH,YE,ZM,ZW", currency = "AFN,DZD,ARS,AMD,AWG,AUD,AZN,BSD,BHD,THB,PAB,BBD,BYN,BZD,BMD,BOB,BRL,BND,BGN,BIF,CVE,CAD,CLP,COP,KMF,CDF,NIO,CRC,CUP,CZK,GMD,DKK,MKD,DJF,DOP,VND,XCD,EGP,SVC,ETB,EUR,FKP,FJD,HUF,GHS,GIP,HTG,PYG,GNF,GYD,HKD,UAH,ISK,INR,IRR,IQD,JMD,JOD,KES,PGK,HRK,KWD,AOA,MMK,LAK,GEL,LBP,ALL,HNL,SLL,LRD,LYD,SZL,LSL,MGA,MWK,MYR,MUR,MXN,MDL,MAD,MZN,NGN,ERN,NAD,NPR,ANG,ILS,TWD,NZD,BTN,KPW,NOK,TOP,PKR,MOP,UYU,PHP,GBP,BWP,QAR,GTQ,ZAR,OMR,KHR,RON,MVR,IDR,RUB,RWF,SHP,SAR,RSD,SCR,SGD,PEN,SBD,KGS,SOS,TJS,SSP,LKR,SDG,SRD,SEK,CHF,SYP,BDT,WST,TZS,KZT,TTD,MNT,TND,TRY,TMT,AED,UGX,USD,UZS,VUV,KRW,YER,JPY,CNY,ZMW,ZWL,PLN,CLF,STD,CUC" }
+eps = { country = "AT", currency = "EUR" }
+giropay = { country = "DE", currency = "EUR" }
+ideal = { country = "NL", currency = "EUR" }
+sofort = { country = "AT,BE,DE,ES,IT,NL", currency = "EUR" }
+
+[pm_filters.jpmorgan]
+debit = { country = "CA, GB, US, AT, BE, BG, HR, CY, CZ, DK, EE, FI, FR, DE, GR, HU, IE, IT, LV, LT, LU, MT, NL, PL, PT, RO, SK, SI, ES, SE", currency = "USD, EUR, GBP, AUD, NZD, SGD, CAD, JPY, HKD, KRW, TWD, MXN, BRL, DKK, NOK, ZAR, SEK, CHF, CZK, PLN, TRY, AFN, ALL, DZD, AOA, ARS, AMD, AWG, AZN, BSD, BDT, BBD, BYN, BZD, BMD, BOB, BAM, BWP, BND, BGN, BIF, BTN, XOF, XAF, XPF, KHR, CVE, KYD, CLP, CNY, COP, KMF, CDF, CRC, HRK, DJF, DOP, XCD, EGP, ETB, FKP, FJD, GMD, GEL, GHS, GIP, GTQ, GYD, HTG, HNL, HUF, ISK, INR, IDR, ILS, JMD, KZT, KES, LAK, LBP, LSL, LRD, MOP, MKD, MGA, MWK, MYR, MVR, MRU, MUR, MDL, MNT, MAD, MZN, MMK, NAD, NPR, ANG, PGK, NIO, NGN, PKR, PAB, PYG, PEN, PHP, QAR, RON, RWF, SHP, WST, STN, SAR, RSD, SCR, SLL, SBD, SOS, LKR, SRD, SZL, TJS, TZS, THB, TOP, TTD, UGX, UAH, AED, UYU, UZS, VUV, VND, YER, ZMW" }
+credit = { country = "CA, GB, US, AT, BE, BG, HR, CY, CZ, DK, EE, FI, FR, DE, GR, HU, IE, IT, LV, LT, LU, MT, NL, PL, PT, RO, SK, SI, ES, SE", currency = "USD, EUR, GBP, AUD, NZD, SGD, CAD, JPY, HKD, KRW, TWD, MXN, BRL, DKK, NOK, ZAR, SEK, CHF, CZK, PLN, TRY, AFN, ALL, DZD, AOA, ARS, AMD, AWG, AZN, BSD, BDT, BBD, BYN, BZD, BMD, BOB, BAM, BWP, BND, BGN, BIF, BTN, XOF, XAF, XPF, KHR, CVE, KYD, CLP, CNY, COP, KMF, CDF, CRC, HRK, DJF, DOP, XCD, EGP, ETB, FKP, FJD, GMD, GEL, GHS, GIP, GTQ, GYD, HTG, HNL, HUF, ISK, INR, IDR, ILS, JMD, KZT, KES, LAK, LBP, LSL, LRD, MOP, MKD, MGA, MWK, MYR, MVR, MRU, MUR, MDL, MNT, MAD, MZN, MMK, NAD, NPR, ANG, PGK, NIO, NGN, PKR, PAB, PYG, PEN, PHP, QAR, RON, RWF, SHP, WST, STN, SAR, RSD, SCR, SLL, SBD, SOS, LKR, SRD, SZL, TJS, TZS, THB, TOP, TTD, UGX, UAH, AED, UYU, UZS, VUV, VND, YER, ZMW" }
+
+[pm_filters.bitpay]
+crypto_currency = { country = "US, CA, GB, AT, BE, BG, HR, CY, CZ, DK, EE, FI, FR, DE, GR, HU, IE, IT, LV, LT, LU, MT, NL, PL, PT, RO, SK, SI, ES, SE", currency = "USD, AUD, CAD, GBP, MXN, NZD, CHF, EUR"}
+
+[pm_filters.paybox]
+debit = { country = "FR", currency = "CAD, AUD, EUR, USD" }
+credit = { country = "FR", currency = "CAD, AUD, EUR, USD" }
+
+[pm_filters.payload]
+debit = { currency = "USD,CAD" }
+credit = { currency = "USD,CAD" }
+ach = { currency = "USD,CAD" }
+
+
+[pm_filters.digitalvirgo]
+direct_carrier_billing = {country = "MA, CM, ZA, EG, SN, DZ, TN, ML, GN, GH, LY, GA, CG, MG, BW, SD, NG, ID, SG, AZ, TR, FR, ES, PL, GB, PT, DE, IT, BE, IE, SK, GR, NL, CH, BR, MX, AR, CL, AE, IQ, KW, BH, SA, QA, PS, JO, OM, RU" , currency = "MAD, XOF, XAF, ZAR, EGP, DZD, TND, GNF, GHS, LYD, XAF, CDF, MGA, BWP, SDG, NGN, IDR, SGD, RUB, AZN, TRY, EUR, PLN, GBP, CHF, BRL, MXN, ARS, CLP, AED, IQD, KWD, BHD, SAR, QAR, ILS, JOD, OMR" }
+
+[pm_filters.payu]
+debit = { country = "AE, AF, AL, AM, CW, AO, AR, AU, AW, AZ, BA, BB, BG, BH, BI, BM, BN, BO, BR, BS, BW, BY, BZ, CA, CD, LI, CL, CN, CO, CR, CV, CZ, DJ, DK, DO, DZ, EG, ET, AD, FJ, FK, GG, GE, GH, GI, GM, GN, GT, GY, HK, HN, HR, HT, HU, ID, IL, IQ, IS, JM, JO, JP, KG, KH, KM, KR, KW, KY, KZ, LA, LB, LR, LS, MA, MD, MG, MK, MN, MO, MR, MV, MW, MX, MY, MZ, NA, NG, NI, BV, CK, OM, PA, PE, PG, PL, PY, QA, RO, RS, RW, SA, SB, SC, SE, SG, SH, SO, SR, SV, SZ, TH, TJ, TM, TN, TO, TR, TT, TW, TZ, UG, AS, UY, UZ, VE, VN, VU, WS, CM, AI, BJ, PF, YE, ZA, ZM, ZW", currency = "AED, AFN, ALL, AMD, ANG, AOA, ARS, AUD, AWG, AZN, BAM, BBD, BGN, BHD, BIF, BMD, BND, BOB, BRL, BSD, BWP, BYN, BZD, CAD, CDF, CHF, CLP, CNY, COP, CRC, CVE, CZK, DJF, DKK, DOP, DZD, EGP, ETB, EUR, FJD, FKP, GBP, GEL, GHS, GIP, GMD, GNF, GTQ, GYD, HKD, HNL, HRK, HTG, HUF, IDR, ILS, IQD, ISK, JMD, JOD, JPY, KGS, KHR, KMF, KRW, KWD, KYD, KZT, LAK, LBP, LRD, LSL, MAD, MDL, MGA, MKD, MNT, MOP, MRU, MVR, MWK, MXN, MYR, MZN, NAD, NGN, NIO, NOK, NZD, OMR, PAB, PEN, PGK, PLN, PYG, QAR, RON, RSD, RWF, SAR, SBD, SCR, SEK, SGD, SHP, SOS, SRD, SVC, SZL, THB, TJS, TMT, TND, TOP, TRY, TTD, TWD, TZS, UGX, USD, UYU, UZS, VES, VND, VUV, WST, XAF, XCD, XOF, XPF, YER, ZAR, ZMW, ZWL" }
+credit = { country = "AE, AF, AL, AM, CW, AO, AR, AU, AW, AZ, BA, BB, BG, BH, BI, BM, BN, BO, BR, BS, BW, BY, BZ, CA, CD, LI, CL, CN, CO, CR, CV, CZ, DJ, DK, DO, DZ, EG, ET, AD, FJ, FK, GG, GE, GH, GI, GM, GN, GT, GY, HK, HN, HR, HT, HU, ID, IL, IQ, IS, JM, JO, JP, KG, KH, KM, KR, KW, KY, KZ, LA, LB, LR, LS, MA, MD, MG, MK, MN, MO, MR, MV, MW, MX, MY, MZ, NA, NG, NI, BV, CK, OM, PA, PE, PG, PL, PY, QA, RO, RS, RW, SA, SB, SC, SE, SG, SH, SO, SR, SV, SZ, TH, TJ, TM, TN, TO, TR, TT, TW, TZ, UG, AS, UY, UZ, VE, VN, VU, WS, CM, AI, BJ, PF, YE, ZA, ZM, ZW", currency = "AED, AFN, ALL, AMD, ANG, AOA, ARS, AUD, AWG, AZN, BAM, BBD, BGN, BHD, BIF, BMD, BND, BOB, BRL, BSD, BWP, BYN, BZD, CAD, CDF, CHF, CLP, CNY, COP, CRC, CVE, CZK, DJF, DKK, DOP, DZD, EGP, ETB, EUR, FJD, FKP, GBP, GEL, GHS, GIP, GMD, GNF, GTQ, GYD, HKD, HNL, HRK, HTG, HUF, IDR, ILS, IQD, ISK, JMD, JOD, JPY, KGS, KHR, KMF, KRW, KWD, KYD, KZT, LAK, LBP, LRD, LSL, MAD, MDL, MGA, MKD, MNT, MOP, MRU, MVR, MWK, MXN, MYR, MZN, NAD, NGN, NIO, NOK, NZD, OMR, PAB, PEN, PGK, PLN, PYG, QAR, RON, RSD, RWF, SAR, SBD, SCR, SEK, SGD, SHP, SOS, SRD, SVC, SZL, THB, TJS, TMT, TND, TOP, TRY, TTD, TWD, TZS, UGX, USD, UYU, UZS, VES, VND, VUV, WST, XAF, XCD, XOF, XPF, YER, ZAR, ZMW, ZWL" }
+google_pay = { country = "AL, DZ, AS, AO, AR, AU, AZ, BH, BY, BR, BG, CA, CL, CO, HR, CZ, DK, DO, EG, HK, HU, ID, IN, IL, JP, JO, KZ, KW, LB, MY, MX, OM, PA, PE, PL, QA, RO, SA, SG, SE, TW, TH, TR, AE, UY, VN", currency = "ALL, DZD, USD, AOA, XCD, ARS, AUD, EUR, AZN, BHD, BYN, BRL, BGN, CAD, CLP, COP, CZK, DKK, DOP, EGP, HKD, HUF, INR, IDR, ILS, JPY, JOD, KZT, KWD, LBP, MYR, MXN, NZD, NOK, OMR, PAB, PEN, PLN, QAR, RON, SAR, SGD, ZAR, SEK, CHF, TWD, THB, TRY, UAH, AED, GBP, UYU, VND" }
+
+[pm_filters.klarna]
+klarna = { country = "AU,AT,BE,CA,CZ,DK,FI,FR,DE,GR,IE,IT,NL,NZ,NO,PL,PT,ES,SE,CH,GB,US", currency = "AUD,EUR,EUR,CAD,CZK,DKK,EUR,EUR,EUR,EUR,EUR,EUR,EUR,NZD,NOK,PLN,EUR,EUR,SEK,CHF,GBP,USD" }
+
+[pm_filters.flexiti]
+flexiti = { country = "CA", currency = "CAD" }
+
+[pm_filters.mifinity]
+mifinity = { country = "BR,CN,SG,MY,DE,CH,DK,GB,ES,AD,GI,FI,FR,GR,HR,IT,JP,MX,AR,CO,CL,PE,VE,UY,PY,BO,EC,GT,HN,SV,NI,CR,PA,DO,CU,PR,NL,NO,PL,PT,SE,RU,TR,TW,HK,MO,AX,AL,DZ,AS,AO,AI,AG,AM,AW,AU,AT,AZ,BS,BH,BD,BB,BE,BZ,BJ,BM,BT,BQ,BA,BW,IO,BN,BG,BF,BI,KH,CM,CA,CV,KY,CF,TD,CX,CC,KM,CG,CK,CI,CW,CY,CZ,DJ,DM,EG,GQ,ER,EE,ET,FK,FO,FJ,GF,PF,TF,GA,GM,GE,GH,GL,GD,GP,GU,GG,GN,GW,GY,HT,HM,VA,IS,IN,ID,IE,IM,IL,JE,JO,KZ,KE,KI,KW,KG,LA,LV,LB,LS,LI,LT,LU,MK,MG,MW,MV,ML,MT,MH,MQ,MR,MU,YT,FM,MD,MC,MN,ME,MS,MA,MZ,NA,NR,NP,NC,NZ,NE,NG,NU,NF,MP,OM,PK,PW,PS,PG,PH,PN,QA,RE,RO,RW,BL,SH,KN,LC,MF,PM,VC,WS,SM,ST,SA,SN,RS,SC,SL,SX,SK,SI,SB,SO,ZA,GS,KR,LK,SR,SJ,SZ,TH,TL,TG,TK,TO,TT,TN,TM,TC,TV,UG,UA,AE,UZ,VU,VN,VG,VI,WF,EH,ZM", currency = "AUD,CAD,CHF,CNY,CZK,DKK,EUR,GBP,INR,JPY,NOK,NZD,PLN,RUB,SEK,ZAR,USD,EGP,UYU,UZS" }
+
+[pm_filters.zen]
+credit = { not_available_flows = { capture_method = "manual" } }
+debit = { not_available_flows = { capture_method = "manual" } }
+boleto = { country = "BR", currency = "BRL" }
+efecty = { country = "CO", currency = "COP" }
+multibanco = { country = "PT", currency = "EUR" }
+pago_efectivo = { country = "PE", currency = "PEN" }
+pse = { country = "CO", currency = "COP" }
+pix = { country = "BR", currency = "BRL" }
+red_compra = { country = "CL", currency = "CLP" }
+red_pagos = { country = "UY", currency = "UYU" }
+
+[pm_filters.zsl]
+local_bank_transfer = { country = "CN", currency = "CNY" }
+
+[pm_filters.aci]
+credit = { country = "AD,AE,AT,BE,BG,CH,CN,CO,CR,CY,CZ,DE,DK,DO,EE,EG,ES,ET,FI,FR,GB,GH,GI,GR,GT,HN,HK,HR,HU,ID,IE,IS,IT,JP,KH,LA,LI,LT,LU,LY,MK,MM,MX,MY,MZ,NG,NZ,OM,PA,PE,PK,PL,PT,QA,RO,SA,SN,SE,SI,SK,SV,TH,UA,US,UY,VN,ZM", currency = "AED,ALL,ARS,BGN,CHF,CLP,CNY,COP,CRC,CZK,DKK,DOP,EGP,EUR,GBP,GHS,HKD,HNL,HRK,HUF,IDR,ILS,ISK,JPY,KHR,KPW,LAK,LKR,MAD,MKD,MMK,MXN,MYR,MZN,NGN,NOK,NZD,OMR,PAB,PEN,PHP,PKR,PLN,QAR,RON,RSD,SAR,SEK,SGD,THB,TRY,TWD,UAH,USD,UYU,VND,ZAR,ZMW" }
+debit = { country = "AD,AE,AT,BE,BG,CH,CN,CO,CR,CY,CZ,DE,DK,DO,EE,EG,ES,ET,FI,FR,GB,GH,GI,GR,GT,HN,HK,HR,HU,ID,IE,IS,IT,JP,KH,LA,LI,LT,LU,LY,MK,MM,MX,MY,MZ,NG,NZ,OM,PA,PE,PK,PL,PT,QA,RO,SA,SN,SE,SI,SK,SV,TH,UA,US,UY,VN,ZM", currency = "AED,ALL,ARS,BGN,CHF,CLP,CNY,COP,CRC,CZK,DKK,DOP,EGP,EUR,GBP,GHS,HKD,HNL,HRK,HUF,IDR,ILS,ISK,JPY,KHR,KPW,LAK,LKR,MAD,MKD,MMK,MXN,MYR,MZN,NGN,NOK,NZD,OMR,PAB,PEN,PHP,PKR,PLN,QAR,RON,RSD,SAR,SEK,SGD,THB,TRY,TWD,UAH,USD,UYU,VND,ZAR,ZMW" }
+mb_way = { country = "EE,ES,PT", currency = "EUR" }
+ali_pay = { country = "CN", currency = "CNY" }
+eps = { country = "AT", currency = "EUR" }
+ideal = { country = "NL", currency = "EUR" }
+giropay = { country = "DE", currency = "EUR" }
+sofort = { country = "AT,BE,CH,DE,ES,GB,IT,NL,PL", currency = "CHF,EUR,GBP,HUF,PLN"}
+interac = { country = "CA", currency = "CAD,USD"}
+przelewy24 = { country = "PL", currency = "CZK,EUR,GBP,PLN" }
+trustly = { country = "ES,GB,SE,NO,AT,NL,DE,DK,FI,EE,LT,LV", currency = "CZK,DKK,EUR,GBP,NOK,SEK" }
+klarna = { country = "AU,AT,BE,CA,CZ,DK,FI,FR,DE,GR,IE,IT,NL,NZ,NO,PL,PT,ES,SE,CH,GB,US", currency = "CHF,DKK,EUR,GBP,NOK,PLN,SEK,USD,AUD,NZD,CAD" }
+
+[pm_filters.gigadat]
+interac = { currency = "CAD"}
+
+[pm_filters.loonio]
+interac = { currency = "CAD"}
+
+[pm_filters.dlocal]
+oxxo = { currency = "MXN" }
+
+[pm_filters.mollie]
+eps = { country = "AT", currency = "EUR" }
+ideal = { country = "NL", currency = "EUR" }
+przelewy24 = { country = "PL", currency = "PLN,EUR" }
+klarna = { country = "DE,AT,NL,BE,FR,GB,IT,ES,PT,SE,DK,FI,NO,CH,IR,CZ,PL,GR,SK", currency = "EUR,GBP,DKK,SEK,NOK,CHF,PLN,CZK" }
+
+[pm_filters.redsys]
+credit = { currency = "AUD,BGN,CAD,CHF,COP,CZK,DKK,EUR,GBP,HRK,HUF,ILS,INR,JPY,MYR,NOK,NZD,PEN,PLN,RUB,SAR,SEK,SGD,THB,USD,ZAR", country="ES" }
+debit = { currency = "AUD,BGN,CAD,CHF,COP,CZK,DKK,EUR,GBP,HRK,HUF,ILS,INR,JPY,MYR,NOK,NZD,PEN,PLN,RUB,SAR,SEK,SGD,THB,USD,ZAR", country="ES" }
+
+[pm_filters.stax]
+credit = { country = "US", currency = "USD" }
+debit = { country = "US", currency = "USD" }
+ach = { country = "US", currency = "USD" }
+
+[pm_filters.prophetpay]
+card_redirect = { country = "US", currency = "USD" }
+
+[pm_filters.multisafepay]
+credit = { country = "AF,AX,AL,DZ,AS,AD,AO,AI,AQ,AG,AR,AM,AW,AU,AT,AZ,BS,BH,BD,BB,BY,BE,BZ,BJ,BM,BT,BO,BQ,BA,BW,BV,BR,IO,BN,BG,BF,BI,CV,KH,CM,CA,KY,CF,TD,CL,CN,CX,CC,CO,KM,CG,CD,CK,CR,CI,HR,CU,CW,CY,CZ,DK,DJ,DM,DO,EC,EG,SV,GQ,ER,EE,ET,FK,FO,FJ,FI,FR,GF,PF,TF,GA,GM,GE,DE,GH,GI,GR,GL,GD,GP,GU,GT,GG,GN,GW,GY,HT,HM,VA,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IM,IL,IT,JM,JP,JE,JO,KZ,KE,KI,KP,KR,KW,KG,LA,LV,LB,LS,LR,LY,LI,LT,LU,MO,MK,MG,MW,MY,MV,ML,MT,MH,MQ,MR,MU,YT,MX,FM,MD,MC,MN,ME,MS,MA,MZ,MM,NA,NR,NP,NL,NC,NZ,NI,NE,NG,NU,NF,MP,NO,OM,PK,PW,PS,PA,PG,PY,PE,PH,PN,PL,PT,PR,QA,RE,RO,RU,RW,BL,SH,KN,LC,MF,PM,VC,WS,SM,ST,SA,SN,RS,SC,SL,SG,SX,SK,SI,SB,SO,ZA,GS,SS,ES,LK,SD,SR,SJ,SZ,SE,CH,SY,TW,TJ,TZ,TH,TL,TG,TK,TO,TT,TN,TR,TM,TC,TV,UG,UA,AE,GB,US,UM,UY,UZ,VU,VE,VN,VG,VI,WF,EH,YE,ZM,ZW", currency = "AED,AUD,BRL,CAD,CHF,CLP,CNY,COP,CZK,DKK,EUR,GBP,HKD,HRK,HUF,ILS,INR,ISK,JPY,KRW,MXN,MYR,NOK,NZD,PEN,PLN,RON,RUB,SEK,SGD,TRY,TWD,USD,ZAR", not_available_flows = { capture_method = "manual" } }
+debit = { country = "AF,AX,AL,DZ,AS,AD,AO,AI,AQ,AG,AR,AM,AW,AU,AT,AZ,BS,BH,BD,BB,BY,BE,BZ,BJ,BM,BT,BO,BQ,BA,BW,BV,BR,IO,BN,BG,BF,BI,CV,KH,CM,CA,KY,CF,TD,CL,CN,CX,CC,CO,KM,CG,CD,CK,CR,CI,HR,CU,CW,CY,CZ,DK,DJ,DM,DO,EC,EG,SV,GQ,ER,EE,ET,FK,FO,FJ,FI,FR,GF,PF,TF,GA,GM,GE,DE,GH,GI,GR,GL,GD,GP,GU,GT,GG,GN,GW,GY,HT,HM,VA,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IM,IL,IT,JM,JP,JE,JO,KZ,KE,KI,KP,KR,KW,KG,LA,LV,LB,LS,LR,LY,LI,LT,LU,MO,MK,MG,MW,MY,MV,ML,MT,MH,MQ,MR,MU,YT,MX,FM,MD,MC,MN,ME,MS,MA,MZ,MM,NA,NR,NP,NL,NC,NZ,NI,NE,NG,NU,NF,MP,NO,OM,PK,PW,PS,PA,PG,PY,PE,PH,PN,PL,PT,PR,QA,RE,RO,RU,RW,BL,SH,KN,LC,MF,PM,VC,WS,SM,ST,SA,SN,RS,SC,SL,SG,SX,SK,SI,SB,SO,ZA,GS,SS,ES,LK,SD,SR,SJ,SZ,SE,CH,SY,TW,TJ,TZ,TH,TL,TG,TK,TO,TT,TN,TR,TM,TC,TV,UG,UA,AE,GB,US,UM,UY,UZ,VU,VE,VN,VG,VI,WF,EH,YE,ZM,ZW", currency = "AED,AUD,BRL,CAD,CHF,CLP,CNY,COP,CZK,DKK,EUR,GBP,HKD,HRK,HUF,ILS,INR,ISK,JPY,KRW,MXN,MYR,NOK,NZD,PEN,PLN,RON,RUB,SEK,SGD,TRY,TWD,USD,ZAR", not_available_flows = { capture_method = "manual" } }
+google_pay = { country = "AL, DZ, AS, AO, AG, AR, AU, AT, AZ, BH, BY, BE, BR, BG, CA, CL, CO, HR, CZ, DK, DO, EG, EE, FI, FR, DE, GR, HK, HU, IN, ID, IE, IL, IT, JP, JO, KZ, KE, KW, LV, LB, LT, LU, MY, MX, NL, NZ, NO, OM, PK, PA, PE, PH, PL, PT, QA, RO, RU, SA, SG, SK, ZA, ES, LK, SE, CH, TW, TH, TR, UA, AE, GB, US, UY, VN", currency = "AED, AUD, BRL, CAD, CHF, CLP, COP, CZK, DKK, EUR, GBP, HKD, HRK, HUF, ILS, INR, JPY, MXN, MYR, NOK, NZD, PEN, PHP, PLN, RON, RUB, SEK, SGD, THB, TRY, TWD, UAH, USD, ZAR" }
+paypal = { country = "AF,AX,AL,DZ,AS,AD,AO,AI,AQ,AG,AR,AM,AW,AU,AT,AZ,BS,BH,BD,BB,BY,BE,BZ,BJ,BM,BT,BO,BQ,BA,BW,BV,BR,IO,BN,BG,BF,BI,CV,KH,CM,CA,KY,CF,TD,CL,CN,CX,CC,CO,KM,CG,CD,CK,CR,CI,HR,CU,CW,CY,CZ,DK,DJ,DM,DO,EC,EG,SV,GQ,ER,EE,ET,FK,FO,FJ,FI,FR,GF,PF,TF,GA,GM,GE,DE,GH,GI,GR,GL,GD,GP,GU,GT,GG,GN,GW,GY,HT,HM,VA,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IM,IL,IT,JM,JP,JE,JO,KZ,KE,KI,KP,KR,KW,KG,LA,LV,LB,LS,LR,LY,LI,LT,LU,MO,MK,MG,MW,MY,MV,ML,MT,MH,MQ,MR,MU,YT,MX,FM,MD,MC,MN,ME,MS,MA,MZ,MM,NA,NR,NP,NL,NC,NZ,NI,NE,NG,NU,NF,MP,NO,OM,PK,PW,PS,PA,PG,PY,PE,PH,PN,PL,PT,PR,QA,RE,RO,RU,RW,BL,SH,KN,LC,MF,PM,VC,WS,SM,ST,SA,SN,RS,SC,SL,SG,SX,SK,SI,SB,SO,ZA,GS,SS,ES,LK,SD,SR,SJ,SZ,SE,CH,SY,TW,TJ,TZ,TH,TL,TG,TK,TO,TT,TN,TR,TM,TC,TV,UG,UA,AE,GB,US,UM,UY,UZ,VU,VE,VN,VG,VI,WF,EH,YE,ZM,ZW", currency = "AUD,BRL,CAD,CHF,CZK,DKK,EUR,GBP,HKD,HRK,HUF,JPY,MXN,MYR,NOK,NZD,PHP,PLN,RUB,SEK,SGD,THB,TRY,TWD,USD" }
+giropay = { country = "DE", currency = "EUR" }
+ideal = { country = "NL", currency = "EUR" }
+klarna = { country = "AT,BE,DK,FI,FR,DE,IT,NL,NO,PT,ES,SE,GB", currency = "DKK,EUR,GBP,NOK,SEK" }
+trustly = { country = "AT,CZ,DK,EE,FI,DE,LV,LT,NL,NO,PL,PT,ES,SE,GB" , currency = "EUR,GBP,SEK"}
+ali_pay = { currency = "EUR,USD" }
+we_chat_pay = { currency = "EUR"}
+eps = { country = "AT" , currency = "EUR" }
+mb_way = { country = "PT" , currency = "EUR" }
+sofort = { country = "AT,BE,FR,DE,IT,PL,ES,CH,GB" , currency = "EUR"}
+
+[pm_filters.cashtocode]
+classic = { country = "AF,AX,AL,DZ,AS,AD,AO,AI,AQ,AG,AR,AM,AW,AU,AT,AZ,BS,BH,BD,BB,BY,BE,BZ,BJ,BM,BT,BO,BQ,BA,BW,BV,BR,IO,BN,BG,BF,BI,KH,CM,CA,CV,KY,CF,TD,CL,CN,CX,CC,CO,KM,CG,CD,CK,CR,CI,HR,CU,CW,CY,CZ,DK,DJ,DM,DO,EC,EG,SV,GQ,ER,EE,ET,FK,FO,FJ,FI,FR,GF,PF,TF,GA,GM,GE,DE,GH,GI,GR,GL,GD,GP,GU,GT,GG,GN,GW,GY,HT,HM,VA,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IM,IL,IT,JM,JP,JE,JO,KZ,KE,KI,KP,KR,KW,KG,LA,LV,LB,LS,LR,LY,LI,LT,LU,MO,MK,MG,MW,MY,MV,ML,MT,MH,MQ,MR,MU,YT,MX,FM,MD,MC,MN,ME,MS,MA,MZ,MM,NA,NR,NP,NL,NC,NZ,NI,NE,NG,NU,NF,MP,NO,OM,PK,PW,PS,PA,PG,PY,PE,PH,PN,PL,PT,PR,QA,RE,RO,RU,RW,BL,SH,KN,LC,MF,PM,VC,WS,SM,ST,SA,SN,RS,SC,SL,SG,SX,SK,SI,SB,SO,ZA,GS,SS,ES,LK,SD,SR,SJ,SZ,SE,CH,SY,TW,TJ,TZ,TH,TL,TG,TK,TO,TT,TN,TR,TM,TC,TV,UG,UA,AE,GB,UM,UY,UZ,VU,VE,VN,VG,VI,WF,EH,YE,ZM,ZW,US", currency = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BYN,BZD,CAD,CDF,CHF,CLF,CLP,CNY,COP,CRC,CUC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLE,SLL,SOS,SRD,SSP,STD,STN,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL" }
+evoucher = { country = "AF,AX,AL,DZ,AS,AD,AO,AI,AQ,AG,AR,AM,AW,AU,AT,AZ,BS,BH,BD,BB,BY,BE,BZ,BJ,BM,BT,BO,BQ,BA,BW,BV,BR,IO,BN,BG,BF,BI,KH,CM,CA,CV,KY,CF,TD,CL,CN,CX,CC,CO,KM,CG,CD,CK,CR,CI,HR,CU,CW,CY,CZ,DK,DJ,DM,DO,EC,EG,SV,GQ,ER,EE,ET,FK,FO,FJ,FI,FR,GF,PF,TF,GA,GM,GE,DE,GH,GI,GR,GL,GD,GP,GU,GT,GG,GN,GW,GY,HT,HM,VA,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IM,IL,IT,JM,JP,JE,JO,KZ,KE,KI,KP,KR,KW,KG,LA,LV,LB,LS,LR,LY,LI,LT,LU,MO,MK,MG,MW,MY,MV,ML,MT,MH,MQ,MR,MU,YT,MX,FM,MD,MC,MN,ME,MS,MA,MZ,MM,NA,NR,NP,NL,NC,NZ,NI,NE,NG,NU,NF,MP,NO,OM,PK,PW,PS,PA,PG,PY,PE,PH,PN,PL,PT,PR,QA,RE,RO,RU,RW,BL,SH,KN,LC,MF,PM,VC,WS,SM,ST,SA,SN,RS,SC,SL,SG,SX,SK,SI,SB,SO,ZA,GS,SS,ES,LK,SD,SR,SJ,SZ,SE,CH,SY,TW,TJ,TZ,TH,TL,TG,TK,TO,TT,TN,TR,TM,TC,TV,UG,UA,AE,GB,UM,UY,UZ,VU,VE,VN,VG,VI,WF,EH,YE,ZM,ZW,US", currency = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BYN,BZD,CAD,CDF,CHF,CLF,CLP,CNY,COP,CRC,CUC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLE,SLL,SOS,SRD,SSP,STD,STN,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL" }
+
+[pm_filters.wellsfargo]
+credit = { country = "AF,AX,AL,DZ,AS,AD,AO,AI,AQ,AG,AR,AM,AW,AU,AT,AZ,BS,BH,BD,BB,BY,BE,BZ,BJ,BM,BT,BO,BQ,BA,BW,BV,BR,IO,BN,BG,BF,BI,KH,CM,CA,CV,KY,CF,TD,CL,CN,CX,CC,CO,KM,CG,CD,CK,CR,CI,HR,CU,CW,CY,CZ,DK,DJ,DM,DO,EC,EG,SV,GQ,ER,EE,ET,FK,FO,FJ,FI,FR,GF,PF,TF,GA,GM,GE,DE,GH,GI,GR,GL,GD,GP,GU,GT,GG,GN,GW,GY,HT,HM,VA,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IM,IL,IT,JM,JP,JE,JO,KZ,KE,KI,KP,KR,KW,KG,LA,LV,LB,LS,LR,LY,LI,LT,LU,MO,MK,MG,MW,MY,MV,ML,MT,MH,MQ,MR,MU,YT,MX,FM,MD,MC,MN,ME,MS,MA,MZ,MM,NA,NR,NP,NL,NC,NZ,NI,NE,NG,NU,NF,MP,NO,OM,PK,PW,PS,PA,PG,PY,PE,PH,PN,PL,PT,PR,QA,RE,RO,RU,RW,BL,SH,KN,LC,MF,PM,VC,WS,SM,ST,SA,SN,RS,SC,SL,SG,SX,SK,SI,SB,SO,ZA,GS,SS,ES,LK,SD,SR,SJ,SZ,SE,CH,SY,TW,TJ,TZ,TH,TL,TG,TK,TO,TT,TN,TR,TM,TC,TV,UG,UA,US,AE,GB,UM,UY,UZ,VU,VE,VN,VG,VI,WF,EH,YE,ZM,ZW", currency = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BYN,BZD,CAD,CDF,CHF,CLP,CNY,COP,CRC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLE,SLL,SOS,SRD,SSP,STN,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL" }
+debit = { country = "AF,AX,AL,DZ,AS,AD,AO,AI,AQ,AG,AR,AM,AW,AU,AT,AZ,BS,BH,BD,BB,BY,BE,BZ,BJ,BM,BT,BO,BQ,BA,BW,BV,BR,IO,BN,BG,BF,BI,KH,CM,CA,CV,KY,CF,TD,CL,CN,CX,CC,CO,KM,CG,CD,CK,CR,CI,HR,CU,CW,CY,CZ,DK,DJ,DM,DO,EC,EG,SV,GQ,ER,EE,ET,FK,FO,FJ,FI,FR,GF,PF,TF,GA,GM,GE,DE,GH,GI,GR,GL,GD,GP,GU,GT,GG,GN,GW,GY,HT,HM,VA,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IM,IL,IT,JM,JP,JE,JO,KZ,KE,KI,KP,KR,KW,KG,LA,LV,LB,LS,LR,LY,LI,LT,LU,MO,MK,MG,MW,MY,MV,ML,MT,MH,MQ,MR,MU,YT,MX,FM,MD,MC,MN,ME,MS,MA,MZ,MM,NA,NR,NP,NL,NC,NZ,NI,NE,NG,NU,NF,MP,NO,OM,PK,PW,PS,PA,PG,PY,PE,PH,PN,PL,PT,PR,QA,RE,RO,RU,RW,BL,SH,KN,LC,MF,PM,VC,WS,SM,ST,SA,SN,RS,SC,SL,SG,SX,SK,SI,SB,SO,ZA,GS,SS,ES,LK,SD,SR,SJ,SZ,SE,CH,SY,TW,TJ,TZ,TH,TL,TG,TK,TO,TT,TN,TR,TM,TC,TV,UG,UA,US,AE,GB,UM,UY,UZ,VU,VE,VN,VG,VI,WF,EH,YE,ZM,ZW", currency = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BYN,BZD,CAD,CDF,CHF,CLP,CNY,COP,CRC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLE,SLL,SOS,SRD,SSP,STN,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL" }
+google_pay = { country = "US", currency = "USD" }
+apple_pay = { country = "US", currency = "USD" }
+ach = { country = "US", currency = "USD" }
+
+[pm_filters.trustpay]
+credit = { not_available_flows = { capture_method = "manual" } }
+debit = { not_available_flows = { capture_method = "manual" } }
+instant_bank_transfer = { country = "CZ,SK,GB,AT,DE,IT", currency = "CZK, EUR, GBP" }
+instant_bank_transfer_poland = { country = "PL", currency = "PLN" }
+instant_bank_transfer_finland = { country = "FI", currency = "EUR" }
+sepa = { country = "ES,SK,AT,NL,DE,BE,FR,FI,PT,IE,EE,LT,LV,IT,GB", currency = "EUR" }
+
+[pm_filters.tesouro]
+credit = { country = "AF,AL,DZ,AD,AO,AI,AG,AR,AM,AW,AU,AT,AZ,BS,BH,BD,BB,BY,BE,BZ,BJ,BM,BT,BO,BA,BW,BN,BG,BF,BI,KH,CM,CA,CV,KY,CF,TD,CL,CN,CO,KM,CD,CG,CK,CR,HR,CU,CW,CY,CZ,DK,DJ,DM,DO,EC,SV,GQ,ER,EE,ET,FK,FO,FJ,FI,FR,GF,PF,TF,GA,GM,GE,DE,GH,GI,GR,GL,GD,GP,GU,GT,GG,GN,GW,GY,HT,HM,VA,HN,HK,HU,IS,ID,IR,IQ,IE,IM,IL,IT,JM,JP,JE,JO,KZ,KE,KI,KR,KW,KG,LA,LV,LB,LS,LR,LY,LI,LT,LU,MO,MG,MW,MY,MV,ML,MT,MH,MR,MU,MX,FM,MD,MC,MN,ME,MS,MA,MZ,MM,NA,NR,NP,NL,NC,NZ,NI,NE,NG,NU,NO,OM,PK,PW,PS,PA,PG,PY,PE,PH,PL,PT,PR,QA,CG,RO,RW,KN,LC,VC,WS,SM,ST,SA,SN,RS,SC,SL,SG,SX,SK,SI,SO,ZA,GS,ES,LK,SR,SJ,SZ,SE,CH,TW,TJ,TZ,TH,TL,TG,TO,TT,TN,TR,TM,TC,TV,UG,UA,AE,GB,US,UY,UZ,VU,VE,VN,VG,WF,YE,ZM,ZW", currency = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BYN,BZD,CAD,CDF,CHF,CLF,CLP,CNY,COP,CRC,CUC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLE,SLL,SOS,SRD,SSP,STD,STN,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL" }
+debit = { country = "AF,AL,DZ,AD,AO,AI,AG,AR,AM,AW,AU,AT,AZ,BS,BH,BD,BB,BY,BE,BZ,BJ,BM,BT,BO,BA,BW,BN,BG,BF,BI,KH,CM,CA,CV,KY,CF,TD,CL,CN,CO,KM,CD,CG,CK,CR,HR,CU,CW,CY,CZ,DK,DJ,DM,DO,EC,SV,GQ,ER,EE,ET,FK,FO,FJ,FI,FR,GF,PF,TF,GA,GM,GE,DE,GH,GI,GR,GL,GD,GP,GU,GT,GG,GN,GW,GY,HT,HM,VA,HN,HK,HU,IS,ID,IR,IQ,IE,IM,IL,IT,JM,JP,JE,JO,KZ,KE,KI,KR,KW,KG,LA,LV,LB,LS,LR,LY,LI,LT,LU,MO,MG,MW,MY,MV,ML,MT,MH,MR,MU,MX,FM,MD,MC,MN,ME,MS,MA,MZ,MM,NA,NR,NP,NL,NC,NZ,NI,NE,NG,NU,NO,OM,PK,PW,PS,PA,PG,PY,PE,PH,PL,PT,PR,QA,CG,RO,RW,KN,LC,VC,WS,SM,ST,SA,SN,RS,SC,SL,SG,SX,SK,SI,SO,ZA,GS,ES,LK,SR,SJ,SZ,SE,CH,TW,TJ,TZ,TH,TL,TG,TO,TT,TN,TR,TM,TC,TV,UG,UA,AE,GB,US,UY,UZ,VU,VE,VN,VG,WF,YE,ZM,ZW", currency = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BYN,BZD,CAD,CDF,CHF,CLF,CLP,CNY,COP,CRC,CUC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLE,SLL,SOS,SRD,SSP,STD,STN,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL" }
+apple_pay = { currency = "USD" }
+google_pay = { currency = "USD" }
+
+[pm_filters.authorizedotnet]
+credit = {currency = "CAD,USD"}
+debit = {currency = "CAD,USD"}
+google_pay = {currency = "CHF,DKK,EUR,GBP,NOK,PLN,SEK,USD,AUD,NZD,CAD"}
+apple_pay = {currency = "EUR,GBP,ISK,USD,AUD,CAD,BRL,CLP,COP,CRC,CZK,DKK,EGP,GEL,GHS,GTQ,HNL,HKD,HUF,ILS,INR,JPY,KZT,KRW,KWD,MAD,MXN,MYR,NOK,NZD,PEN,PLN,PYG,QAR,RON,SAR,SEK,SGD,THB,TWD,UAH,AED,VND,ZAR"}
+paypal = {currency = "AUD,BRL,CAD,CHF,CNY,CZK,DKK,EUR,GBP,HKD,HUF,ILS,JPY,MXN,MYR,NOK,NZD,PHP,PLN,SEK,SGD,THB,TWD,USD"}
+
+[pm_filters.dwolla]
+ach = { country = "US", currency = "USD" }
+
+[pm_filters.worldpay]
+debit = { country = "AF,DZ,AW,AU,AZ,BS,BH,BD,BB,BZ,BM,BT,BO,BA,BW,BR,BN,BG,BI,KH,CA,CV,KY,CL,CO,KM,CD,CR,CZ,DK,DJ,ST,DO,EC,EG,SV,ER,ET,FK,FJ,GM,GE,GH,GI,GT,GN,GY,HT,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IL,IT,JM,JP,JO,KZ,KE,KW,LA,LB,LS,LR,LY,LT,MO,MK,MG,MW,MY,MV,MR,MU,MX,MD,MN,MA,MZ,MM,NA,NZ,NI,NG,KP,NO,AR,PK,PG,PY,PE,UY,PH,PL,GB,QA,OM,RO,RU,RW,WS,SG,ST,ZA,KR,LK,SH,SD,SR,SZ,SE,CH,SY,TW,TJ,TZ,TH,TT,TN,TR,UG,UA,US,UZ,VU,VE,VN,ZM,ZW", currency = "AFN,DZD,ANG,AWG,AUD,AZN,BSD,BHD,BDT,BBD,BZD,BMD,BTN,BOB,BAM,BWP,BRL,BND,BGN,BIF,KHR,CAD,CVE,KYD,XOF,XAF,XPF,CLP,COP,KMF,CDF,CRC,EUR,CZK,DKK,DJF,DOP,XCD,EGP,SVC,ERN,ETB,EUR,FKP,FJD,GMD,GEL,GHS,GIP,GTQ,GNF,GYD,HTG,HNL,HKD,HUF,ISK,INR,IDR,IRR,IQD,ILS,JMD,JPY,JOD,KZT,KES,KWD,LAK,LBP,LSL,LRD,LYD,MOP,MKD,MGA,MWK,MYR,MVR,MRU,MUR,MXN,MDL,MNT,MAD,MZN,MMK,NAD,NPR,NZD,NIO,NGN,KPW,NOK,ARS,PKR,PAB,PGK,PYG,PEN,UYU,PHP,PLN,GBP,QAR,OMR,RON,RUB,RWF,WST,SAR,RSD,SCR,SLL,SGD,STN,SBD,SOS,ZAR,KRW,LKR,SHP,SDG,SRD,SZL,SEK,CHF,SYP,TWD,TJS,TZS,THB,TOP,TTD,TND,TRY,TMT,AED,UGX,UAH,USD,UZS,VUV,VND,YER,CNY,ZMW,ZWL" }
+credit = { country = "AF,DZ,AW,AU,AZ,BS,BH,BD,BB,BZ,BM,BT,BO,BA,BW,BR,BN,BG,BI,KH,CA,CV,KY,CL,CO,KM,CD,CR,CZ,DK,DJ,ST,DO,EC,EG,SV,ER,ET,FK,FJ,GM,GE,GH,GI,GT,GN,GY,HT,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IL,IT,JM,JP,JO,KZ,KE,KW,LA,LB,LS,LR,LY,LT,MO,MK,MG,MW,MY,MV,MR,MU,MX,MD,MN,MA,MZ,MM,NA,NZ,NI,NG,KP,NO,AR,PK,PG,PY,PE,UY,PH,PL,GB,QA,OM,RO,RU,RW,WS,SG,ST,ZA,KR,LK,SH,SD,SR,SZ,SE,CH,SY,TW,TJ,TZ,TH,TT,TN,TR,UG,UA,US,UZ,VU,VE,VN,ZM,ZW", currency = "AFN,DZD,ANG,AWG,AUD,AZN,BSD,BHD,BDT,BBD,BZD,BMD,BTN,BOB,BAM,BWP,BRL,BND,BGN,BIF,KHR,CAD,CVE,KYD,XOF,XAF,XPF,CLP,COP,KMF,CDF,CRC,EUR,CZK,DKK,DJF,DOP,XCD,EGP,SVC,ERN,ETB,EUR,FKP,FJD,GMD,GEL,GHS,GIP,GTQ,GNF,GYD,HTG,HNL,HKD,HUF,ISK,INR,IDR,IRR,IQD,ILS,JMD,JPY,JOD,KZT,KES,KWD,LAK,LBP,LSL,LRD,LYD,MOP,MKD,MGA,MWK,MYR,MVR,MRU,MUR,MXN,MDL,MNT,MAD,MZN,MMK,NAD,NPR,NZD,NIO,NGN,KPW,NOK,ARS,PKR,PAB,PGK,PYG,PEN,UYU,PHP,PLN,GBP,QAR,OMR,RON,RUB,RWF,WST,SAR,RSD,SCR,SLL,SGD,STN,SBD,SOS,ZAR,KRW,LKR,SHP,SDG,SRD,SZL,SEK,CHF,SYP,TWD,TJS,TZS,THB,TOP,TTD,TND,TRY,TMT,AED,UGX,UAH,USD,UZS,VUV,VND,YER,CNY,ZMW,ZWL" }
+google_pay = { country = "AL, DZ, AS, AO, AG, AR, AU, AT, AZ, BH, BY, BE, BR, BG, CA, CL, CO, HR, CZ, DK, DO, EG, EE, FI, FR, DE, GR, HK, HU, IN, ID, IE, IL, IT, JP, JO, KZ, KE, KW, LV, LB, LT, LU, MY, MX, NL, NZ, NO, OM, PK, PA, PE, PH, PL, PT, QA, RO, RU, SA, SG, SK, ZA, ES, LK, SE, CH, TW, TH, TR, UA, AE, GB, US, UY, VN", currency = "DZD, AOA, USD, XCD, ARS, AUD, AZN, EUR, BHD, BYN, BRL, BGN, CAD, CLP, COP, CZK, DKK, DOP, EGP, HKD, HUF, INR, IDR, ILS, JPY, JOD, KZT, KES, KWD, LBP, MYR, MXN, NZD, NOK, OMR, PKR, PAB, PEN, PHP, PLN, QAR, RON, RUB, SAR, SGD, ZAR, LKR, SEK, CHF, TWD, THB, TRY, UAH, AED, GBP, UYU, VND" }
+apple_pay = { country = "EG, MA, ZA, AU, CN, HK, JP, MO, MY, MN, NZ, SG, TW, VN, AM, AT, AZ, BY, BE, BG, HR, CY, CZ, DK, EE, FO, FI, FR, GE, DE, GR, GL, GG, HU, IE, IS, IM, IT, KZ, JE, LV, LI, LT, LU, MT, MD, MC, ME, NL, NO, PL, PT, RO, SM, RS, SK, SI, ES, SE, CH, UA, GB, VA, AR, BR, CL, CO, CR, DO, EC, SV, GT, HN, MX, PA, PY, PE, BS, BH, IL, JO, KW, OM, PS, QA, SA, AE, CA, US, PR", currency = "EGP, MAD, ZAR, AUD, CNY, HKD, JPY, MOP, MYR, MNT, NZD, SGD, KRW, TWD, VND, EUR, AZN, BYN, BGN, CZK, DKK, GEL, GBP, HUF, ISK, KZT, CHF, MDL, NOK, PLN, RON, RSD, SEK, UAH, ARS, BRL, CLP, COP, CRC, DOP, USD, GTQ, HNL, MXN, PAB, PYG, PEN, BSD, UYU, BHD, ILS, JOD, KWD, OMR, QAR, SAR, AED, CAD" }
+
+[pm_filters.worldpayxml]
+debit = { country = "AF,DZ,AW,AU,AZ,BS,BH,BD,BB,BZ,BM,BT,BO,BA,BW,BR,BN,BG,BI,KH,CA,CV,KY,CL,CO,KM,CD,CR,CZ,DK,DJ,ST,DO,EC,EG,SV,ER,ET,FK,FJ,GM,GE,GH,GI,GT,GN,GY,HT,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IL,IT,JM,JP,JO,KZ,KE,KW,LA,LB,LS,LR,LY,LT,MO,MK,MG,MW,MY,MV,MR,MU,MX,MD,MN,MA,MZ,MM,NA,NZ,NI,NG,KP,NO,AR,PK,PG,PY,PE,UY,PH,PL,GB,QA,OM,RO,RU,RW,WS,SG,ST,ZA,KR,LK,SH,SD,SR,SZ,SE,CH,SY,TW,TJ,TZ,TH,TT,TN,TR,UG,UA,US,UZ,VU,VE,VN,ZM,ZW", currency = "AFN,DZD,ANG,AWG,AUD,AZN,BSD,BHD,BDT,BBD,BZD,BMD,BTN,BOB,BAM,BWP,BRL,BND,BGN,BIF,KHR,CAD,CVE,KYD,XOF,XAF,XPF,CLP,COP,KMF,CDF,CRC,EUR,CZK,DKK,DJF,DOP,XCD,EGP,SVC,ERN,ETB,EUR,FKP,FJD,GMD,GEL,GHS,GIP,GTQ,GNF,GYD,HTG,HNL,HKD,HUF,ISK,INR,IDR,IRR,IQD,ILS,JMD,JPY,JOD,KZT,KES,KWD,LAK,LBP,LSL,LRD,LYD,MOP,MKD,MGA,MWK,MYR,MVR,MRU,MUR,MXN,MDL,MNT,MAD,MZN,MMK,NAD,NPR,NZD,NIO,NGN,KPW,NOK,ARS,PKR,PAB,PGK,PYG,PEN,UYU,PHP,PLN,GBP,QAR,OMR,RON,RUB,RWF,WST,SAR,RSD,SCR,SLL,SGD,STN,SBD,SOS,ZAR,KRW,LKR,SHP,SDG,SRD,SZL,SEK,CHF,SYP,TWD,TJS,TZS,THB,TOP,TTD,TND,TRY,TMT,AED,UGX,UAH,USD,UZS,VUV,VND,YER,CNY,ZMW,ZWL" }
+credit = { country = "AF,DZ,AW,AU,AZ,BS,BH,BD,BB,BZ,BM,BT,BO,BA,BW,BR,BN,BG,BI,KH,CA,CV,KY,CL,CO,KM,CD,CR,CZ,DK,DJ,ST,DO,EC,EG,SV,ER,ET,FK,FJ,GM,GE,GH,GI,GT,GN,GY,HT,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IL,IT,JM,JP,JO,KZ,KE,KW,LA,LB,LS,LR,LY,LT,MO,MK,MG,MW,MY,MV,MR,MU,MX,MD,MN,MA,MZ,MM,NA,NZ,NI,NG,KP,NO,AR,PK,PG,PY,PE,UY,PH,PL,GB,QA,OM,RO,RU,RW,WS,SG,ST,ZA,KR,LK,SH,SD,SR,SZ,SE,CH,SY,TW,TJ,TZ,TH,TT,TN,TR,UG,UA,US,UZ,VU,VE,VN,ZM,ZW", currency = "AFN,DZD,ANG,AWG,AUD,AZN,BSD,BHD,BDT,BBD,BZD,BMD,BTN,BOB,BAM,BWP,BRL,BND,BGN,BIF,KHR,CAD,CVE,KYD,XOF,XAF,XPF,CLP,COP,KMF,CDF,CRC,EUR,CZK,DKK,DJF,DOP,XCD,EGP,SVC,ERN,ETB,EUR,FKP,FJD,GMD,GEL,GHS,GIP,GTQ,GNF,GYD,HTG,HNL,HKD,HUF,ISK,INR,IDR,IRR,IQD,ILS,JMD,JPY,JOD,KZT,KES,KWD,LAK,LBP,LSL,LRD,LYD,MOP,MKD,MGA,MWK,MYR,MVR,MRU,MUR,MXN,MDL,MNT,MAD,MZN,MMK,NAD,NPR,NZD,NIO,NGN,KPW,NOK,ARS,PKR,PAB,PGK,PYG,PEN,UYU,PHP,PLN,GBP,QAR,OMR,RON,RUB,RWF,WST,SAR,RSD,SCR,SLL,SGD,STN,SBD,SOS,ZAR,KRW,LKR,SHP,SDG,SRD,SZL,SEK,CHF,SYP,TWD,TJS,TZS,THB,TOP,TTD,TND,TRY,TMT,AED,UGX,UAH,USD,UZS,VUV,VND,YER,CNY,ZMW,ZWL" }
+google_pay = { country = "AF,DZ,AW,AU,AZ,BS,BH,BD,BB,BZ,BM,BT,BO,BA,BW,BR,BN,BG,BI,KH,CA,CV,KY,CL,CO,KM,CD,CR,CZ,DK,DJ,ST,DO,EC,EG,SV,ER,ET,FK,FJ,GM,GE,GH,GI,GT,GN,GY,HT,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IL,IT,JM,JP,JO,KZ,KE,KW,LA,LB,LS,LR,LY,LT,MO,MK,MG,MW,MY,MV,MR,MU,MX,MD,MN,MA,MZ,MM,NA,NZ,NI,NG,KP,NO,AR,PK,PG,PY,PE,UY,PH,PL,GB,QA,OM,RO,RU,RW,WS,SG,ST,ZA,KR,LK,SH,SD,SR,SZ,SE,CH,SY,TW,TJ,TZ,TH,TT,TN,TR,UG,UA,US,UZ,VU,VE,VN,ZM,ZW", currency = "AFN,DZD,ANG,AWG,AUD,AZN,BSD,BHD,BDT,BBD,BZD,BMD,BTN,BOB,BAM,BWP,BRL,BND,BGN,BIF,KHR,CAD,CVE,KYD,XOF,XAF,XPF,CLP,COP,KMF,CDF,CRC,EUR,CZK,DKK,DJF,DOP,XCD,EGP,SVC,ERN,ETB,EUR,FKP,FJD,GMD,GEL,GHS,GIP,GTQ,GNF,GYD,HTG,HNL,HKD,HUF,ISK,INR,IDR,IRR,IQD,ILS,JMD,JPY,JOD,KZT,KES,KWD,LAK,LBP,LSL,LRD,LYD,MOP,MKD,MGA,MWK,MYR,MVR,MRU,MUR,MXN,MDL,MNT,MAD,MZN,MMK,NAD,NPR,NZD,NIO,NGN,KPW,NOK,ARS,PKR,PAB,PGK,PYG,PEN,UYU,PHP,PLN,GBP,QAR,OMR,RON,RUB,RWF,WST,SAR,RSD,SCR,SLL,SGD,STN,SBD,SOS,ZAR,KRW,LKR,SHP,SDG,SRD,SZL,SEK,CHF,SYP,TWD,TJS,TZS,THB,TOP,TTD,TND,TRY,TMT,AED,UGX,UAH,USD,UZS,VUV,VND,YER,CNY,ZMW,ZWL" }
+apple_pay = { country = "AF,DZ,AW,AU,AZ,BS,BH,BD,BB,BZ,BM,BT,BO,BA,BW,BR,BN,BG,BI,KH,CA,CV,KY,CL,CO,KM,CD,CR,CZ,DK,DJ,ST,DO,EC,EG,SV,ER,ET,FK,FJ,GM,GE,GH,GI,GT,GN,GY,HT,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IL,IT,JM,JP,JO,KZ,KE,KW,LA,LB,LS,LR,LY,LT,MO,MK,MG,MW,MY,MV,MR,MU,MX,MD,MN,MA,MZ,MM,NA,NZ,NI,NG,KP,NO,AR,PK,PG,PY,PE,UY,PH,PL,GB,QA,OM,RO,RU,RW,WS,SG,ST,ZA,KR,LK,SH,SD,SR,SZ,SE,CH,SY,TW,TJ,TZ,TH,TT,TN,TR,UG,UA,US,UZ,VU,VE,VN,ZM,ZW", currency = "AFN,DZD,ANG,AWG,AUD,AZN,BSD,BHD,BDT,BBD,BZD,BMD,BTN,BOB,BAM,BWP,BRL,BND,BGN,BIF,KHR,CAD,CVE,KYD,XOF,XAF,XPF,CLP,COP,KMF,CDF,CRC,EUR,CZK,DKK,DJF,DOP,XCD,EGP,SVC,ERN,ETB,EUR,FKP,FJD,GMD,GEL,GHS,GIP,GTQ,GNF,GYD,HTG,HNL,HKD,HUF,ISK,INR,IDR,IRR,IQD,ILS,JMD,JPY,JOD,KZT,KES,KWD,LAK,LBP,LSL,LRD,LYD,MOP,MKD,MGA,MWK,MYR,MVR,MRU,MUR,MXN,MDL,MNT,MAD,MZN,MMK,NAD,NPR,NZD,NIO,NGN,KPW,NOK,ARS,PKR,PAB,PGK,PYG,PEN,UYU,PHP,PLN,GBP,QAR,OMR,RON,RUB,RWF,WST,SAR,RSD,SCR,SLL,SGD,STN,SBD,SOS,ZAR,KRW,LKR,SHP,SDG,SRD,SZL,SEK,CHF,SYP,TWD,TJS,TZS,THB,TOP,TTD,TND,TRY,TMT,AED,UGX,UAH,USD,UZS,VUV,VND,YER,CNY,ZMW,ZWL" }
+
+[pm_filters.worldpayvantiv]
+debit = { country = "AF,DZ,AW,AU,AZ,BS,BH,BD,BB,BZ,BM,BT,BO,BA,BW,BR,BN,BG,BI,KH,CA,CV,KY,CL,CO,KM,CD,CR,CZ,DK,DJ,ST,DO,EC,EG,SV,ER,ET,FK,FJ,GM,GE,GH,GI,GT,GN,GY,HT,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IL,IT,JM,JP,JO,KZ,KE,KW,LA,LB,LS,LR,LY,LT,MO,MK,MG,MW,MY,MV,MR,MU,MX,MD,MN,MA,MZ,MM,NA,NZ,NI,NG,KP,NO,AR,PK,PG,PY,PE,UY,PH,PL,GB,QA,OM,RO,RU,RW,WS,SG,ST,ZA,KR,LK,SH,SD,SR,SZ,SE,CH,SY,TW,TJ,TZ,TH,TT,TN,TR,UG,UA,US,UZ,VU,VE,VN,ZM,ZW", currency = "AFN,DZD,ANG,AWG,AUD,AZN,BSD,BHD,BDT,BBD,BZD,BMD,BTN,BOB,BAM,BWP,BRL,BND,BGN,BIF,KHR,CAD,CVE,KYD,XOF,XAF,XPF,CLP,COP,KMF,CDF,CRC,EUR,CZK,DKK,DJF,DOP,XCD,EGP,SVC,ERN,ETB,EUR,FKP,FJD,GMD,GEL,GHS,GIP,GTQ,GNF,GYD,HTG,HNL,HKD,HUF,ISK,INR,IDR,IRR,IQD,ILS,JMD,JPY,JOD,KZT,KES,KWD,LAK,LBP,LSL,LRD,LYD,MOP,MKD,MGA,MWK,MYR,MVR,MRU,MUR,MXN,MDL,MNT,MAD,MZN,MMK,NAD,NPR,NZD,NIO,NGN,KPW,NOK,ARS,PKR,PAB,PGK,PYG,PEN,UYU,PHP,PLN,GBP,QAR,OMR,RON,RUB,RWF,WST,SAR,RSD,SCR,SLL,SGD,STN,SBD,SOS,ZAR,KRW,LKR,SHP,SDG,SRD,SZL,SEK,CHF,SYP,TWD,TJS,TZS,THB,TOP,TTD,TND,TRY,TMT,AED,UGX,UAH,USD,UZS,VUV,VND,YER,CNY,ZMW,ZWL" }
+credit = { country = "AF,DZ,AW,AU,AZ,BS,BH,BD,BB,BZ,BM,BT,BO,BA,BW,BR,BN,BG,BI,KH,CA,CV,KY,CL,CO,KM,CD,CR,CZ,DK,DJ,ST,DO,EC,EG,SV,ER,ET,FK,FJ,GM,GE,GH,GI,GT,GN,GY,HT,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IL,IT,JM,JP,JO,KZ,KE,KW,LA,LB,LS,LR,LY,LT,MO,MK,MG,MW,MY,MV,MR,MU,MX,MD,MN,MA,MZ,MM,NA,NZ,NI,NG,KP,NO,AR,PK,PG,PY,PE,UY,PH,PL,GB,QA,OM,RO,RU,RW,WS,SG,ST,ZA,KR,LK,SH,SD,SR,SZ,SE,CH,SY,TW,TJ,TZ,TH,TT,TN,TR,UG,UA,US,UZ,VU,VE,VN,ZM,ZW", currency = "AFN,DZD,ANG,AWG,AUD,AZN,BSD,BHD,BDT,BBD,BZD,BMD,BTN,BOB,BAM,BWP,BRL,BND,BGN,BIF,KHR,CAD,CVE,KYD,XOF,XAF,XPF,CLP,COP,KMF,CDF,CRC,EUR,CZK,DKK,DJF,DOP,XCD,EGP,SVC,ERN,ETB,EUR,FKP,FJD,GMD,GEL,GHS,GIP,GTQ,GNF,GYD,HTG,HNL,HKD,HUF,ISK,INR,IDR,IRR,IQD,ILS,JMD,JPY,JOD,KZT,KES,KWD,LAK,LBP,LSL,LRD,LYD,MOP,MKD,MGA,MWK,MYR,MVR,MRU,MUR,MXN,MDL,MNT,MAD,MZN,MMK,NAD,NPR,NZD,NIO,NGN,KPW,NOK,ARS,PKR,PAB,PGK,PYG,PEN,UYU,PHP,PLN,GBP,QAR,OMR,RON,RUB,RWF,WST,SAR,RSD,SCR,SLL,SGD,STN,SBD,SOS,ZAR,KRW,LKR,SHP,SDG,SRD,SZL,SEK,CHF,SYP,TWD,TJS,TZS,THB,TOP,TTD,TND,TRY,TMT,AED,UGX,UAH,USD,UZS,VUV,VND,YER,CNY,ZMW,ZWL" }
+apple_pay = { country = "AF,DZ,AW,AU,AZ,BS,BH,BD,BB,BZ,BM,BT,BO,BA,BW,BR,BN,BG,BI,KH,CA,CV,KY,CL,CO,KM,CD,CR,CZ,DK,DJ,ST,DO,EC,EG,SV,ER,ET,FK,FJ,GM,GE,GH,GI,GT,GN,GY,HT,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IL,IT,JM,JP,JO,KZ,KE,KW,LA,LB,LS,LR,LY,LT,MO,MK,MG,MW,MY,MV,MR,MU,MX,MD,MN,MA,MZ,MM,NA,NZ,NI,NG,KP,NO,AR,PK,PG,PY,PE,UY,PH,PL,GB,QA,OM,RO,RU,RW,WS,SG,ST,ZA,KR,LK,SH,SD,SR,SZ,SE,CH,SY,TW,TJ,TZ,TH,TT,TN,TR,UG,UA,US,UZ,VU,VE,VN,ZM,ZW", currency = "AFN,DZD,ANG,AWG,AUD,AZN,BSD,BHD,BDT,BBD,BZD,BMD,BTN,BOB,BAM,BWP,BRL,BND,BGN,BIF,KHR,CAD,CVE,KYD,XOF,XAF,XPF,CLP,COP,KMF,CDF,CRC,EUR,CZK,DKK,DJF,DOP,XCD,EGP,SVC,ERN,ETB,EUR,FKP,FJD,GMD,GEL,GHS,GIP,GTQ,GNF,GYD,HTG,HNL,HKD,HUF,ISK,INR,IDR,IRR,IQD,ILS,JMD,JPY,JOD,KZT,KES,KWD,LAK,LBP,LSL,LRD,LYD,MOP,MKD,MGA,MWK,MYR,MVR,MRU,MUR,MXN,MDL,MNT,MAD,MZN,MMK,NAD,NPR,NZD,NIO,NGN,KPW,NOK,ARS,PKR,PAB,PGK,PYG,PEN,UYU,PHP,PLN,GBP,QAR,OMR,RON,RUB,RWF,WST,SAR,RSD,SCR,SLL,SGD,STN,SBD,SOS,ZAR,KRW,LKR,SHP,SDG,SRD,SZL,SEK,CHF,SYP,TWD,TJS,TZS,THB,TOP,TTD,TND,TRY,TMT,AED,UGX,UAH,USD,UZS,VUV,VND,YER,CNY,ZMW,ZWL" }
+google_pay = { country = "AF,DZ,AW,AU,AZ,BS,BH,BD,BB,BZ,BM,BT,BO,BA,BW,BR,BN,BG,BI,KH,CA,CV,KY,CL,CO,KM,CD,CR,CZ,DK,DJ,ST,DO,EC,EG,SV,ER,ET,FK,FJ,GM,GE,GH,GI,GT,GN,GY,HT,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IL,IT,JM,JP,JO,KZ,KE,KW,LA,LB,LS,LR,LY,LT,MO,MK,MG,MW,MY,MV,MR,MU,MX,MD,MN,MA,MZ,MM,NA,NZ,NI,NG,KP,NO,AR,PK,PG,PY,PE,UY,PH,PL,GB,QA,OM,RO,RU,RW,WS,SG,ST,ZA,KR,LK,SH,SD,SR,SZ,SE,CH,SY,TW,TJ,TZ,TH,TT,TN,TR,UG,UA,US,UZ,VU,VE,VN,ZM,ZW", currency = "AFN,DZD,ANG,AWG,AUD,AZN,BSD,BHD,BDT,BBD,BZD,BMD,BTN,BOB,BAM,BWP,BRL,BND,BGN,BIF,KHR,CAD,CVE,KYD,XOF,XAF,XPF,CLP,COP,KMF,CDF,CRC,EUR,CZK,DKK,DJF,DOP,XCD,EGP,SVC,ERN,ETB,EUR,FKP,FJD,GMD,GEL,GHS,GIP,GTQ,GNF,GYD,HTG,HNL,HKD,HUF,ISK,INR,IDR,IRR,IQD,ILS,JMD,JPY,JOD,KZT,KES,KWD,LAK,LBP,LSL,LRD,LYD,MOP,MKD,MGA,MWK,MYR,MVR,MRU,MUR,MXN,MDL,MNT,MAD,MZN,MMK,NAD,NPR,NZD,NIO,NGN,KPW,NOK,ARS,PKR,PAB,PGK,PYG,PEN,UYU,PHP,PLN,GBP,QAR,OMR,RON,RUB,RWF,WST,SAR,RSD,SCR,SLL,SGD,STN,SBD,SOS,ZAR,KRW,LKR,SHP,SDG,SRD,SZL,SEK,CHF,SYP,TWD,TJS,TZS,THB,TOP,TTD,TND,TRY,TMT,AED,UGX,UAH,USD,UZS,VUV,VND,YER,CNY,ZMW,ZWL" }
+
+[pm_filters.worldpaymodular]
+google_pay = { country = "AL, DZ, AS, AO, AG, AR, AU, AT, AZ, BH, BY, BE, BR, BG, CA, CL, CO, HR, CZ, DK, DO, EG, EE, FI, FR, DE, GR, HK, HU, IN, ID, IE, IL, IT, JP, JO, KZ, KE, KW, LV, LB, LT, LU, MY, MX, NL, NZ, NO, OM, PK, PA, PE, PH, PL, PT, QA, RO, RU, SA, SG, SK, ZA, ES, LK, SE, CH, TW, TH, TR, UA, AE, GB, US, UY, VN", currency = "DZD, AOA, USD, XCD, ARS, AUD, AZN, EUR, BHD, BYN, BRL, BGN, CAD, CLP, COP, CZK, DKK, DOP, EGP, HKD, HUF, INR, IDR, ILS, JPY, JOD, KZT, KES, KWD, LBP, MYR, MXN, NZD, NOK, OMR, PKR, PAB, PEN, PHP, PLN, QAR, RON, RUB, SAR, SGD, ZAR, LKR, SEK, CHF, TWD, THB, TRY, UAH, AED, GBP, UYU, VND" }
+apple_pay = { country = "EG, MA, ZA, AU, CN, HK, JP, MO, MY, MN, NZ, SG, TW, VN, AM, AT, AZ, BY, BE, BG, HR, CY, CZ, DK, EE, FO, FI, FR, GE, DE, GR, GL, GG, HU, IE, IS, IM, IT, KZ, JE, LV, LI, LT, LU, MT, MD, MC, ME, NL, NO, PL, PT, RO, SM, RS, SK, SI, ES, SE, CH, UA, GB, VA, AR, BR, CL, CO, CR, DO, EC, SV, GT, HN, MX, PA, PY, PE, BS, BH, IL, JO, KW, OM, PS, QA, SA, AE, CA, US, PR", currency = "EGP, MAD, ZAR, AUD, CNY, HKD, JPY, MOP, MYR, MNT, NZD, SGD, KRW, TWD, VND, EUR, AZN, BYN, BGN, CZK, DKK, GEL, GBP, HUF, ISK, KZT, CHF, MDL, NOK, PLN, RON, RSD, SEK, UAH, ARS, BRL, CLP, COP, CRC, DOP, USD, GTQ, HNL, MXN, PAB, PYG, PEN, BSD, UYU, BHD, ILS, JOD, KWD, OMR, QAR, SAR, AED, CAD" }
+
+[pm_filters.calida]
+bluecode = { country = "AT,BE,BG,HR,CY,CZ,DK,EE,FI,FR,DE,GR,HU,IE,IT,LV,LT,LU,MT,NL,PL,PT,RO,SK,SI,ES,SE,IS,LI,NO", currency = "EUR" }
+
+[file_upload_config]
+bucket_name = ""
+region = ""
+
+[pm_filters.forte]
+credit = { country = "US, CA", currency = "CAD,USD"}
+debit = { country = "US, CA", currency = "CAD,USD"}
+
+[pm_filters.nordea]
+sepa = { country = "DK,FI,NO,SE", currency = "DKK,EUR,NOK,SEK" }
+
+[pm_filters.fiuu]
+duit_now = { country = "MY", currency = "MYR" }
+apple_pay = { country = "MY", currency = "MYR" }
+google_pay = { country = "MY", currency = "MYR" }
+online_banking_fpx = { country = "MY", currency = "MYR" }
+credit = { country = "CN,HK,ID,MY,PH,SG,TH,TW,VN", currency = "CNY,HKD,IDR,MYR,PHP,SGD,THB,TWD,VND" }
+debit = { country = "CN,HK,ID,MY,PH,SG,TH,TW,VN", currency = "CNY,HKD,IDR,MYR,PHP,SGD,THB,TWD,VND" }
+
+[pm_filters.inespay]
+sepa = { country = "ES", currency = "EUR"}
+
+[pm_filters.bluesnap]
+credit = { country = "AD,AE,AG,AL,AM,AO,AR,AT,AU,AZ,BA,BB,BD,BE,BG,BH,BI,BJ,BN,BO,BR,BS,BT,BW,BY,BZ,CA,CD,CF,CG,CH,CI,CL,CM,CN,CO,CR,CV,CY,CZ,DE,DK,DJ,DM,DO,DZ,EC,EE,EG,ER,ES,ET,FI,FJ,FM,FR,GA,GB,GD,GE,GG,GH,GM,GN,GQ,GR,GT,GW,GY,HN,HR,HT,HU,ID,IE,IL,IN,IS,IT,JM,JP,JO,KE,KG,KH,KI,KM,KN,KR,KW,KZ,LA,LB,LC,LI,LK,LR,LS,LT,LU,LV,MA,MC,MD,ME,MG,MH,MK,ML,MM,MN,MR,MT,MU,MV,MW,MX,MY,MZ,NA,NE,NG,NI,NL,NO,NP,NR,NZ,OM,PA,PE,PG,PH,PK,PL,PS,PT,PW,PY,QA,RO,RS,RW,SA,SB,SC,SE,SG,SI,SK,SL,SM,SN,SO,SR,SS,ST,SV,SZ,TD,TG,TH,TJ,TL,TM,TN,TO,TR,TT,TV,TZ,UA,UG,US,UY,UZ,VA,VC,VE,VN,VU,WS,ZA,ZM,ZW", currency = "AED,AFN,ALL,AMD,ANG,ARS,AUD,AWG,BAM,BBD,BGN,BHD,BMD,BND,BOB,BRL,BSD,BWP,CAD,CHF,CLP,CNY,COP,CRC,CZK,DKK,DOP,DZD,EGP,EUR,FJD,GBP,GEL,GIP,GTQ,HKD,HUF,IDR,ILS,INR,ISK,JMD,JPY,KES,KHR,KRW,KWD,KYD,KZT,LBP,LKR,MAD,MDL,MKD,MUR,MWK,MXN,MYR,NAD,NGN,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PLN,PKR,QAR,RON,RSD,RUB,SAR,SCR,SDG,SEK,SGD,THB,TND,TRY,TTD,TWD,TZS,UAH,USD,UYU,UZS,VND,XAF,XCD,XOF,ZAR"}
+google_pay = { country = "AL, DZ, AS, AO, AG, AR, AU, AT, AZ, BH, BY, BE, BR, BG, CL, CO, HR, CZ, DK, DO, EG, EE, FI, FR, DE, GR, HK, HU, IN, ID, IE, IL, IT, JP, JO, KZ, KE, KW, LV, LB, LT, LU, MY, MX, NL, NZ, NO, OM, PK, PA, PE, PH, PL, PT, QA, RO, RU, SA, SG, SK, ZA, ES, LK, SE, CH, TW, TH, TR, UA, AE, GB, US, UY, VN", currency = "ALL, DZD, USD, XCD, ARS, AUD, EUR, BHD, BRL, BGN, CAD, CLP, COP, CZK, DKK, DOP, EGP, HKD, HUF, INR, IDR, ILS, JPY, KZT, KES, KWD, LBP, MYR, MXN, NZD, NOK, OMR, PKR, PAB, PEN, PHP, PLN, QAR, RON, RUB, SAR, SGD, ZAR, LKR, SEK, CHF, TWD, THB, TRY, UAH, AED, GBP, UYU, VND"}
+apple_pay = { country = "EG, MA, ZA, AU, HK, JP, MO, MY, MN, NZ, SG, KR, TW, VN, AM, AT, AZ, BY, BE, BG, HR, CY, DK, EE, FO, FI, FR, GE, DE, GR, GL, GG, HU, IS, IE, IM, IT , KZ, JE, LV, LI, LT, LU, MT, MD, MC, ME, NL, NO, PL, PT, RO, SM, RS, SI, ES, SE, CH, UA, GB, VA, AR, BR, CL, CO, CR, DO, EC, SV, GT, HN, MX, PA, PY, PE, BS, UY, BH, IL, JO, KW, OM, PS, QA, SA, AE, CA, US", currency = "EGP, MAD, ZAR, AUD, CNY, HKD, JPY, MYR, NZD, SGD, KRW, TWD, VND, AMD, EUR, BGN, CZK, DKK, GEL, GBP, HUF, ISK, KZT, CHF, MDL, NOK, PLN, RON, RSD, SEK, UAH, GBP, ARS, BRL, CLP, COP, CRC, DOP, USD, GTQ, MXN, PAB, PEN, BSD, UYU, BHD, ILS, KWD, OMR, QAR, SAR, AED, CAD"}
+
+[pm_filters.fiserv]
+credit = {country = "AU,NZ,CN,HK,IN,LK,KR,MY,SG,GB,BE,FR,DE,IT,ME,NL,PL,ES,ZA,AR,BR,CO,MX,PA,UY,US,CA", currency = "AFN,ALL,DZD,AOA,ARS,AMD,AWG,AUD,AZN,BSD,BHD,BDT,BBD,BYN,BZD,BMD,BTN,BOB,VES,BAM,BWP,BRL,BND,BGN,BIF,KHR,CAD,CVE,KYD,XAF,CLP,CNY,COP,KMF,CDF,CRC,HRK,CUP,CZK,DKK,DJF,DOP,XCD,EGP,ERN,ETB,EUR,FKP,FJD,XPF,GMD,GEL,GHS,GIP,GTQ,GNF,GYD,HTG,HNL,HKD,HUF,ISK,INR,IDR,IRR,IQD,ILS,JMD,JPY,JOD,KZT,KES,KGS,KWD,LAK,LBP,LSL,LRD,LYD,MOP,MKD,MGA,MWK,MYR,MVR,MRU,MUR,MXN,MDL,MNT,MAD,MZN,MMK,NAD,NPR,ANG,NZD,NIO,NGN,VUV,KPW,NOK,OMR,PKR,PAB,PGK,PYG,PEN,PHP,PLN,GBP,QAR,RON,RUB,RWF,SHP,SVC,WST,STN,SAR,RSD,SCR,SLL,SGD,SBD,SOS,ZAR,KRW,SSP,LKR,SDG,SRD,SZL,SEK,CHF,SYP,TWD,TJS,TZS,THB,TOP,TTD,TND,TRY,TMT,UGX,UAH,AED,USD,UYU,UZS,VND,XOF,YER,ZMW,ZWL"}
+debit = {country = "AU,NZ,CN,HK,IN,LK,KR,MY,SG,GB,BE,FR,DE,IT,ME,NL,PL,ES,ZA,AR,BR,CO,MX,PA,UY,US,CA", currency = "AFN,ALL,DZD,AOA,ARS,AMD,AWG,AUD,AZN,BSD,BHD,BDT,BBD,BYN,BZD,BMD,BTN,BOB,VES,BAM,BWP,BRL,BND,BGN,BIF,KHR,CAD,CVE,KYD,XAF,CLP,CNY,COP,KMF,CDF,CRC,HRK,CUP,CZK,DKK,DJF,DOP,XCD,EGP,ERN,ETB,EUR,FKP,FJD,XPF,GMD,GEL,GHS,GIP,GTQ,GNF,GYD,HTG,HNL,HKD,HUF,ISK,INR,IDR,IRR,IQD,ILS,JMD,JPY,JOD,KZT,KES,KGS,KWD,LAK,LBP,LSL,LRD,LYD,MOP,MKD,MGA,MWK,MYR,MVR,MRU,MUR,MXN,MDL,MNT,MAD,MZN,MMK,NAD,NPR,ANG,NZD,NIO,NGN,VUV,KPW,NOK,OMR,PKR,PAB,PGK,PYG,PEN,PHP,PLN,GBP,QAR,RON,RUB,RWF,SHP,SVC,WST,STN,SAR,RSD,SCR,SLL,SGD,SBD,SOS,ZAR,KRW,SSP,LKR,SDG,SRD,SZL,SEK,CHF,SYP,TWD,TJS,TZS,THB,TOP,TTD,TND,TRY,TMT,UGX,UAH,AED,USD,UYU,UZS,VND,XOF,YER,ZMW,ZWL"}
+paypal = { currency = "AUD,EUR,BRL,CAD,CNY,EUR,EUR,EUR,GBP,HKD,INR,EUR,JPY,MYR,EUR,NZD,PHP,PLN,SGD,USD", country = "AU, BE, BR, CA, CN, DE, ES, FR, GB, HK, IN, IT, JP, MY, NL, NZ, PH, PL, SG, US" }
+google_pay = { country = "AU,AT,BE,BR,CA,CN,HK,MY,NZ,SG,US", currency = "AUD,EUR,EUR,BRL,CAD,CNY,HKD,MYR,NZD,SGD,USD" }
+apple_pay = { country = "AU,NZ,CN,HK,JP,SG,MY,KR,TW,VN,GB,IE,FR,DE,IT,ES,PT,NL,BE,LU,AT,CH,SE,FI,DK,NO,PL,CZ,SK,HU,LT,LV,EE,GR,RO,BG,HR,SI,MT,CY,IS,LI,MC,SM,VA,US,CA,MX,BR,AR,CL,CO,PE,UY,CR,PA,DO,EC,SV,GT,HN,BS,PR,AE,SA,QA,KW,BH,OM,IL,JO,PS,EG,MA,ZA,GE,AM,AZ,MD,ME,MK,AL,BA,RS,UA", currency = "AUD,BRL,CAD,CHF,CZK,DKK,EUR,GBP,HKD,HUF,ILS,JPY,MXN,NOK,NZD,PHP,PLN,SEK,SGD,THB,TWD,USD" }
+
+
+[pm_filters.amazonpay]
+amazon_pay = { country = "US", currency = "USD" }
+
+[pm_filters.rapyd]
+apple_pay = { country = "BR, CA, CL, CO, DO, SV, MX, PE, PT, US, AT, BE, BG, HR, CY, CZ, DO, DK, EE, FI, FR, GE, DE, GR, GL, HU, IS, IE, IL, IT, LV, LI, LT, LU, MT, MD, MC, ME, NL, NO, PL, RO, SM, SK, SI, ZA, ES, SE, CH, GB, VA, AU, HK, JP, MY, NZ, SG, KR, TW, VN", currency = "AMD, AUD, BGN, BRL, BYN, CAD, CHF, CLP, CNY, COP, CRC, CZK, DKK, DOP, EUR, GBP, GEL, GTQ, HUF, ISK, JPY, KRW, MDL, MXN, MYR, NOK, PAB, PEN, PLN, PYG, RON, RSD, SEK, SGD, TWD, UAH, USD, UYU, VND, ZAR" }
+google_pay = { country = "BR, CA, CL, CO, DO, MX, PE, PT, US, AT, BE, BG, HR, CZ, DK, EE, FI, FR, DE, GR, HU, IE, IL, IT, LV, LT, LU, NZ, NO, GB, PL, RO, RU, SK, ZA, ES, SE, CH, TR, AU, HK, IN, ID, JP, MY, PH, SG, TW, TH, VN", currency = "AUD, BGN, BRL, BYN, CAD, CHF, CLP, COP, CZK, DKK, DOP, EUR, GBP, HUF, IDR, JPY, KES, MXN, MYR, NOK, PAB, PEN, PHP, PLN, RON, RUB, SEK, SGD, THB, TRY, TWD, UAH, USD, UYU, VND, ZAR" }
+credit = { country = "AE,AF,AG,AI,AL,AM,AO,AQ,AR,AS,AT,AU,AW,AX,AZ,BA,BB,BD,BE,BF,BG,BH,BI,BJ,BL,BM,BN,BO,BQ,BR,BS,BT,BV,BW,BY,BZ,CA,CC,CD,CF,CG,CH,CI,CK,CL,CM,CN,CO,CR,CU,CV,CW,CX,CY,CZ,DE,DJ,DK,DM,DO,DZ,EC,EE,EG,EH,ER,ES,ET,FI,FJ,FK,FM,FO,FR,GA,GB,GD,GE,GF,GG,GH,GI,GL,GM,GN,GP,GQ,GR,GT,GU,GW,GY,HK,HM,HN,HR,HT,HU,ID,IE,IL,IM,IN,IO,IQ,IR,IS,IT,JE,JM,JO,JP,KE,KG,KH,KI,KM,KN,KP,KR,KW,KY,KZ,LA,LB,LC,LI,LK,LR,LS,LT,LU,LV,LY,MA,MC,MD,ME,MF,MG,MH,MK,ML,MM,MN,MO,MP,MQ,MR,MS,MT,MU,MV,MW,MX,MY,MZ,NA,NC,NE,NF,NG,NI,NL,NO,NP,NR,NU,NZ,OM,PA,PE,PF,PG,PH,PK,PL,PM,PN,PR,PS,PT,PW,PY,QA,RE,RO,RS,RU,RW,SA,SB,SC,SD,SE,SG,SH,SI,SJ,SK,SL,SM,SN,SO,SR,SS,ST,SV,SX,SY,SZ,TC,TD,TF,TG,TH,TJ,TL,TM,TN,TO,TR,TT,TV,TW,TZ,UA,UG,UM,US,UY,UZ,VA,VC,VE,VG,VI,VN,VU,WF,WS,YE,YT,ZA,ZM,ZW", currency = "AED,AUD,BDT,BGN,BND,BOB,BRL,BWP,CAD,CHF,CNY,COP,CZK,DKK,EGP,EUR,FJD,GBP,GEL,GHS,HKD,HRK,HUF,IDR,ILS,INR,IQD,IRR,ISK,JPY,KES,KRW,KWD,KZT,LAK,LKR,MAD,MDL,MMK,MOP,MXN,MYR,MZN,NAD,NGN,NOK,NPR,NZD,PEN,PHP,PKR,PLN,QAR,RON,RSD,RUB,RWF,SAR,SCR,SEK,SGD,SLL,THB,TRY,TWD,TZS,UAH,UGX,USD,UYU,VND,XAF,XOF,ZAR,ZMW,MWK" }
+debit = { country = "AE,AF,AG,AI,AL,AM,AO,AQ,AR,AS,AT,AU,AW,AX,AZ,BA,BB,BD,BE,BF,BG,BH,BI,BJ,BL,BM,BN,BO,BQ,BR,BS,BT,BV,BW,BY,BZ,CA,CC,CD,CF,CG,CH,CI,CK,CL,CM,CN,CO,CR,CU,CV,CW,CX,CY,CZ,DE,DJ,DK,DM,DO,DZ,EC,EE,EG,EH,ER,ES,ET,FI,FJ,FK,FM,FO,FR,GA,GB,GD,GE,GF,GG,GH,GI,GL,GM,GN,GP,GQ,GR,GT,GU,GW,GY,HK,HM,HN,HR,HT,HU,ID,IE,IL,IM,IN,IO,IQ,IR,IS,IT,JE,JM,JO,JP,KE,KG,KH,KI,KM,KN,KP,KR,KW,KY,KZ,LA,LB,LC,LI,LK,LR,LS,LT,LU,LV,LY,MA,MC,MD,ME,MF,MG,MH,MK,ML,MM,MN,MO,MP,MQ,MR,MS,MT,MU,MV,MW,MX,MY,MZ,NA,NC,NE,NF,NG,NI,NL,NO,NP,NR,NU,NZ,OM,PA,PE,PF,PG,PH,PK,PL,PM,PN,PR,PS,PT,PW,PY,QA,RE,RO,RS,RU,RW,SA,SB,SC,SD,SE,SG,SH,SI,SJ,SK,SL,SM,SN,SO,SR,SS,ST,SV,SX,SY,SZ,TC,TD,TF,TG,TH,TJ,TL,TM,TN,TO,TR,TT,TV,TW,TZ,UA,UG,UM,US,UY,UZ,VA,VC,VE,VG,VI,VN,VU,WF,WS,YE,YT,ZA,ZM,ZW", currency = "AED,AUD,BDT,BGN,BND,BOB,BRL,BWP,CAD,CHF,CNY,COP,CZK,DKK,EGP,EUR,FJD,GBP,GEL,GHS,HKD,HRK,HUF,IDR,ILS,INR,IQD,IRR,ISK,JPY,KES,KRW,KWD,KZT,LAK,LKR,MAD,MDL,MMK,MOP,MXN,MYR,MZN,NAD,NGN,NOK,NPR,NZD,PEN,PHP,PKR,PLN,QAR,RON,RSD,RUB,RWF,SAR,SCR,SEK,SGD,SLL,THB,TRY,TWD,TZS,UAH,UGX,USD,UYU,VND,XAF,XOF,ZAR,ZMW,MWK" }
+
+[pm_filters.bamboraapac]
+credit = { country = "AD,AE,AG,AL,AM,AO,AR,AT,AU,AZ,BA,BB,BD,BE,BG,BH,BI,BJ,BN,BO,BR,BS,BT,BW,BY,BZ,CA,CD,CF,CG,CH,CI,CL,CM,CN,CO,CR,CV,CY,CZ,DE,DK,DJ,DM,DO,DZ,EC,EE,EG,ER,ES,ET,FI,FJ,FM,FR,GA,GB,GD,GE,GG,GH,GM,GN,GQ,GR,GT,GW,GY,HN,HR,HT,HU,ID,IE,IL,IN,IS,IT,JM,JP,JO,KE,KG,KH,KI,KM,KN,KR,KW,KZ,LA,LB,LC,LI,LK,LR,LS,LT,LU,LV,MA,MC,MD,ME,MG,MH,MK,ML,MM,MN,MR,MT,MU,MV,MW,MX,MY,MZ,NA,NE,NG,NI,NL,NO,NP,NR,NZ,OM,PA,PE,PG,PH,PK,PL,PS,PT,PW,PY,QA,RO,RS,RW,SA,SB,SC,SE,SG,SI,SK,SL,SM,SN,SO,SR,SS,ST,SV,SZ,TD,TG,TH,TJ,TL,TM,TN,TO,TR,TT,TV,TZ,UA,UG,US,UY,UZ,VA,VC,VE,VN,VU,WS,ZA,ZM,ZW", currency = "AED,AUD,BDT,BGN,BND,BOB,BRL,BWP,CAD,CHF,CNY,COP,CZK,DKK,EGP,EUR,FJD,GBP,GEL,GHS,HKD,HRK,HUF,IDR,ILS,INR,IQD,IRR,ISK,JPY,KES,KRW,KWD,KZT,LAK,LKR,MAD,MDL,MMK,MOP,MXN,MYR,MZN,NAD,NGN,NOK,NPR,NZD,PEN,PHP,PKR,PLN,QAR,RON,RSD,RUB,RWF,SAR,SCR,SEK,SGD,SLL,THB,TRY,TWD,TZS,UAH,UGX,USD,UYU,VND,XAF,XOF,ZAR,ZMW,MWK" }
+debit = { country = "AD,AE,AG,AL,AM,AO,AR,AT,AU,AZ,BA,BB,BD,BE,BG,BH,BI,BJ,BN,BO,BR,BS,BT,BW,BY,BZ,CA,CD,CF,CG,CH,CI,CL,CM,CN,CO,CR,CV,CY,CZ,DE,DK,DJ,DM,DO,DZ,EC,EE,EG,ER,ES,ET,FI,FJ,FM,FR,GA,GB,GD,GE,GG,GH,GM,GN,GQ,GR,GT,GW,GY,HN,HR,HT,HU,ID,IE,IL,IN,IS,IT,JM,JP,JO,KE,KG,KH,KI,KM,KN,KR,KW,KZ,LA,LB,LC,LI,LK,LR,LS,LT,LU,LV,MA,MC,MD,ME,MG,MH,MK,ML,MM,MN,MR,MT,MU,MV,MW,MX,MY,MZ,NA,NE,NG,NI,NL,NO,NP,NR,NZ,OM,PA,PE,PG,PH,PK,PL,PS,PT,PW,PY,QA,RO,RS,RW,SA,SB,SC,SE,SG,SI,SK,SL,SM,SN,SO,SR,SS,ST,SV,SZ,TD,TG,TH,TJ,TL,TM,TN,TO,TR,TT,TV,TZ,UA,UG,US,UY,UZ,VA,VC,VE,VN,VU,WS,ZA,ZM,ZW", currency = "AED,AUD,BDT,BGN,BND,BOB,BRL,BWP,CAD,CHF,CNY,COP,CZK,DKK,EGP,EUR,FJD,GBP,GEL,GHS,HKD,HRK,HUF,IDR,ILS,INR,IQD,IRR,ISK,JPY,KES,KRW,KWD,KZT,LAK,LKR,MAD,MDL,MMK,MOP,MXN,MYR,MZN,NAD,NGN,NOK,NPR,NZD,PEN,PHP,PKR,PLN,QAR,RON,RSD,RUB,RWF,SAR,SCR,SEK,SGD,SLL,THB,TRY,TWD,TZS,UAH,UGX,USD,UYU,VND,XAF,XOF,ZAR,ZMW,MWK" }
+
+[pm_filters.gocardless]
+ach = { country = "US", currency = "USD" }
+becs = { country = "AU", currency = "AUD" }
+sepa = { country = "AU,AT,BE,BG,CA,HR,CY,CZ,DK,FI,FR,DE,HU,IT,LU,MT,NL,NZ,NO,PL,PT,IE,RO,SK,SI,ZA,ES,SE,CH,GB", currency = "GBP,EUR,SEK,DKK,AUD,NZD,CAD" }
+
+[pm_filters.powertranz]
+credit = { country = "AE,AF,AG,AI,AL,AM,AO,AQ,AR,AS,AT,AU,AW,AX,AZ,BA,BB,BD,BE,BF,BG,BH,BI,BJ,BL,BM,BN,BO,BQ,BR,BS,BT,BV,BW,BY,BZ,CA,CC,CD,CF,CG,CH,CI,CK,CL,CM,CN,CO,CR,CU,CV,CW,CX,CY,CZ,DE,DJ,DK,DM,DO,DZ,EC,EE,EG,EH,ER,ES,ET,FI,FJ,FK,FM,FO,FR,GA,GB,GD,GE,GF,GG,GH,GI,GL,GM,GN,GP,GQ,GR,GT,GU,GW,GY,HK,HM,HN,HR,HT,HU,ID,IE,IL,IM,IN,IO,IQ,IR,IS,IT,JE,JM,JO,JP,KE,KG,KH,KI,KM,KN,KP,KR,KW,KY,KZ,LA,LB,LC,LI,LK,LR,LS,LT,LU,LV,LY,MA,MC,MD,ME,MF,MG,MH,MK,ML,MM,MN,MO,MP,MQ,MR,MS,MT,MU,MV,MW,MX,MY,MZ,NA,NC,NE,NF,NG,NI,NL,NO,NP,NR,NU,NZ,OM,PA,PE,PF,PG,PH,PK,PL,PM,PN,PR,PS,PT,PW,PY,QA,RE,RO,RS,RU,RW,SA,SB,SC,SD,SE,SG,SH,SI,SJ,SK,SL,SM,SN,SO,SR,SS,ST,SV,SX,SY,SZ,TC,TD,TF,TG,TH,TJ,TL,TM,TN,TO,TR,TT,TV,TW,TZ,UA,UG,UM,US,UY,UZ,VA,VC,VE,VG,VI,VN,VU,WF,WS,YE,YT,ZA,ZM,ZW", currency = "BBD,BMD,BSD,CRC,GTQ,HNL,JMD,KYD,TTD,USD" }
+debit = { country = "AE,AF,AG,AI,AL,AM,AO,AQ,AR,AS,AT,AU,AW,AX,AZ,BA,BB,BD,BE,BF,BG,BH,BI,BJ,BL,BM,BN,BO,BQ,BR,BS,BT,BV,BW,BY,BZ,CA,CC,CD,CF,CG,CH,CI,CK,CL,CM,CN,CO,CR,CU,CV,CW,CX,CY,CZ,DE,DJ,DK,DM,DO,DZ,EC,EE,EG,EH,ER,ES,ET,FI,FJ,FK,FM,FO,FR,GA,GB,GD,GE,GF,GG,GH,GI,GL,GM,GN,GP,GQ,GR,GT,GU,GW,GY,HK,HM,HN,HR,HT,HU,ID,IE,IL,IM,IN,IO,IQ,IR,IS,IT,JE,JM,JO,JP,KE,KG,KH,KI,KM,KN,KP,KR,KW,KY,KZ,LA,LB,LC,LI,LK,LR,LS,LT,LU,LV,LY,MA,MC,MD,ME,MF,MG,MH,MK,ML,MM,MN,MO,MP,MQ,MR,MS,MT,MU,MV,MW,MX,MY,MZ,NA,NC,NE,NF,NG,NI,NL,NO,NP,NR,NU,NZ,OM,PA,PE,PF,PG,PH,PK,PL,PM,PN,PR,PS,PT,PW,PY,QA,RE,RO,RS,RU,RW,SA,SB,SC,SD,SE,SG,SH,SI,SJ,SK,SL,SM,SN,SO,SR,SS,ST,SV,SX,SY,SZ,TC,TD,TF,TG,TH,TJ,TL,TM,TN,TO,TR,TT,TV,TW,TZ,UA,UG,UM,US,UY,UZ,VA,VC,VE,VG,VI,VN,VU,WF,WS,YE,YT,ZA,ZM,ZW", currency = "BBD,BMD,BSD,CRC,GTQ,HNL,JMD,KYD,TTD,USD" }
+
+[pm_filters.worldline]
+giropay = { country = "DE", currency = "EUR" }
+ideal = { country = "NL", currency = "EUR" }
+credit = { country = "AD,AE,AF,AG,AI,AL,AM,AO,AQ,AR,AS,AT,AU,AW,AX,AZ,BA,BB,BD,BE,BF,BG,BH,BI,BJ,BL,BM,BN,BO,BQ,BR,BS,BT,BV,BW,BY,BZ,CA,CC,CD,CF,CG,CH,CI,CK,CL,CM,CN,CO,CR,CU,CV,CW,CX,CY,CZ,DE,DJ,DK,DM,DO,DZ,EC,EE,EG,EH,ER,ES,ET,FI,FJ,FK,FM,FO,FR,GA,GB,GD,GE,GF,GG,GH,GI,GL,GM,GN,GP,GQ,GR,GT,GU,GW,GY,HK,HM,HN,HR,HT,HU,ID,IE,IL,IM,IN,IO,IQ,IR,IS,IT,JE,JM,JO,JP,KE,KG,KH,KI,KM,KN,KP,KR,KW,KY,KZ,LA,LB,LC,LI,LK,LR,LS,LT,LU,LV,LY,MA,MC,MD,ME,MF,MG,MH,MK,ML,MM,MN,MO,MP,MQ,MR,MS,MT,MU,MV,MW,MX,MY,MZ,NA,NC,NE,NF,NG,NI,NL,NO,NP,NR,NU,NZ,OM,PA,PE,PF,PG,PH,PK,PL,PM,PN,PR,PS,PT,PW,PY,QA,RE,RO,RS,RU,RW,SA,SB,SC,SD,SE,SG,SH,SI,SJ,SK,SL,SM,SN,SO,SR,SS,ST,SV,SX,SY,SZ,TC,TD,TF,TG,TH,TJ,TL,TM,TN,TO,TR,TT,TV,TW,TZ,UA,UG,UM,US,UY,UZ,VA,VC,VE,VG,VI,VN,VU,WF,WS,YE,YT,ZA,ZM,ZW", currency = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BYN,BZD,CAD,CDF,CHF,CLP,CNY,COP,CRC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLL,SOS,SRD,SSP,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL" }
+debit = { country = "AD,AE,AF,AG,AI,AL,AM,AO,AQ,AR,AS,AT,AU,AW,AX,AZ,BA,BB,BD,BE,BF,BG,BH,BI,BJ,BL,BM,BN,BO,BQ,BR,BS,BT,BV,BW,BY,BZ,CA,CC,CD,CF,CG,CH,CI,CK,CL,CM,CN,CO,CR,CU,CV,CW,CX,CY,CZ,DE,DJ,DK,DM,DO,DZ,EC,EE,EG,EH,ER,ES,ET,FI,FJ,FK,FM,FO,FR,GA,GB,GD,GE,GF,GG,GH,GI,GL,GM,GN,GP,GQ,GR,GT,GU,GW,GY,HK,HM,HN,HR,HT,HU,ID,IE,IL,IM,IN,IO,IQ,IR,IS,IT,JE,JM,JO,JP,KE,KG,KH,KI,KM,KN,KP,KR,KW,KY,KZ,LA,LB,LC,LI,LK,LR,LS,LT,LU,LV,LY,MA,MC,MD,ME,MF,MG,MH,MK,ML,MM,MN,MO,MP,MQ,MR,MS,MT,MU,MV,MW,MX,MY,MZ,NA,NC,NE,NF,NG,NI,NL,NO,NP,NR,NU,NZ,OM,PA,PE,PF,PG,PH,PK,PL,PM,PN,PR,PS,PT,PW,PY,QA,RE,RO,RS,RU,RW,SA,SB,SC,SD,SE,SG,SH,SI,SJ,SK,SL,SM,SN,SO,SR,SS,ST,SV,SX,SY,SZ,TC,TD,TF,TG,TH,TJ,TL,TM,TN,TO,TR,TT,TV,TW,TZ,UA,UG,UM,US,UY,UZ,VA,VC,VE,VG,VI,VN,VU,WF,WS,YE,YT,ZA,ZM,ZW", currency = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BYN,BZD,CAD,CDF,CHF,CLP,CNY,COP,CRC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLL,SOS,SRD,SSP,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL" }
+
+[pm_filters.shift4]
+eps = { country = "AT", currency = "EUR" }
+giropay = { country = "DE", currency = "EUR" }
+ideal = { country = "NL", currency = "EUR" }
+sofort = { country = "AT,BE,CH,DE,ES,FI,FR,GB,IT,NL,PL,SE", currency = "CHF,EUR" }
+credit = { country = "AD,AE,AF,AG,AI,AL,AM,AO,AQ,AR,AS,AT,AU,AW,AX,AZ,BA,BB,BD,BE,BF,BG,BH,BI,BJ,BL,BM,BN,BO,BQ,BR,BS,BT,BV,BW,BY,BZ,CA,CC,CD,CF,CG,CH,CI,CK,CL,CM,CN,CO,CR,CU,CV,CW,CX,CY,CZ,DE,DJ,DK,DM,DO,DZ,EC,EE,EG,EH,ER,ES,ET,FI,FJ,FK,FM,FO,FR,GA,GB,GD,GE,GF,GG,GH,GI,GL,GM,GN,GP,GQ,GR,GT,GU,GW,GY,HK,HM,HN,HR,HT,HU,ID,IE,IL,IM,IN,IO,IQ,IR,IS,IT,JE,JM,JO,JP,KE,KG,KH,KI,KM,KN,KP,KR,KW,KY,KZ,LA,LB,LC,LI,LK,LR,LS,LT,LU,LV,LY,MA,MC,MD,ME,MF,MG,MH,MK,ML,MM,MN,MO,MP,MQ,MR,MS,MT,MU,MV,MW,MX,MY,MZ,NA,NC,NE,NF,NG,NI,NL,NO,NP,NR,NU,NZ,OM,PA,PE,PF,PG,PH,PK,PL,PM,PN,PR,PS,PT,PW,PY,QA,RE,RO,RS,RU,RW,SA,SB,SC,SD,SE,SG,SH,SI,SJ,SK,SL,SM,SN,SO,SR,SS,ST,SV,SX,SY,SZ,TC,TD,TF,TG,TH,TJ,TL,TM,TN,TO,TR,TT,TV,TW,TZ,UA,UG,UM,US,UY,UZ,VA,VC,VE,VG,VI,VN,VU,WF,WS,YE,YT,ZA,ZM,ZW", currency = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BYN,BZD,CAD,CDF,CHF,CLP,CNY,COP,CRC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLL,SOS,SRD,SSP,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL" }
+debit = { country = "AD,AE,AF,AG,AI,AL,AM,AO,AQ,AR,AS,AT,AU,AW,AX,AZ,BA,BB,BD,BE,BF,BG,BH,BI,BJ,BL,BM,BN,BO,BQ,BR,BS,BT,BV,BW,BY,BZ,CA,CC,CD,CF,CG,CH,CI,CK,CL,CM,CN,CO,CR,CU,CV,CW,CX,CY,CZ,DE,DJ,DK,DM,DO,DZ,EC,EE,EG,EH,ER,ES,ET,FI,FJ,FK,FM,FO,FR,GA,GB,GD,GE,GF,GG,GH,GI,GL,GM,GN,GP,GQ,GR,GT,GU,GW,GY,HK,HM,HN,HR,HT,HU,ID,IE,IL,IM,IN,IO,IQ,IR,IS,IT,JE,JM,JO,JP,KE,KG,KH,KI,KM,KN,KP,KR,KW,KY,KZ,LA,LB,LC,LI,LK,LR,LS,LT,LU,LV,LY,MA,MC,MD,ME,MF,MG,MH,MK,ML,MM,MN,MO,MP,MQ,MR,MS,MT,MU,MV,MW,MX,MY,MZ,NA,NC,NE,NF,NG,NI,NL,NO,NP,NR,NU,NZ,OM,PA,PE,PF,PG,PH,PK,PL,PM,PN,PR,PS,PT,PW,PY,QA,RE,RO,RS,RU,RW,SA,SB,SC,SD,SE,SG,SH,SI,SJ,SK,SL,SM,SN,SO,SR,SS,ST,SV,SX,SY,SZ,TC,TD,TF,TG,TH,TJ,TL,TM,TN,TO,TR,TT,TV,TW,TZ,UA,UG,UM,US,UY,UZ,VA,VC,VE,VG,VI,VN,VU,WF,WS,YE,YT,ZA,ZM,ZW", currency = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BYN,BZD,CAD,CDF,CHF,CLP,CNY,COP,CRC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLL,SOS,SRD,SSP,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL" }
+boleto = { country = "BR", currency = "BRL" }
+trustly = { currency = "CZK,DKK,EUR,GBP,NOK,SEK" }
+ali_pay = { country = "CN", currency = "CNY" }
+we_chat_pay = { country = "CN", currency = "CNY" }
+klarna = { currency = "EUR,GBP,CHF,SEK" }
+blik = { country = "PL", currency = "PLN" }
+crypto_currency = { currency = "USD,GBP,AED" }
+paysera = { currency = "EUR" }
+skrill = { currency = "USD" }
+
+[pm_filters.placetopay]
+credit = { country = "BE,CH,CO,CR,EC,HN,MX,PA,PR,UY", currency = "CLP,COP,USD"}
+debit = { country = "BE,CH,CO,CR,EC,HN,MX,PA,PR,UY", currency = "CLP,COP,USD"}
+
+[pm_filters.coingate]
+crypto_currency = { country = "AL, AD, AT, BE, BA, BG, HR, CZ, DK, EE, FI, FR, DE, GR, HU, IS, IE, IT, LV, LT, LU, MT, MD, NL, NO, PL, PT, RO, RS, SK, SI, ES, SE, CH, UA, GB, AR, BR, CL, CO, CR, DO, SV, GD, MX, PE, LC, AU, NZ, CY, HK, IN, IL, JP, KR, QA, SA, SG, EG", currency = "EUR, USD, GBP" }
+
+[pm_filters.paystack]
+eft = { country = "NG, ZA, GH, KE, CI", currency = "NGN, GHS, ZAR, KES, USD" }
+
+[pm_filters.santander]
+pix = { country = "BR", currency = "BRL" }
+boleto = { country = "BR", currency = "BRL" }
+
+[pm_filters.boku]
+dana = { country = "ID", currency = "IDR" }
+gcash = { country = "PH", currency = "PHP" }
+go_pay = { country = "ID", currency = "IDR" }
+kakao_pay = { country = "KR", currency = "KRW" }
+momo = { country = "VN", currency = "VND" }
+
+[pm_filters.nmi]
+credit = { country = "EG,ZA,BH,CY,HK,IN,ID,IL,JP,JO,KW,MY,PK,PH,SA,SG,KR,TW,TH,TR,AE,VN,AL,AD,AM,AT,AZ,BY,BE,BA,BG,HR,CZ,DK,EE,FI,FR,GE,DE,GR,HU,IS,IE,IT,KZ,LV,LI,LT,LU,MT,MD,MC,ME,NL,MK,NO,PL,PT,RO,SM,RS,SK,SI,ES,SE,CH,TR,GB,VA,AG,BS,BB,BZ,CA,SV,GT,HN,MX,PA,KN,LC,TT,US,AU,NZ,AR,BO,BR,CL,CO,EC,GY,PY,PE,SR,UY,VE", currency = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BYN,BZD,CAD,CDF,CHF,CLF,CLP,CNY,COP,CRC,CUC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLE,SLL,SOS,SRD,SSP,STD,STN,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL" }
+debit = { country = "EG,ZA,BH,CY,HK,IN,ID,IL,JP,JO,KW,MY,PK,PH,SA,SG,KR,TW,TH,TR,AE,VN,AL,AD,AM,AT,AZ,BY,BE,BA,BG,HR,CZ,DK,EE,FI,FR,GE,DE,GR,HU,IS,IE,IT,KZ,LV,LI,LT,LU,MT,MD,MC,ME,NL,MK,NO,PL,PT,RO,SM,RS,SK,SI,ES,SE,CH,TR,GB,VA,AG,BS,BB,BZ,CA,SV,GT,HN,MX,PA,KN,LC,TT,US,AU,NZ,AR,BO,BR,CL,CO,EC,GY,PY,PE,SR,UY,VE", currency = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BYN,BZD,CAD,CDF,CHF,CLF,CLP,CNY,COP,CRC,CUC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLE,SLL,SOS,SRD,SSP,STD,STN,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL" }
+apple_pay = { country = "EG,ZA,BH,CY,HK,IN,ID,IL,JP,JO,KW,MY,PK,PH,SA,SG,KR,TW,TH,TR,AE,VN,AL,AD,AM,AT,AZ,BY,BE,BA,BG,HR,CZ,DK,EE,FI,FR,GE,DE,GR,HU,IS,IE,IT,KZ,LV,LI,LT,LU,MT,MD,MC,ME,NL,MK,NO,PL,PT,RO,SM,RS,SK,SI,ES,SE,CH,TR,GB,VA,AG,BS,BB,BZ,CA,SV,GT,HN,MX,PA,KN,LC,TT,US,AU,NZ,AR,BO,BR,CL,CO,EC,GY,PY,PE,SR,UY,VE", currency = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BYN,BZD,CAD,CDF,CHF,CLF,CLP,CNY,COP,CRC,CUC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLE,SLL,SOS,SRD,SSP,STD,STN,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL" }
+google_pay = { country = "EG,ZA,BH,CY,HK,IN,ID,IL,JP,JO,KW,MY,PK,PH,SA,SG,KR,TW,TH,TR,AE,VN,AL,AD,AM,AT,AZ,BY,BE,BA,BG,HR,CZ,DK,EE,FI,FR,GE,DE,GR,HU,IS,IE,IT,KZ,LV,LI,LT,LU,MT,MD,MC,ME,NL,MK,NO,PL,PT,RO,SM,RS,SK,SI,ES,SE,CH,TR,GB,VA,AG,BS,BB,BZ,CA,SV,GT,HN,MX,PA,KN,LC,TT,US,AU,NZ,AR,BO,BR,CL,CO,EC,GY,PY,PE,SR,UY,VE", currency = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD,BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTN,BWP,BYN,BZD,CAD,CDF,CHF,CLF,CLP,CNY,COP,CRC,CUC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EGP,ERN,ETB,EUR,FJD,FKP,GBP,GEL,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK,HTG,HUF,IDR,ILS,INR,IQD,IRR,ISK,JMD,JOD,JPY,KES,KGS,KHR,KMF,KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT,MOP,MRU,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR,PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK,SGD,SHP,SLE,SLL,SOS,SRD,SSP,STD,STN,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY,TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VES,VND,VUV,WST,XAF,XCD,XOF,XPF,YER,ZAR,ZMW,ZWL" }
+
+[pm_filters.paypal]
+credit = { country = "DZ,AO,BJ,BW,BF,BI,CM,CV,TD,KM,CI,CD,DJ,EG,ER,ET,GA,GM,GN,GW,KE,LS,MG,MW,ML,MR,MU,MA,MZ,NA,NE,NG,CG,RW,SH,ST,SN,SC,SL,SO,ZA,SZ,TZ,TG,TN,UG,ZM,ZW,AI,AG,AR,AW,BS,BB,BZ,BM,BO,BR,VG,CA,KY,CL,CO,CR,DM,DO,EC,SV,FK,GL,GD,GT,GY,HN,JM,MX,MS,NI,PA,PY,PE,KN,LC,PM,VC,SR,TT,TC,US,UY,VE,AM,AU,BH,BT,BN,KH,CN,CK,FJ,PF,HK,IN,ID,IL,JP,JO,KZ,KI,KW,KG,LA,MY,MV,MH,FM,MN,NR,NP,NC,NZ,NU,NF,OM,PW,PG,PH,PN,QA,WS,SA,SG,SB,KR,LK,TW,TJ,TH,TO,TM,TV,AE,VU,VN,WF,YE,AL,AD,AT,AZ,BY,BE,BA,BG,HR,CY,CZ,DK,EE,FO,FI,FR,GE,DE,GR,HU,IS,IE,IT,LV,LI,LT,LU,MK,MT,MD,MC,ME,NL,NO,PL,PT,RO,RU,SM,RS,SK,SI,ES,SJ,SE,CH,UA,GB,VA", currency = "AUD,BRL,CAD,CNY,CZK,DKK,EUR,HKD,HUF,ILS,JPY,MYR,MXN,TWD,NZD,NOK,PHP,PLN,GBP,SGD,SEK,CHF,THB,USD" }
+debit = { country = "DZ,AO,BJ,BW,BF,BI,CM,CV,TD,KM,CI,CD,DJ,EG,ER,ET,GA,GM,GN,GW,KE,LS,MG,MW,ML,MR,MU,MA,MZ,NA,NE,NG,CG,RW,SH,ST,SN,SC,SL,SO,ZA,SZ,TZ,TG,TN,UG,ZM,ZW,AI,AG,AR,AW,BS,BB,BZ,BM,BO,BR,VG,CA,KY,CL,CO,CR,DM,DO,EC,SV,FK,GL,GD,GT,GY,HN,JM,MX,MS,NI,PA,PY,PE,KN,LC,PM,VC,SR,TT,TC,US,UY,VE,AM,AU,BH,BT,BN,KH,CN,CK,FJ,PF,HK,IN,ID,IL,JP,JO,KZ,KI,KW,KG,LA,MY,MV,MH,FM,MN,NR,NP,NC,NZ,NU,NF,OM,PW,PG,PH,PN,QA,WS,SA,SG,SB,KR,LK,TW,TJ,TH,TO,TM,TV,AE,VU,VN,WF,YE,AL,AD,AT,AZ,BY,BE,BA,BG,HR,CY,CZ,DK,EE,FO,FI,FR,GE,DE,GR,HU,IS,IE,IT,LV,LI,LT,LU,MK,MT,MD,MC,ME,NL,NO,PL,PT,RO,RU,SM,RS,SK,SI,ES,SJ,SE,CH,UA,GB,VA", currency = "AUD,BRL,CAD,CNY,CZK,DKK,EUR,HKD,HUF,ILS,JPY,MYR,MXN,TWD,NZD,NOK,PHP,PLN,GBP,SGD,SEK,CHF,THB,USD" }
+paypal = { country = "DZ,AO,BJ,BW,BF,BI,CM,CV,TD,KM,CI,CD,DJ,EG,ER,ET,GA,GM,GN,GW,KE,LS,MG,MW,ML,MR,MU,MA,MZ,NA,NE,NG,CG,RW,SH,ST,SN,SC,SL,SO,ZA,SZ,TZ,TG,TN,UG,ZM,ZW,AI,AG,AR,AW,BS,BB,BZ,BM,BO,BR,VG,CA,KY,CL,CO,CR,DM,DO,EC,SV,FK,GL,GD,GT,GY,HN,JM,MX,MS,NI,PA,PY,PE,KN,LC,PM,VC,SR,TT,TC,US,UY,VE,AM,AU,BH,BT,BN,KH,CN,CK,FJ,PF,HK,IN,ID,IL,JP,JO,KZ,KI,KW,KG,LA,MY,MV,MH,FM,MN,NR,NP,NC,NZ,NU,NF,OM,PW,PG,PH,PN,QA,WS,SA,SG,SB,KR,LK,TW,TJ,TH,TO,TM,TV,AE,VU,VN,WF,YE,AL,AD,AT,AZ,BY,BE,BA,BG,HR,CY,CZ,DK,EE,FO,FI,FR,GE,DE,GR,HU,IS,IE,IT,LV,LI,LT,LU,MK,MT,MD,MC,ME,NL,NO,PL,PT,RO,RU,SM,RS,SK,SI,ES,SJ,SE,CH,UA,GB,VA", currency = "AUD,BRL,CAD,CNY,CZK,DKK,EUR,HKD,HUF,ILS,JPY,MYR,MXN,TWD,NZD,NOK,PHP,PLN,GBP,SGD,SEK,CHF,THB,USD" }
+eps = { country = "DZ,AO,BJ,BW,BF,BI,CM,CV,TD,KM,CI,CD,DJ,EG,ER,ET,GA,GM,GN,GW,KE,LS,MG,MW,ML,MR,MU,MA,MZ,NA,NE,NG,CG,RW,SH,ST,SN,SC,SL,SO,ZA,SZ,TZ,TG,TN,UG,ZM,ZW,AI,AG,AR,AW,BS,BB,BZ,BM,BO,BR,VG,CA,KY,CL,CO,CR,DM,DO,EC,SV,FK,GL,GD,GT,GY,HN,JM,MX,MS,NI,PA,PY,PE,KN,LC,PM,VC,SR,TT,TC,US,UY,VE,AM,AU,BH,BT,BN,KH,CN,CK,FJ,PF,HK,IN,ID,IL,JP,JO,KZ,KI,KW,KG,LA,MY,MV,MH,FM,MN,NR,NP,NC,NZ,NU,NF,OM,PW,PG,PH,PN,QA,WS,SA,SG,SB,KR,LK,TW,TJ,TH,TO,TM,TV,AE,VU,VN,WF,YE,AL,AD,AT,AZ,BY,BE,BA,BG,HR,CY,CZ,DK,EE,FO,FI,FR,GE,DE,GR,HU,IS,IE,IT,LV,LI,LT,LU,MK,MT,MD,MC,ME,NL,NO,PL,PT,RO,RU,SM,RS,SK,SI,ES,SJ,SE,CH,UA,GB,VA", currency = "AUD,BRL,CAD,CNY,CZK,DKK,EUR,HKD,HUF,ILS,JPY,MYR,MXN,TWD,NZD,NOK,PHP,PLN,GBP,SGD,SEK,CHF,THB,USD" }
+giropay = { currency = "EUR" }
+ideal = { currency = "EUR" }
+sofort = { country = "DZ,AO,BJ,BW,BF,BI,CM,CV,TD,KM,CI,CD,DJ,EG,ER,ET,GA,GM,GN,GW,KE,LS,MG,MW,ML,MR,MU,MA,MZ,NA,NE,NG,CG,RW,SH,ST,SN,SC,SL,SO,ZA,SZ,TZ,TG,TN,UG,ZM,ZW,AI,AG,AR,AW,BS,BB,BZ,BM,BO,BR,VG,CA,KY,CL,CO,CR,DM,DO,EC,SV,FK,GL,GD,GT,GY,HN,JM,MX,MS,NI,PA,PY,PE,KN,LC,PM,VC,SR,TT,TC,US,UY,VE,AM,AU,BH,BT,BN,KH,CN,CK,FJ,PF,HK,IN,ID,IL,JP,JO,KZ,KI,KW,KG,LA,MY,MV,MH,FM,MN,NR,NP,NC,NZ,NU,NF,OM,PW,PG,PH,PN,QA,WS,SA,SG,SB,KR,LK,TW,TJ,TH,TO,TM,TV,AE,VU,VN,WF,YE,AL,AD,AT,AZ,BY,BE,BA,BG,HR,CY,CZ,DK,EE,FO,FI,FR,GE,DE,GR,HU,IS,IE,IT,LV,LI,LT,LU,MK,MT,MD,MC,ME,NL,NO,PL,PT,RO,RU,SM,RS,SK,SI,ES,SJ,SE,CH,UA,GB,VA", currency = "AUD,BRL,CAD,CNY,CZK,DKK,EUR,HKD,HUF,ILS,JPY,MYR,MXN,TWD,NZD,NOK,PHP,PLN,GBP,SGD,SEK,CHF,THB,USD" }
+
+[pm_filters.datatrans]
+credit = { country = "AL,AD,AM,AT,AZ,BY,BE,BA,BG,CH,CY,CZ,DE,DK,EE,ES,FI,FR,GB,GE,GR,HR,HU,IE,IS,IT,KZ,LI,LT,LU,LV,MC,MD,ME,MK,MT,NL,NO,PL,PT,RO,RU,SE,SI,SK,SM,TR,UA,VA", currency = "BHD,BIF,CHF,DJF,EUR,GBP,GNF,IQD,ISK,JPY,JOD,KMF,KRW,KWD,LYD,OMR,PYG,RWF,TND,UGX,USD,VND,VUV,XAF,XOF,XPF" }
+debit = { country = "AL,AD,AM,AT,AZ,BY,BE,BA,BG,CH,CY,CZ,DE,DK,EE,ES,FI,FR,GB,GE,GR,HR,HU,IE,IS,IT,KZ,LI,LT,LU,LV,MC,MD,ME,MK,MT,NL,NO,PL,PT,RO,RU,SE,SI,SK,SM,TR,UA,VA", currency = "BHD,BIF,CHF,DJF,EUR,GBP,GNF,IQD,ISK,JPY,JOD,KMF,KRW,KWD,LYD,OMR,PYG,RWF,TND,UGX,USD,VND,VUV,XAF,XOF,XPF" }
+
+[pm_filters.payme]
+credit = { country = "US,CA,IL,GB", currency = "ILS,USD,EUR" }
+debit = { country = "US,CA,IL,GB", currency = "ILS,USD,EUR" }
+apple_pay = { country = "US,CA,IL,GB", currency = "ILS,USD,EUR" }
+
+[pm_filters.paysafe]
+apple_pay = {country = "AF,AX,AL,DZ,AS,AD,AO,AI,AQ,AG,AR,AM,AW,AU,AT,AZ,BS,BH,BD,BB,BY,BE,BZ,BJ,BM,BT,BO,BQ,BA,BW,BV,BR,IO,BN,BG,BF,BI,KH,CM,CA,CV,KY,CF,TD,CL,CN,CX,CC,CO,KM,CG,CD,CK,CR,CI,HR,CU,CW,CY,CZ,DK,DJ,DM,DO,EC,EG,SV,GQ,ER,EE,ET,FK,FO,FJ,FI,FR,GF,PF,TF,GA,GM,GE,DE,GH,GI,GR,GL,GD,GP,GU,GT,GG,GN,GW,GY,HT,HM,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IM,IL,IT,JM,JP,JE,JO,KZ,KE,KI,KP,KR,KW,KG,LA,LV,LB,LS,LR,LY,LI,LT,LU,MO,MK,MG,MW,MY,MV,ML,MT,MH,MQ,MR,MU,YT,MX,FM,MD,MC,MN,ME,MS,MA,MZ,MM,NA,NR,NP,NC,NZ,NI,NE,NG,NU,NF,MP,NO,OM,PK,PW,PS,PA,PG,PY,PE,PH,PN,PL,PT,PR,QA,RE,RO,RU,RW,BL,SH,KN,LC,MF,VC,WS,SM,ST,SA,SN,RS,SC,SL,SG,SX,SK,SI,SB,SO,ZA,GS,SS,ES,LK,PM,SD,SR,SJ,SZ,SE,CH,SY,TW,TJ,TZ,TH,NL,TL,TG,TK,TO,TT,TN,TR,TM,TC,TV,UG,UA,AE,GB,US,UM,UY,UZ,VU,VA,VE,VN,VG,VI,WF,EH,YE,ZM,ZW", currency = "ARS,AUD,AZN,BHD,BOB,BAM,BRL,BGN,CAD,CLP,CNY,COP,CRC,HRK,CZK,DKK,DOP,XCD,EGP,ETB,EUR,FJD,GEL,GTQ,HTG,HNL,HKD,HUF,INR,IDR,JMD,JPY,JOD,KZT,KES,KRW,KWD,LBP,LYD,MWK,MUR,MXN,MDL,MAD,ILS,NZD,NGN,NOK,OMR,PKR,PAB,PYG,PEN,PHP,PLN,GBP,QAR,RON,RUB,RWF,SAR,RSD,SGD,ZAR,LKR,SEK,CHF,SYP,TWD,THB,TTD,TND,TRY,UAH,AED,UYU,USD,VND" }
+
+[pm_filters.payjustnow]
+payjustnow = { country = "ZA", currency = "ZAR" }
+
+[pm_filters.payjustnowinstore]
+payjustnow = { country = "ZA", currency = "ZAR" }
diff --git a/config/grafana-datasource.yaml b/config/grafana-datasource.yaml
new file mode 100644
index 00000000..fbed2ef2
--- /dev/null
+++ b/config/grafana-datasource.yaml
@@ -0,0 +1,8 @@
+apiVersion: 1
+
+datasources:
+ - name: Metrics
+ type: prometheus
+ access: proxy
+ url: http://prometheus:9090/
+ editable: true
diff --git a/config/prometheus.yaml b/config/prometheus.yaml
new file mode 100644
index 00000000..587b77c7
--- /dev/null
+++ b/config/prometheus.yaml
@@ -0,0 +1,30 @@
+# my global config
+global:
+ scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
+ evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
+ # scrape_timeout is set to the global default (10s).
+
+# alter manager if required
+# Alertmanager configuration
+# alerting:
+# alertmanagers:
+# - static_configs:
+# - targets:
+# - alertmanager:9093
+
+# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
+rule_files:
+ # - "first_rules.yml"
+ # - "second_rules.yml"
+
+# A scrape configuration containing exactly one endpoint to scrape:
+# Here it's Prometheus itself.
+scrape_configs:
+ # The job name is added as a label `job=` to any timeseries scraped from this config.
+ - job_name: "open-router"
+
+ metrics_path: /metrics
+ # scheme defaults to 'http'.
+
+ static_configs:
+ - targets: ["open-router-pg:9094"] # this can be replaced by open-router-local-pg for local setup
diff --git a/cypress.config.js b/cypress.config.js
new file mode 100644
index 00000000..5d7ee8dc
--- /dev/null
+++ b/cypress.config.js
@@ -0,0 +1,53 @@
+const { defineConfig } = require('cypress')
+
+module.exports = defineConfig({
+ e2e: {
+ baseUrl: 'http://localhost:8080',
+ supportFile: 'cypress/support/e2e.js',
+ specPattern: 'cypress/e2e/**/*.cy.{js,jsx,ts,tsx}',
+ viewportWidth: 1280,
+ viewportHeight: 720,
+ video: false,
+ screenshotOnRunFailure: true,
+ defaultCommandTimeout: 10000,
+ requestTimeout: 10000,
+ responseTimeout: 10000,
+ env: {
+ // Default configuration - can be overridden via environment variables
+ API_BASE_URL: 'http://localhost:8080',
+ DEFAULT_MERCHANT_ID_PREFIX: 'merc_',
+ DEFAULT_PAYMENT_ID_PREFIX: 'PAY_',
+ DEFAULT_CUSTOMER_ID_PREFIX: 'CUST',
+ // Test data configuration
+ DEFAULT_GATEWAYS: ['GatewayA', 'GatewayB', 'GatewayC'],
+ DEFAULT_AMOUNT: 100.50,
+ DEFAULT_CURRENCY: 'USD',
+ // Routing algorithm types
+ ROUTING_ALGORITHMS: {
+ SUCCESS_RATE: 'SR_BASED_ROUTING',
+ PAYMENT_LATENCY: 'PL_BASED_ROUTING',
+ COST_BASED: 'COST_BASED_ROUTING'
+ },
+ // Payment method types for testing
+ PAYMENT_METHODS: {
+ UPI: {
+ type: 'UPI',
+ method: 'UPI_PAY'
+ },
+ UPI_COLLECT: {
+ type: 'upi',
+ method: 'upi_collect'
+ },
+ CARD: {
+ type: 'CARD',
+ method: 'CARD_PAY'
+ }
+ }
+ },
+ setupNodeEvents(on, config) {
+ // implement node event listeners here
+ require('@cypress/grep/src/plugin')(config)
+ return config
+ },
+ },
+})
diff --git a/cypress/README.md b/cypress/README.md
new file mode 100644
index 00000000..da51a9ac
--- /dev/null
+++ b/cypress/README.md
@@ -0,0 +1,318 @@
+# Decision Engine Cypress Testing Framework
+
+This directory contains comprehensive end-to-end tests for the Decision Engine routing flows using Cypress. The testing framework is designed to be generic and easily extensible for testing different routing algorithms and scenarios.
+
+## 📁 Directory Structure
+
+```
+cypress/
+├── e2e/
+│ └── routing-flows/
+│ ├── gateway-latency-scoring.cy.js # Gateway latency scoring tests
+│ ├── success-rate-routing.cy.js # Success rate routing tests
+├── support/
+│ ├── commands.js # Custom Cypress commands
+│ ├── e2e.js # Global test configuration
+│ └── test-data-factory.js # Test data generation utilities
+└── README.md # This file
+```
+
+## 🚀 Getting Started
+
+### Prerequisites
+
+1. **Node.js** (v16 or higher)
+2. **Decision Engine Service** running on `http://localhost:8082`
+3. **Database** (MySQL/PostgreSQL) properly configured
+4. **Redis** instance running
+
+### Installation
+
+1. Install dependencies:
+```bash
+npm install
+```
+
+2. Verify Cypress installation:
+```bash
+npx cypress verify
+```
+
+### Running Tests
+
+#### Interactive Mode (Cypress Test Runner)
+```bash
+npm run cypress:open
+```
+
+#### Headless Mode (CI/CD)
+```bash
+npm run cypress:run
+```
+
+#### Specific Test Suites
+```bash
+# Gateway latency scoring tests
+npm run test:gateway-latency
+
+# Success rate routing tests
+npm run test:success-rate
+
+# All routing flow tests
+npm run test
+```
+
+#### Running Tests with Tags
+```bash
+# Run only smoke tests
+npx cypress run --env grepTags="@smoke"
+
+# Run only gateway latency tests
+npx cypress run --env grepTags="@gateway-latency"
+
+# Run performance tests
+npx cypress run --env grepTags="@performance"
+```
+
+## 🛠️ Custom Commands
+
+The framework provides several custom Cypress commands for easy test creation:
+
+### Merchant Management
+```javascript
+cy.createMerchantAccount(merchantId)
+```
+
+### Rule Configuration
+```javascript
+cy.createRoutingRule(merchantId, ruleConfig)
+cy.createSuccessRateRule(merchantId, options)
+cy.createPaymentLatencyRule(merchantId, options)
+```
+
+### Gateway Operations
+```javascript
+cy.decideGateway(decisionRequest)
+cy.updateGatewayScore(scoreUpdate)
+```
+
+### Complete Flows
+```javascript
+cy.completeGatewayLatencyFlow(options)
+```
+
+### Utility Commands
+```javascript
+cy.waitForService()
+cy.cleanupTestData(merchantId)
+```
+
+## 📊 Test Data Factory
+
+The `TestDataFactory` class provides utilities for generating test data:
+
+```javascript
+const TestDataFactory = require('../support/test-data-factory')
+
+// Generate unique IDs
+const merchantId = TestDataFactory.generateMerchantId()
+const paymentId = TestDataFactory.generatePaymentId()
+
+// Get rule configurations
+const srRule = TestDataFactory.getSuccessRateRuleConfig({
+ successRate: 0.8,
+ latencyThreshold: 100
+})
+
+// Get test scenarios
+const latencyScenarios = TestDataFactory.getLatencyTestScenarios()
+const paymentMethods = TestDataFactory.getPaymentMethodTestCases()
+```
+
+## ⚙️ Configuration
+
+### Environment Variables
+
+Configure the testing environment in `cypress.config.js`:
+
+```javascript
+env: {
+ API_BASE_URL: 'http://localhost:8082',
+ DEFAULT_GATEWAYS: ['GatewayA', 'GatewayB', 'GatewayC'],
+ DEFAULT_AMOUNT: 100.50,
+ DEFAULT_CURRENCY: 'USD'
+}
+```
+
+### Override via Command Line
+```bash
+npx cypress run --env API_BASE_URL=http://localhost:8080
+```
+
+## 🏷️ Test Tags
+
+Tests are organized using tags for easy filtering:
+
+- `@smoke` - Critical path tests
+- `@gateway-latency` - Gateway latency specific tests
+- `@success-rate` - Success rate routing tests
+- `@payment-latency` - Payment latency routing tests
+- `@performance` - Performance related tests
+- `@edge-cases` - Edge case scenarios
+- `@routing` - General routing tests
+
+## 📝 Writing New Tests
+
+### 1. Basic Test Structure
+
+```javascript
+describe('New Routing Flow', () => {
+ let testData = {}
+
+ beforeEach(() => {
+ cy.waitForService()
+ testData = {
+ merchantId: `merc_new_${Date.now()}`,
+ paymentId: `PAY_new_${Date.now()}`
+ }
+ })
+
+ afterEach(() => {
+ cy.cleanupTestData(testData.merchantId)
+ })
+
+ it('should test new routing logic', { tags: ['@new-feature'] }, () => {
+ // Test implementation
+ })
+})
+```
+
+### 2. Using Test Data Factory
+
+```javascript
+const TestDataFactory = require('../support/test-data-factory')
+
+it('should test with generated data', () => {
+ const merchantId = TestDataFactory.generateMerchantId()
+ const ruleConfig = TestDataFactory.getSuccessRateRuleConfig({
+ successRate: 0.9
+ })
+
+ cy.createMerchantAccount(merchantId)
+ .then(() => cy.createRoutingRule(merchantId, ruleConfig))
+ .then(() => {
+ // Continue test
+ })
+})
+```
+
+### 3. Adding New Custom Commands
+
+In `cypress/support/commands.js`:
+
+```javascript
+Cypress.Commands.add('newCustomCommand', (parameters) => {
+ return cy.request({
+ method: 'POST',
+ url: `${getApiBaseUrl()}/new-endpoint`,
+ body: parameters
+ }).then((response) => {
+ expect(response.status).to.eq(200)
+ return cy.wrap(response.body)
+ })
+})
+```
+
+## 🔧 Extending for New Routing Logic
+
+To add tests for a new routing algorithm:
+
+### 1. Create New Test File
+```bash
+touch cypress/e2e/routing-flows/new-algorithm-routing.cy.js
+```
+
+### 2. Add Rule Configuration Helper
+In `cypress/support/commands.js`:
+```javascript
+Cypress.Commands.add('createNewAlgorithmRule', (merchantId, options = {}) => {
+ const ruleConfig = {
+ type: "newAlgorithm",
+ data: {
+ // Algorithm specific configuration
+ }
+ }
+ return cy.createRoutingRule(merchantId, ruleConfig)
+})
+```
+
+### 3. Add Test Data Factory Methods
+In `cypress/support/test-data-factory.js`:
+```javascript
+static getNewAlgorithmRuleConfig(options = {}) {
+ return {
+ type: "newAlgorithm",
+ data: {
+ // Default configuration
+ }
+ }
+}
+```
+
+### 4. Update Package.json Scripts
+```json
+{
+ "scripts": {
+ "test:new-algorithm": "cypress run --spec 'cypress/e2e/routing-flows/new-algorithm-routing.cy.js'"
+ }
+}
+```
+
+## 🐛 Debugging
+
+### 1. Enable Debug Logs
+```bash
+DEBUG=cypress:* npm run cypress:run
+```
+
+### 2. Screenshots and Videos
+- Screenshots are automatically taken on test failures
+- Videos can be enabled in `cypress.config.js`
+
+### 3. Browser DevTools
+When running in interactive mode, use browser DevTools to inspect network requests and responses.
+
+## 📈 Performance Testing
+
+The framework includes utilities for performance testing:
+
+```javascript
+const performanceConfig = TestDataFactory.getPerformanceTestConfig()
+const loadTestData = TestDataFactory.generateLoadTestData(100)
+
+// Use in tests for load testing scenarios
+```
+
+## 🚨 Best Practices
+
+1. **Use unique test data** - Always generate unique merchant IDs and payment IDs
+2. **Clean up after tests** - Use `afterEach` hooks to clean up test data
+3. **Wait for service readiness** - Always call `cy.waitForService()` in `beforeEach`
+4. **Use descriptive test names** - Make test purposes clear from the name
+5. **Tag tests appropriately** - Use tags for easy test filtering
+6. **Verify responses** - Always validate API response structure and data
+7. **Log important data** - Use `cy.log()` for debugging information
+
+## 🤝 Contributing
+
+When adding new tests:
+
+1. Follow the existing file structure and naming conventions
+2. Add appropriate tags to new tests
+3. Update this README if adding new features
+4. Ensure tests are independent and can run in any order
+5. Add test data factory methods for reusable test data
+
+---
+
+**Happy Testing! 🎉**
diff --git a/cypress/e2e/routing-flows/gateway-latency-scoring.cy.js b/cypress/e2e/routing-flows/gateway-latency-scoring.cy.js
new file mode 100644
index 00000000..c2bb36da
--- /dev/null
+++ b/cypress/e2e/routing-flows/gateway-latency-scoring.cy.js
@@ -0,0 +1,224 @@
+describe('Gateway Latency Scoring Flow', () => {
+ let testData = {}
+
+ beforeEach(() => {
+ // Wait for service to be ready
+ cy.waitForService()
+
+ // Generate unique test data for each test
+ testData = {
+ merchantId: `merc_${Date.now()}`,
+ paymentId: `PAY_${Date.now()}`,
+ customerId: `CUST${Date.now()}`
+ }
+ })
+
+ afterEach(() => {
+ // Clean up test data if needed
+ cy.cleanupTestData(testData.merchantId)
+ })
+
+ it('should create merchant account successfully', { tags: ['@merchant'] }, () => {
+ cy.createMerchantAccount(testData.merchantId).then((result) => {
+ expect(result.merchantId).to.equal(testData.merchantId)
+ expect(result.response).to.exist
+ })
+ })
+
+ it('should create success rate routing rule successfully', { tags: ['@routing-rule'] }, () => {
+ cy.createMerchantAccount(testData.merchantId).then(() => {
+ return cy.createSuccessRateRule(testData.merchantId, {
+ latencyThreshold: 90,
+ successRate: 0.5,
+ bucketSize: 200,
+ hedgingPercent: 5,
+ gatewayLatency: 5000
+ })
+ }).then((result) => {
+ expect(result.ruleConfig).to.have.property('type', 'successRate')
+ expect(result.ruleConfig.data).to.have.property('defaultLatencyThreshold', 90)
+ expect(result.ruleConfig.data).to.have.property('defaultSuccessRate', 0.5)
+ expect(result.response).to.exist
+ })
+ })
+
+ it('should decide gateway successfully', { tags: ['@gateway-decision'] }, () => {
+ cy.createMerchantAccount(testData.merchantId).then(() => {
+ return cy.createSuccessRateRule(testData.merchantId)
+ }).then(() => {
+ return cy.decideGateway({
+ merchantId: testData.merchantId,
+ eligibleGatewayList: ["GatewayA", "GatewayB", "GatewayC"],
+ rankingAlgorithm: "SR_BASED_ROUTING",
+ eliminationEnabled: true,
+ paymentInfo: {
+ paymentId: testData.paymentId,
+ amount: 100.50,
+ currency: "USD",
+ customerId: testData.customerId,
+ paymentMethodType: "UPI",
+ paymentMethod: "UPI_PAY"
+ }
+ })
+ }).then((result) => {
+ expect(result.response).to.haveValidGatewayResponse()
+ expect(result.response.decided_gateway).to.be.oneOf(["GatewayA", "GatewayB", "GatewayC"])
+ })
+ })
+
+ it('should update gateway score successfully', { tags: ['@score-update'] }, () => {
+ let selectedGateway
+
+ cy.createMerchantAccount(testData.merchantId).then(() => {
+ return cy.createSuccessRateRule(testData.merchantId)
+ }).then(() => {
+ return cy.decideGateway({
+ merchantId: testData.merchantId,
+ paymentInfo: {
+ paymentId: testData.paymentId
+ }
+ })
+ }).then((result) => {
+ selectedGateway = result.response.decided_gateway
+ return cy.updateGatewayScore({
+ merchantId: testData.merchantId,
+ gateway: selectedGateway,
+ paymentId: testData.paymentId,
+ status: "AUTHORIZED",
+ txnLatency: {
+ gatewayLatency: 6000
+ }
+ })
+ }).then((result) => {
+ expect(result.response).to.haveValidScoreUpdate()
+ })
+ })
+
+ it('should show different gateway selection after score update', { tags: ['@score-impact'] }, () => {
+ let initialGateway, updatedGateway, initialGatewayScore, initialGatewayCurrentScore
+
+ cy.createMerchantAccount(testData.merchantId).then(() => {
+ return cy.createEliminationRule(testData.merchantId, {
+ gatewayLatency: 3000 // Lower threshold to make latency impact more visible
+ })
+ }).then(() => {
+ // First gateway decision
+ return cy.decideGateway({
+ merchantId: testData.merchantId,
+ paymentInfo: {
+ paymentId: testData.paymentId
+ }
+ })
+ }).then((result) => {
+ initialGateway = result.response.decided_gateway
+ initialGatewayScore = result.response.gateway_priority_map[initialGateway]
+
+ // Update score with high latency
+ return cy.updateGatewayScore({
+ merchantId: testData.merchantId,
+ gateway: initialGateway,
+ paymentId: testData.paymentId,
+ status: "AUTHORIZED",
+ txnLatency: {
+ gatewayLatency: 8000 // High latency to impact scoring
+ }
+ })
+ }).then(() => {
+ // Second gateway decision to see if scoring changed
+ return cy.decideGateway({
+ merchantId: testData.merchantId,
+ eliminationEnabled: true,
+ paymentInfo: {
+ paymentId: `PAY_${Date.now()}_2` // Different payment ID
+ }
+ })
+ }).then((result) => {
+ initialGatewayCurrentScore = result.response.gateway_priority_map[initialGateway]
+ updatedGateway = result.response.decided_gateway
+
+ // Log both gateways for comparison
+ cy.log(`Initial Gateway: ${initialGateway}`)
+ cy.log(`Updated Gateway: ${updatedGateway}`)
+
+ expect(updatedGateway).to.not.equal(initialGateway);
+ expect(initialGatewayCurrentScore).to.be.lessThan(initialGatewayScore);
+ })
+ })
+
+ it('should handle different payment methods', { tags: ['@payment-methods'] }, () => {
+ const paymentMethods = [
+ { type: "UPI", method: "UPI_PAY" },
+ { type: "upi", method: "upi_collect" },
+ { type: "CARD", method: "CARD_PAY" }
+ ]
+
+ cy.createMerchantAccount(testData.merchantId).then(() => {
+ return cy.createSuccessRateRule(testData.merchantId)
+ }).then(() => {
+ // Test each payment method
+ paymentMethods.forEach((paymentMethod, index) => {
+ cy.decideGateway({
+ merchantId: testData.merchantId,
+ paymentInfo: {
+ paymentId: `${testData.paymentId}_${index}`,
+ paymentMethodType: paymentMethod.type,
+ paymentMethod: paymentMethod.method
+ }
+ }).then((result) => {
+ expect(result.response).to.haveValidGatewayResponse()
+ cy.log(`Payment Method ${paymentMethod.type}/${paymentMethod.method}: Gateway ${result.response.decided_gateway}`)
+ })
+ })
+ })
+ })
+
+ it('legacy api: should show different gateway selection after score update', { tags: ['@score-impact'] }, () => {
+ let initialGateway, updatedGateway, initialGatewayScore, initialGatewayCurrentScore
+
+ cy.createMerchantAccount(testData.merchantId).then(() => {
+ return cy.createSuccessRateRule(testData.merchantId, {
+ gatewayLatency: 3000 // Lower threshold to make latency impact more visible
+ })
+ }).then(() => {
+ // First gateway decision
+ return cy.decideGatewayLegacy({
+ merchantId: testData.merchantId,
+ paymentInfo: {
+ paymentId: testData.paymentId
+ }
+ })
+ }).then((result) => {
+ initialGateway = result.response.decided_gateway
+ initialGatewayScore = result.response.gateway_priority_map[initialGateway]
+
+ // Update score with high latency
+ return cy.updateGatewayScore({
+ merchantId: testData.merchantId,
+ gateway: initialGateway,
+ paymentId: testData.paymentId,
+ status: "AUTHORIZED",
+ txnLatency: {
+ gatewayLatency: 8000 // High latency to impact scoring
+ }
+ })
+ }).then(() => {
+ // Second gateway decision to see if scoring changed
+ return cy.decideGateway({
+ merchantId: testData.merchantId,
+ paymentInfo: {
+ paymentId: `PAY_${Date.now()}_2` // Different payment ID
+ }
+ })
+ }).then((result) => {
+ initialGatewayCurrentScore = result.response.gateway_priority_map[initialGateway]
+ updatedGateway = result.response.decided_gateway
+
+ // Log both gateways for comparison
+ cy.log(`Initial Gateway: ${initialGateway}`)
+ cy.log(`Updated Gateway: ${updatedGateway}`)
+
+ expect(updatedGateway).to.not.equal(initialGateway);
+ expect(initialGatewayCurrentScore).to.be.lessThan(initialGatewayScore);
+ })
+ })
+})
diff --git a/cypress/e2e/routing-flows/success-rate-routing.cy.js b/cypress/e2e/routing-flows/success-rate-routing.cy.js
new file mode 100644
index 00000000..837bc698
--- /dev/null
+++ b/cypress/e2e/routing-flows/success-rate-routing.cy.js
@@ -0,0 +1,244 @@
+describe('Success Rate Routing Flow', () => {
+ let testData = {}
+
+ beforeEach(() => {
+ cy.waitForService()
+
+ testData = {
+ merchantId: `merc_sr_${Date.now()}`,
+ paymentId: `PAY_SR_${Date.now()}`,
+ customerId: `CUST_SR_${Date.now()}`
+ }
+ })
+
+ afterEach(() => {
+ cy.cleanupTestData(testData.merchantId)
+ })
+
+ it('should test success rate based routing', { tags: ['@success-rate', '@routing'] }, () => {
+ cy.createMerchantAccount(testData.merchantId).then(() => {
+ return cy.createSuccessRateRule(testData.merchantId, {
+ successRate: 0.8,
+ latencyThreshold: 100,
+ bucketSize: 300,
+ hedgingPercent: 10
+ })
+ }).then(() => {
+ // Define multiple transactions to simulate real-world scenario
+ const transactions = [
+ { paymentId: `${testData.paymentId}_txn_1`, status: "AUTHORIZED", latency: 2000 },
+ { paymentId: `${testData.paymentId}_txn_2`, status: "FAILURE", latency: 5000 },
+ { paymentId: `${testData.paymentId}_txn_3`, status: "AUTHORIZED", latency: 1500 },
+ { paymentId: `${testData.paymentId}_txn_4`, status: "AUTHORIZED", latency: 3000 },
+ { paymentId: `${testData.paymentId}_txn_5`, status: "FAILURE", latency: 4500 },
+ { paymentId: `${testData.paymentId}_txn_6`, status: "AUTHORIZED", latency: 2500 }
+ ]
+
+ // Store gateway decisions for each transaction
+ const gatewayDecisions = []
+
+ // Process each transaction: decide gateway first, then update score
+ const processTransaction = (txn, index) => {
+ return cy.decideGateway({
+ merchantId: testData.merchantId,
+ rankingAlgorithm: "SR_BASED_ROUTING",
+ paymentInfo: {
+ paymentId: txn.paymentId,
+ paymentMethodType: "UPI",
+ paymentMethod: "UPI_PAY",
+ customerId: `${testData.customerId}_${index}`
+ }
+ }).then((decisionResult) => {
+ expect(decisionResult.response).to.haveValidGatewayResponse()
+
+ // Store the gateway decision
+ gatewayDecisions.push({
+ paymentId: txn.paymentId,
+ gateway: decisionResult.response.decided_gateway,
+ gateway_priority_map: decisionResult.response.gateway_priority_map,
+ status: txn.status,
+ latency: txn.latency
+ })
+
+ cy.log(`Transaction ${index + 1}: Payment ${txn.paymentId} routed to ${decisionResult.response.decided_gateway}`)
+
+ // Update gateway score only once per transaction
+ return cy.updateGatewayScore({
+ merchantId: testData.merchantId,
+ gateway: decisionResult.response.decided_gateway,
+ paymentId: txn.paymentId,
+ status: txn.status,
+ txnLatency: {
+ gatewayLatency: txn.latency
+ }
+ }).then((updateResult) => {
+ expect(updateResult.response).to.haveValidScoreUpdate()
+ cy.log(`Score updated for ${txn.paymentId}: ${txn.status} with ${txn.latency}ms latency`)
+ return cy.wrap(decisionResult.response.decided_gateway)
+ })
+ })
+ }
+
+ // Process transactions sequentially to ensure proper ordering
+ let chain = cy.wrap(null)
+ transactions.forEach((txn, index) => {
+ chain = chain.then(() => processTransaction(txn, index))
+ })
+
+ return chain.then(() => {
+ // Verify that we have decisions for all transactions
+ expect(gatewayDecisions).to.have.length(transactions.length)
+
+ // Log summary of gateway selections
+ const gatewaySummary = gatewayDecisions.reduce((acc, decision) => {
+ acc[decision.gateway] = (acc[decision.gateway] || 0) + 1
+ return acc
+ }, {})
+ cy.log('Gateway Decision', gatewayDecisions)
+ cy.log('Gateway Selection Summary:', gatewaySummary)
+
+ // Test routing behavior after score updates by making additional decisions
+ return cy.decideGateway({
+ merchantId: testData.merchantId,
+ rankingAlgorithm: "SR_BASED_ROUTING",
+ paymentInfo: {
+ paymentId: `${testData.paymentId}_final_test`,
+ paymentMethodType: "UPI",
+ paymentMethod: "UPI_PAY",
+ customerId: `${testData.customerId}_final`
+ }
+ }).then((finalResult) => {
+ expect(finalResult.response).to.haveValidGatewayResponse()
+ cy.log(`Final routing decision after score updates: ${finalResult.response.decided_gateway}`)
+
+ // Verify that routing is influenced by the success rate data
+ // The gateway with better success rate should be preferred
+ const successfulGateways = gatewayDecisions
+ .filter(d => d.status === "AUTHORIZED")
+ .map(d => d.gateway)
+
+ if (successfulGateways.length > 0) {
+ cy.log('Gateways with successful transactions:', [...new Set(successfulGateways)])
+ }
+ })
+ })
+ })
+ })
+
+ it('should handle multiple gateways with different success rates', { tags: ['@success-rate', '@multiple-gateways'] }, () => {
+ const merchantId = `${testData.merchantId}_multi_gw`
+
+ cy.createMerchantAccount(merchantId).then(() => {
+ return cy.createSuccessRateRule(merchantId, {
+ successRate: 0.7,
+ latencyThreshold: 100,
+ bucketSize: 200,
+ hedgingPercent: 5
+ })
+ }).then(() => {
+ // Simulate transactions across multiple gateways with different success patterns
+ const gatewayTransactions = [
+ // GatewayA - Good performance
+ { paymentId: `${testData.paymentId}_gwa_1`, gateway: 'GatewayA', status: "AUTHORIZED", latency: 1500 },
+ { paymentId: `${testData.paymentId}_gwa_2`, gateway: 'GatewayA', status: "AUTHORIZED", latency: 1800 },
+ { paymentId: `${testData.paymentId}_gwa_3`, gateway: 'GatewayA', status: "AUTHORIZED", latency: 1600 },
+
+ // GatewayB - Mixed performance
+ { paymentId: `${testData.paymentId}_gwb_1`, gateway: 'GatewayB', status: "AUTHORIZED", latency: 2500 },
+ { paymentId: `${testData.paymentId}_gwb_2`, gateway: 'GatewayB', status: "FAILURE", latency: 4000 },
+ { paymentId: `${testData.paymentId}_gwb_3`, gateway: 'GatewayB', status: "AUTHORIZED", latency: 2200 },
+
+ // GatewayC - Poor performance
+ { paymentId: `${testData.paymentId}_gwc_1`, gateway: 'GatewayC', status: "FAILURE", latency: 5000 },
+ { paymentId: `${testData.paymentId}_gwc_2`, gateway: 'GatewayC', status: "FAILURE", latency: 4500 },
+ { paymentId: `${testData.paymentId}_gwc_3`, gateway: 'GatewayC', status: "AUTHORIZED", latency: 3000 }
+ ]
+
+ // Process each transaction: decide gateway first, then update score once
+ let chain = cy.wrap(null)
+
+ gatewayTransactions.forEach((txn, index) => {
+ chain = chain.then(() => {
+ // First decide gateway for this transaction
+ return cy.decideGateway({
+ merchantId: merchantId,
+ rankingAlgorithm: "SR_BASED_ROUTING",
+ eligibleGatewayList: ['GatewayA', 'GatewayB', 'GatewayC'],
+ paymentInfo: {
+ paymentId: txn.paymentId,
+ paymentMethodType: "UPI",
+ paymentMethod: "UPI_PAY",
+ customerId: `${testData.customerId}_multi_${index}`
+ }
+ }).then((decisionResult) => {
+ expect(decisionResult.response).to.haveValidGatewayResponse()
+
+ const decidedGateway = decisionResult.response.decided_gateway
+ cy.log(`Transaction ${index + 1}: ${txn.paymentId} routed to ${decidedGateway}`)
+
+ // Update score only once per transaction using the decided gateway
+ return cy.updateGatewayScore({
+ merchantId: merchantId,
+ gateway: decidedGateway,
+ paymentId: txn.paymentId,
+ status: txn.status,
+ txnLatency: {
+ gatewayLatency: txn.latency
+ }
+ }).then((updateResult) => {
+ expect(updateResult.response).to.haveValidScoreUpdate()
+ cy.log(`Score updated for ${txn.paymentId}: ${txn.status} (${txn.latency}ms) on ${decidedGateway}`)
+ return cy.wrap({ decidedGateway, originalGateway: txn.gateway, status: txn.status })
+ })
+ })
+ })
+ })
+
+ return chain.then(() => {
+ // After all score updates, test final routing decisions
+ const finalTests = Array.from({ length: 3 }, (_, i) => ({
+ paymentId: `${testData.paymentId}_final_${i}`,
+ customerId: `${testData.customerId}_final_${i}`
+ }))
+
+ let finalChain = cy.wrap(null)
+ const finalDecisions = []
+
+ finalTests.forEach((test, index) => {
+ finalChain = finalChain.then(() => {
+ return cy.decideGateway({
+ merchantId: merchantId,
+ rankingAlgorithm: "SR_BASED_ROUTING",
+ eligibleGatewayList: ['GatewayA', 'GatewayB', 'GatewayC'],
+ paymentInfo: {
+ paymentId: test.paymentId,
+ paymentMethodType: "UPI",
+ paymentMethod: "UPI_PAY",
+ customerId: test.customerId
+ }
+ }).then((finalResult) => {
+ expect(finalResult.response).to.haveValidGatewayResponse()
+ finalDecisions.push(finalResult.response.decided_gateway)
+ cy.log(`Final decision ${index + 1}: ${test.paymentId} → ${finalResult.response.decided_gateway}`)
+ return cy.wrap(finalResult.response.decided_gateway)
+ })
+ })
+ })
+
+ return finalChain.then(() => {
+ // Log summary of final routing decisions
+ const finalSummary = finalDecisions.reduce((acc, gateway) => {
+ acc[gateway] = (acc[gateway] || 0) + 1
+ return acc
+ }, {})
+
+ cy.log('Final Routing Summary after score updates:', finalSummary)
+
+ // Verify that routing is influenced by success rate data
+ expect(finalDecisions).to.have.length(3)
+ cy.log('All final routing decisions completed successfully')
+ })
+ })
+ })
+ })
+})
diff --git a/cypress/support/commands.js b/cypress/support/commands.js
new file mode 100644
index 00000000..f82b5117
--- /dev/null
+++ b/cypress/support/commands.js
@@ -0,0 +1,292 @@
+// ***********************************************
+// This example commands.js shows you how to
+// create various custom commands and overwrite
+// existing commands.
+//
+// For more comprehensive examples of custom
+// commands please read more here:
+// https://on.cypress.io/custom-commands
+// ***********************************************
+
+const { v4: uuidv4 } = require('uuid')
+
+// Helper function to generate unique IDs
+function generateUniqueId(prefix = '') {
+ const timestamp = Date.now()
+ const random = Math.floor(Math.random() * 1000)
+ return `${prefix}${timestamp}${random}`
+}
+
+// Helper function to get API base URL
+function getApiBaseUrl() {
+ return Cypress.env('API_BASE_URL') || 'http://localhost:8082'
+}
+
+/**
+ * Create a merchant account
+ * @param {string} merchantId - Optional merchant ID, will generate if not provided
+ */
+Cypress.Commands.add('createMerchantAccount', (merchantId = null) => {
+ const id = merchantId || generateUniqueId(Cypress.env('DEFAULT_MERCHANT_ID_PREFIX'))
+
+ return cy.request({
+ method: 'POST',
+ url: `${getApiBaseUrl()}/merchant-account/create`,
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: {
+ merchant_id: id
+ }
+ }).then((response) => {
+ expect(response.status).to.eq(200)
+ return cy.wrap({ merchantId: id, response: response.body })
+ })
+})
+
+/**
+ * Create a routing rule
+ * @param {string} merchantId - Merchant ID
+ * @param {object} ruleConfig - Rule configuration object
+ */
+Cypress.Commands.add('createRoutingRule', (merchantId, ruleConfig) => {
+ const defaultConfig = {
+ type: "successRate",
+ data: {
+ defaultLatencyThreshold: 90,
+ defaultSuccessRate: 0.5,
+ defaultBucketSize: 200,
+ defaultHedgingPercent: 5,
+ txnLatency: {
+ gatewayLatency: 5000
+ },
+ subLevelInputConfig: [
+ {
+ paymentMethodType: "upi",
+ paymentMethod: "upi_collect",
+ bucketSize: 250,
+ hedgingPercent: 1
+ }
+ ]
+ }
+ }
+
+ const config = { ...defaultConfig, ...ruleConfig }
+
+ return cy.request({
+ method: 'POST',
+ url: `${getApiBaseUrl()}/rule/create`,
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: {
+ merchant_id: merchantId,
+ config: config
+ }
+ }).then((response) => {
+ expect(response.status).to.eq(200)
+ return cy.wrap({ ruleConfig: config, response: response.body })
+ })
+})
+
+/**
+ * Decide gateway for a payment
+ * @param {object} decisionRequest - Gateway decision request object
+ */
+Cypress.Commands.add('decideGateway', (decisionRequest) => {
+ const request = {
+ merchantId: decisionRequest.merchantId || generateUniqueId(Cypress.env('DEFAULT_MERCHANT_ID_PREFIX')),
+ eligibleGatewayList: decisionRequest.eligibleGatewayList || Cypress.env('DEFAULT_GATEWAYS'),
+ rankingAlgorithm: decisionRequest.rankingAlgorithm || Cypress.env('ROUTING_ALGORITHMS').SUCCESS_RATE,
+ eliminationEnabled: decisionRequest.eliminationEnabled || true,
+ paymentInfo: {
+ paymentId: decisionRequest.paymentInfo.paymentId || generateUniqueId(Cypress.env('DEFAULT_PAYMENT_ID_PREFIX')),
+ amount: decisionRequest.paymentInfo.amount || 100.50,
+ currency: decisionRequest.paymentInfo.currency || 'USD',
+ customerId: decisionRequest.paymentInfo.customerId || generateUniqueId(Cypress.env('DEFAULT_CUSTOMER_ID_PREFIX') || 'CUST'),
+ udfs: decisionRequest.paymentInfo.udfs || null,
+ preferredGateway: decisionRequest.paymentInfo.preferredGateway || null,
+ paymentType: decisionRequest.paymentInfo.paymentType || "ORDER_PAYMENT",
+ metadata: decisionRequest.paymentInfo.metadata || null,
+ internalMetadata: decisionRequest.paymentInfo.internalMetadata || null,
+ isEmi: decisionRequest.paymentInfo.isEmi || false,
+ emiBank: decisionRequest.paymentInfo.emiBank || null,
+ emiTenure: decisionRequest.paymentInfo.emiTenure || null,
+ paymentMethodType: decisionRequest.paymentInfo.paymentMethodType || Cypress.env('PAYMENT_METHODS').UPI.type,
+ paymentMethod: decisionRequest.paymentInfo.paymentMethod || Cypress.env('PAYMENT_METHODS').UPI.method,
+ paymentSource: decisionRequest.paymentInfo.paymentSource || null,
+ authType: decisionRequest.paymentInfo.authType || null,
+ cardIssuerBankName: decisionRequest.paymentInfo.cardIssuerBankName || null,
+ cardIsin: decisionRequest.paymentInfo.cardIsin || null,
+ cardType: decisionRequest.paymentInfo.cardType || null,
+ cardSwitchProvider: decisionRequest.paymentInfo.cardSwitchProvider || null
+ }
+ }
+
+ return cy.request({
+ method: 'POST',
+ url: `${getApiBaseUrl()}/decide-gateway`,
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: request
+ }).then((response) => {
+ expect(response.status).to.eq(200)
+ return cy.wrap({ request, response: response.body })
+ })
+})
+
+/**
+ * Legacy Decide gateway for a payment
+ * @param {object} decisionRequest - Gateway decision request object
+ */
+Cypress.Commands.add('decideGatewayLegacy', (decisionRequest) => {
+ const request = {
+ merchantId: decisionRequest.merchantId || generateUniqueId(Cypress.env('DEFAULT_MERCHANT_ID_PREFIX')),
+ eligibleGatewayList: decisionRequest.eligibleGatewayList || Cypress.env('DEFAULT_GATEWAYS'),
+ rankingAlgorithm: decisionRequest.rankingAlgorithm || Cypress.env('ROUTING_ALGORITHMS').SUCCESS_RATE,
+ eliminationEnabled: decisionRequest.eliminationEnabled || true,
+ paymentInfo: {
+ paymentId: decisionRequest.paymentInfo.paymentId || generateUniqueId(Cypress.env('DEFAULT_PAYMENT_ID_PREFIX')),
+ amount: decisionRequest.paymentInfo.amount || 100.50,
+ currency: decisionRequest.paymentInfo.currency || 'USD',
+ customerId: decisionRequest.paymentInfo.customerId || generateUniqueId(Cypress.env('DEFAULT_CUSTOMER_ID_PREFIX') || 'CUST'),
+ udfs: decisionRequest.paymentInfo.udfs || null,
+ preferredGateway: decisionRequest.paymentInfo.preferredGateway || null,
+ paymentType: decisionRequest.paymentInfo.paymentType || "ORDER_PAYMENT",
+ metadata: decisionRequest.paymentInfo.metadata || null,
+ internalMetadata: decisionRequest.paymentInfo.internalMetadata || null,
+ isEmi: decisionRequest.paymentInfo.isEmi || false,
+ emiBank: decisionRequest.paymentInfo.emiBank || null,
+ emiTenure: decisionRequest.paymentInfo.emiTenure || null,
+ paymentMethodType: decisionRequest.paymentInfo.paymentMethodType || Cypress.env('PAYMENT_METHODS').UPI.type,
+ paymentMethod: decisionRequest.paymentInfo.paymentMethod || Cypress.env('PAYMENT_METHODS').UPI.method,
+ paymentSource: decisionRequest.paymentInfo.paymentSource || null,
+ authType: decisionRequest.paymentInfo.authType || null,
+ cardIssuerBankName: decisionRequest.paymentInfo.cardIssuerBankName || null,
+ cardIsin: decisionRequest.paymentInfo.cardIsin || null,
+ cardType: decisionRequest.paymentInfo.cardType || null,
+ cardSwitchProvider: decisionRequest.paymentInfo.cardSwitchProvider || null
+ }
+ }
+
+ return cy.request({
+ method: 'POST',
+ url: `${getApiBaseUrl()}/decision_gateway`,
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: request
+ }).then((response) => {
+ expect(response.status).to.eq(200)
+ return cy.wrap({ request, response: response.body })
+ })
+})
+
+/**
+ * Update gateway score
+ * @param {object} scoreUpdate - Score update object
+ */
+Cypress.Commands.add('updateGatewayScore', (scoreUpdate) => {
+ const defaultUpdate = {
+ merchantId: scoreUpdate.merchantId || generateUniqueId(Cypress.env('DEFAULT_MERCHANT_ID_PREFIX')),
+ gateway: scoreUpdate.gateway || "GatewayC",
+ gatewayReferenceId: scoreUpdate.gatewayReferenceId || null,
+ status: scoreUpdate.status || "AUTHORIZED",
+ paymentId: scoreUpdate.paymentId || generateUniqueId(Cypress.env('DEFAULT_PAYMENT_ID_PREFIX')),
+ enforceDynamicRoutingFailure: null,
+ txnLatency: scoreUpdate.txnLatency.gatewayLatency || {
+ gatewayLatency: 6000
+ }
+ }
+
+ const update = { ...defaultUpdate, ...scoreUpdate }
+
+ return cy.request({
+ method: 'POST',
+ url: `${getApiBaseUrl()}/update-gateway-score`,
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: update
+ }).then((response) => {
+ expect(response.status).to.eq(200)
+ return cy.wrap({ update, response: response.body })
+ })
+})
+
+/**
+ * Create a success rate routing rule
+ * @param {string} merchantId - Merchant ID
+ * @param {object} options - Configuration options
+ */
+Cypress.Commands.add('createSuccessRateRule', (merchantId, options = {}) => {
+ const ruleConfig = {
+ type: "successRate",
+ data: {
+ defaultLatencyThreshold: options.latencyThreshold || 90,
+ defaultSuccessRate: options.successRate || 0.5,
+ defaultBucketSize: options.bucketSize || 200,
+ defaultHedgingPercent: options.hedgingPercent || 5,
+ txnLatency: {
+ gatewayLatency: options.gatewayLatency || 5000
+ },
+ subLevelInputConfig: options.subLevelConfig || [
+ {
+ paymentMethodType: "upi",
+ paymentMethod: "upi_collect",
+ bucketSize: 250,
+ hedgingPercent: 1
+ }
+ ]
+ }
+ }
+
+ return cy.createRoutingRule(merchantId, ruleConfig)
+})
+
+/**
+ * Create a elimination routing rule
+ * @param {string} merchantId - Merchant ID
+ * @param {object} options - Configuration options
+ */
+Cypress.Commands.add('createEliminationRule', (merchantId, options = {}) => {
+ const ruleConfig = {
+ type: "elimination",
+ data: {
+ threshold: 0.35,
+ txnLatency: {
+ gatewayLatency: options.gatewayLatency || 5000
+ }
+ }
+ }
+
+ return cy.createRoutingRule(merchantId, ruleConfig)
+})
+
+/**
+ * Wait for service to be ready
+ */
+Cypress.Commands.add('waitForService', () => {
+ return cy.request({
+ method: 'GET',
+ url: `${getApiBaseUrl()}/health`,
+ failOnStatusCode: false,
+ timeout: 30000
+ }).then((response) => {
+ if (response.status !== 200) {
+ cy.wait(2000)
+ cy.waitForService()
+ }
+ })
+})
+
+/**
+ * Clean up test data (if cleanup endpoints exist)
+ * @param {string} merchantId - Merchant ID to clean up
+ */
+Cypress.Commands.add('cleanupTestData', (merchantId) => {
+ // This would depend on cleanup endpoints being available
+ // For now, just log the cleanup attempt
+ cy.log(`Cleaning up test data for merchant: ${merchantId}`)
+})
diff --git a/cypress/support/e2e.js b/cypress/support/e2e.js
new file mode 100644
index 00000000..f6028f4c
--- /dev/null
+++ b/cypress/support/e2e.js
@@ -0,0 +1,46 @@
+// ***********************************************************
+// This example support/e2e.js is processed and
+// loaded automatically before your test files.
+//
+// This is a great place to put global configuration and
+// behavior that modifies Cypress.
+//
+// You can change the location of this file or turn off
+// automatically serving support files with the
+// 'supportFile' configuration option.
+//
+// You can read more here:
+// https://on.cypress.io/configuration
+// ***********************************************************
+
+// Import commands.js using ES2015 syntax:
+import './commands'
+import '@cypress/grep/src/support'
+
+// Alternatively you can use CommonJS syntax:
+// require('./commands')
+
+// Global configuration
+Cypress.on('uncaught:exception', (err, runnable) => {
+ // returning false here prevents Cypress from
+ // failing the test on uncaught exceptions
+ return false
+})
+
+// Add custom assertions
+chai.use(function (chai, utils) {
+ chai.Assertion.addMethod('haveValidGatewayResponse', function () {
+ const obj = this._obj
+
+ expect(obj).to.have.property('decided_gateway')
+ expect(obj).to.have.property('gateway_priority_map')
+ expect(obj.gateway_priority_map).to.be.an('object')
+ })
+
+ chai.Assertion.addMethod('haveValidScoreUpdate', function () {
+ const obj = this._obj
+
+ expect(obj).to.have.property('message')
+ expect(obj.message).to.equal('Success')
+ })
+})
diff --git a/cypress/support/test-data-factory.js b/cypress/support/test-data-factory.js
new file mode 100644
index 00000000..cd37486d
--- /dev/null
+++ b/cypress/support/test-data-factory.js
@@ -0,0 +1,220 @@
+// Test Data Factory for Decision Engine Tests
+// This file provides utilities to generate test data for different routing scenarios
+
+const { v4: uuidv4 } = require('uuid')
+
+class TestDataFactory {
+ static generateMerchantId(prefix = 'merc_test_') {
+ return `${prefix}${Date.now()}_${Math.floor(Math.random() * 1000)}`
+ }
+
+ static generatePaymentId(prefix = 'PAY_test_') {
+ return `${prefix}${Date.now()}_${Math.floor(Math.random() * 1000)}`
+ }
+
+ static generateCustomerId(prefix = 'CUST_test_') {
+ return `${prefix}${Date.now()}_${Math.floor(Math.random() * 1000)}`
+ }
+
+ // Success Rate Rule Configurations
+ static getSuccessRateRuleConfig(options = {}) {
+ return {
+ type: "successRate",
+ data: {
+ defaultLatencyThreshold: options.latencyThreshold || 90,
+ defaultSuccessRate: options.successRate || 0.5,
+ defaultBucketSize: options.bucketSize || 200,
+ defaultHedgingPercent: options.hedgingPercent || 5,
+ txnLatency: {
+ gatewayLatency: options.gatewayLatency || 5000
+ },
+ subLevelInputConfig: options.subLevelConfig || [
+ {
+ paymentMethodType: "upi",
+ paymentMethod: "upi_collect",
+ bucketSize: 250,
+ hedgingPercent: 1
+ }
+ ]
+ }
+ }
+ }
+
+ // Payment Latency Rule Configurations
+ static getPaymentLatencyRuleConfig(options = {}) {
+ return {
+ type: "paymentLatency",
+ data: {
+ defaultLatencyThreshold: options.latencyThreshold || 90,
+ defaultBucketSize: options.bucketSize || 200,
+ defaultHedgingPercent: options.hedgingPercent || 5,
+ txnLatency: {
+ gatewayLatency: options.gatewayLatency || 3000,
+ paymentLatency: options.paymentLatency || 5000
+ },
+ subLevelInputConfig: options.subLevelConfig || []
+ }
+ }
+ }
+
+ // Cost Based Rule Configurations (if supported)
+ static getCostBasedRuleConfig(options = {}) {
+ return {
+ type: "costBased",
+ data: {
+ defaultCostThreshold: options.costThreshold || 2.5,
+ defaultBucketSize: options.bucketSize || 200,
+ defaultHedgingPercent: options.hedgingPercent || 5,
+ costConfig: {
+ baseCost: options.baseCost || 1.0,
+ variableCost: options.variableCost || 0.5
+ },
+ subLevelInputConfig: options.subLevelConfig || []
+ }
+ }
+ }
+
+ // Payment Info Configurations
+ static getPaymentInfo(options = {}) {
+ return {
+ paymentId: options.paymentId || this.generatePaymentId(),
+ amount: options.amount || 100.50,
+ currency: options.currency || "USD",
+ customerId: options.customerId || this.generateCustomerId(),
+ udfs: options.udfs || null,
+ preferredGateway: options.preferredGateway || null,
+ paymentType: options.paymentType || "ORDER_PAYMENT",
+ metadata: options.metadata || null,
+ internalMetadata: options.internalMetadata || null,
+ isEmi: options.isEmi || false,
+ emiBank: options.emiBank || null,
+ emiTenure: options.emiTenure || null,
+ paymentMethodType: options.paymentMethodType || "UPI",
+ paymentMethod: options.paymentMethod || "UPI_PAY",
+ paymentSource: options.paymentSource || null,
+ authType: options.authType || null,
+ cardIssuerBankName: options.cardIssuerBankName || null,
+ cardIsin: options.cardIsin || null,
+ cardType: options.cardType || null,
+ cardSwitchProvider: options.cardSwitchProvider || null
+ }
+ }
+
+ // Gateway Decision Request
+ static getGatewayDecisionRequest(options = {}) {
+ return {
+ merchantId: options.merchantId || this.generateMerchantId(),
+ eligibleGatewayList: options.eligibleGatewayList || ["GatewayA", "GatewayB", "GatewayC"],
+ rankingAlgorithm: options.rankingAlgorithm || "SR_BASED_ROUTING",
+ eliminationEnabled: options.eliminationEnabled !== undefined ? options.eliminationEnabled : true,
+ paymentInfo: this.getPaymentInfo(options.paymentInfo || {})
+ }
+ }
+
+ // Score Update Request
+ static getScoreUpdateRequest(options = {}) {
+ return {
+ merchantId: options.merchantId || this.generateMerchantId(),
+ gateway: options.gateway || "GatewayA",
+ gatewayReferenceId: options.gatewayReferenceId || null,
+ status: options.status || "AUTHORIZED",
+ paymentId: options.paymentId || this.generatePaymentId(),
+ enforceDynamicRoutingFailure: options.enforceDynamicRoutingFailure || null,
+ txnLatency: {
+ gatewayLatency: options.gatewayLatency || 3000,
+ paymentLatency: options.paymentLatency || 4000,
+ ...options.txnLatency
+ }
+ }
+ }
+
+ // Test Scenarios
+ static getLatencyTestScenarios() {
+ return [
+ { name: "Low Latency", gatewayLatency: 1000, paymentLatency: 1500, status: "AUTHORIZED" },
+ { name: "Medium Latency", gatewayLatency: 3000, paymentLatency: 4000, status: "AUTHORIZED" },
+ { name: "High Latency", gatewayLatency: 6000, paymentLatency: 8000, status: "AUTHORIZED" },
+ { name: "Failed Transaction", gatewayLatency: 2000, paymentLatency: 3000, status: "FAILED" },
+ { name: "Timeout", gatewayLatency: 10000, paymentLatency: 12000, status: "TIMEOUT" }
+ ]
+ }
+
+ static getSuccessRateTestScenarios() {
+ return [
+ { name: "High Success", transactions: Array(8).fill("AUTHORIZED").concat(Array(2).fill("FAILED")) },
+ { name: "Medium Success", transactions: Array(6).fill("AUTHORIZED").concat(Array(4).fill("FAILED")) },
+ { name: "Low Success", transactions: Array(3).fill("AUTHORIZED").concat(Array(7).fill("FAILED")) },
+ { name: "All Success", transactions: Array(10).fill("AUTHORIZED") },
+ { name: "All Failed", transactions: Array(10).fill("FAILED") }
+ ]
+ }
+
+ static getPaymentMethodTestCases() {
+ return [
+ { type: "UPI", method: "UPI_PAY", description: "UPI Payment" },
+ { type: "upi", method: "upi_collect", description: "UPI Collect" },
+ { type: "CARD", method: "CARD_PAY", description: "Card Payment" },
+ { type: "NETBANKING", method: "NETBANKING_PAY", description: "Net Banking" },
+ { type: "WALLET", method: "WALLET_PAY", description: "Wallet Payment" }
+ ]
+ }
+
+ static getRoutingAlgorithmTestCases() {
+ return [
+ { algorithm: "SR_BASED_ROUTING", description: "Success Rate Based Routing" },
+ { algorithm: "PL_BASED_ROUTING", description: "Payment Latency Based Routing" },
+ { algorithm: "COST_BASED_ROUTING", description: "Cost Based Routing" }
+ ]
+ }
+
+ // Edge Case Scenarios
+ static getEdgeCaseScenarios() {
+ return {
+ extremeLatency: {
+ gatewayLatency: 30000,
+ paymentLatency: 45000,
+ status: "TIMEOUT"
+ },
+ zeroLatency: {
+ gatewayLatency: 0,
+ paymentLatency: 0,
+ status: "AUTHORIZED"
+ },
+ negativeAmount: {
+ amount: -100,
+ currency: "USD"
+ },
+ largeAmount: {
+ amount: 999999.99,
+ currency: "USD"
+ },
+ invalidCurrency: {
+ amount: 100,
+ currency: "INVALID"
+ }
+ }
+ }
+
+ // Load Testing Data
+ static generateLoadTestData(count = 100) {
+ return Array.from({ length: count }, (_, index) => ({
+ merchantId: this.generateMerchantId(`load_test_${index}_`),
+ paymentId: this.generatePaymentId(`load_pay_${index}_`),
+ customerId: this.generateCustomerId(`load_cust_${index}_`),
+ amount: Math.floor(Math.random() * 1000) + 1,
+ latency: Math.floor(Math.random() * 5000) + 500
+ }))
+ }
+
+ // Performance Test Configurations
+ static getPerformanceTestConfig() {
+ return {
+ concurrentUsers: [1, 5, 10, 20, 50],
+ requestsPerSecond: [1, 5, 10, 25, 50],
+ testDuration: [30, 60, 120, 300], // seconds
+ latencyThresholds: [1000, 2000, 3000, 5000] // milliseconds
+ }
+ }
+}
+
+module.exports = TestDataFactory
diff --git a/decision-engine.postman_collection.json b/decision-engine.postman_collection.json
new file mode 100644
index 00000000..3a03b1bd
--- /dev/null
+++ b/decision-engine.postman_collection.json
@@ -0,0 +1,368 @@
+{
+ "info": {
+ "name": "Decision Engine",
+ "description": "Postman collection for juspay/decision-engine — a payment gateway routing service.\n\nBase URL: http://localhost:8080\n\nQuick start:\n1. Create a merchant account (Merchant / Create)\n2. Call POST /decide-gateway with a payment payload\n3. Record the outcome via POST /update-gateway-score",
+ "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
+ },
+ "variable": [
+ {
+ "key": "baseUrl",
+ "value": "http://localhost:8080",
+ "type": "string"
+ },
+ {
+ "key": "merchantId",
+ "value": "test_merchant",
+ "type": "string"
+ }
+ ],
+ "item": [
+ {
+ "name": "Health",
+ "item": [
+ {
+ "name": "Health Check",
+ "request": {
+ "method": "GET",
+ "header": [],
+ "url": {
+ "raw": "{{baseUrl}}/health",
+ "host": ["{{baseUrl}}"],
+ "path": ["health"]
+ },
+ "description": "Returns {\"message\":\"Health is good\"} when the service is up."
+ }
+ }
+ ]
+ },
+ {
+ "name": "Merchant Account",
+ "item": [
+ {
+ "name": "Create Merchant",
+ "request": {
+ "method": "POST",
+ "header": [{ "key": "Content-Type", "value": "application/json" }],
+ "url": {
+ "raw": "{{baseUrl}}/merchant-account/create",
+ "host": ["{{baseUrl}}"],
+ "path": ["merchant-account", "create"]
+ },
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"merchant_id\": \"{{merchantId}}\",\n \"gateway_success_rate_based_decider_input\": null\n}",
+ "options": { "raw": { "language": "json" } }
+ },
+ "description": "Register a new merchant. Must be done before calling /decide-gateway."
+ }
+ },
+ {
+ "name": "Get Merchant",
+ "request": {
+ "method": "GET",
+ "header": [],
+ "url": {
+ "raw": "{{baseUrl}}/merchant-account/{{merchantId}}",
+ "host": ["{{baseUrl}}"],
+ "path": ["merchant-account", "{{merchantId}}"]
+ },
+ "description": "Fetch a merchant's configuration by merchant_id."
+ }
+ },
+ {
+ "name": "Delete Merchant",
+ "request": {
+ "method": "DELETE",
+ "header": [],
+ "url": {
+ "raw": "{{baseUrl}}/merchant-account/{{merchantId}}",
+ "host": ["{{baseUrl}}"],
+ "path": ["merchant-account", "{{merchantId}}"]
+ },
+ "description": "Delete a merchant account."
+ }
+ }
+ ]
+ },
+ {
+ "name": "Gateway Decision",
+ "item": [
+ {
+ "name": "Decide Gateway (v2 — recommended)",
+ "request": {
+ "method": "POST",
+ "header": [{ "key": "Content-Type", "value": "application/json" }],
+ "url": {
+ "raw": "{{baseUrl}}/decide-gateway",
+ "host": ["{{baseUrl}}"],
+ "path": ["decide-gateway"]
+ },
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"merchantId\": \"{{merchantId}}\",\n \"paymentInfo\": {\n \"paymentId\": \"pay_001\",\n \"amount\": 1000.0,\n \"currency\": \"USD\",\n \"country\": \"US\",\n \"customerId\": \"cust_123\",\n \"paymentType\": \"ORDER_PAYMENT\",\n \"paymentMethodType\": \"CARD\",\n \"paymentMethod\": \"CREDIT\",\n \"authType\": \"THREE_DS\",\n \"cardIsin\": \"411111\",\n \"cardType\": \"CREDIT\",\n \"cardIssuerBankName\": \"HDFC\",\n \"preferredGateway\": null,\n \"paymentSource\": null,\n \"isEmi\": false,\n \"emiBank\": null,\n \"emiTenure\": null,\n \"metadata\": null,\n \"internalMetadata\": null,\n \"udfs\": null\n },\n \"eligibleGatewayList\": [\"stripe\", \"paypal\", \"adyen\"],\n \"rankingAlgorithm\": \"SrBasedRouting\",\n \"eliminationEnabled\": false\n}",
+ "options": { "raw": { "language": "json" } }
+ },
+ "description": "Core routing decision API (v2). Returns the best gateway from eligible_gateway_list.\n\nranking_algorithm options: SrBasedRouting | PlBasedRouting | NtwBasedRouting\n\nResponse includes:\n- decided_gateway: the selected gateway name\n- routing_approach: e.g. SR_SELECTION_V3_ROUTING, PRIORITY_LOGIC\n- gateway_priority_map: scores for each eligible gateway\n- routing_dimension: dimension used for SR scoring (e.g. CARD_BRAND, AUTH_TYPE)"
+ }
+ },
+ {
+ "name": "Decision Gateway (v1 — full payload)",
+ "request": {
+ "method": "POST",
+ "header": [{ "key": "Content-Type", "value": "application/json" }],
+ "url": {
+ "raw": "{{baseUrl}}/decision_gateway",
+ "host": ["{{baseUrl}}"],
+ "path": ["decision_gateway"]
+ },
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"orderReference\": {\n \"orderId\": \"order_001\",\n \"amount\": 1000.0,\n \"currency\": \"USD\",\n \"merchantId\": \"{{merchantId}}\",\n \"status\": \"NEW\",\n \"orderType\": \"ORDER_PAYMENT\",\n \"customerId\": \"cust_123\",\n \"preferredGateway\": null,\n \"metadata\": null,\n \"udfs\": {}\n },\n \"txnDetail\": {\n \"txnId\": \"txn_001\",\n \"orderId\": \"order_001\",\n \"merchantId\": \"{{merchantId}}\",\n \"status\": \"PENDING_VBV\",\n \"type\": \"ORDER_PAYMENT\",\n \"txnUuid\": \"pay_001\",\n \"gateway\": \"stripe\"\n },\n \"txnCardInfo\": {\n \"id\": \"card_001\",\n \"paymentMethodType\": \"CARD\",\n \"paymentMethod\": \"CREDIT\",\n \"authType\": \"THREE_DS\",\n \"cardIsin\": \"411111\",\n \"cardType\": \"CREDIT\",\n \"dateCreated\": \"2026-03-31T00:00:00Z\"\n },\n \"merchantAccount\": {\n \"merchantId\": \"{{merchantId}}\",\n \"gatewaySuccessRateBasedDeciderInput\": null\n },\n \"enforceGatewayList\": [\"stripe\", \"paypal\", \"adyen\"],\n \"priorityLogicScript\": null,\n \"priorityLogicOutput\": null\n}",
+ "options": { "raw": { "language": "json" } }
+ },
+ "description": "Legacy full-payload decision endpoint. Prefer /decide-gateway (v2) for new integrations."
+ }
+ },
+ {
+ "name": "Hybrid Routing",
+ "request": {
+ "method": "POST",
+ "header": [{ "key": "Content-Type", "value": "application/json" }],
+ "url": {
+ "raw": "{{baseUrl}}/routing/hybrid",
+ "host": ["{{baseUrl}}"],
+ "path": ["routing", "hybrid"]
+ },
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"static_routing_request\": {\n \"created_by\": \"{{merchantId}}\",\n \"fallback_output\": null,\n \"parameters\": {\n \"payment_method\": \"card\",\n \"currency\": \"USD\",\n \"country\": \"US\"\n }\n },\n \"dynamic_routing_request\": {\n \"merchant_id\": \"{{merchantId}}\",\n \"payment_info\": {\n \"payment_id\": \"pay_001\",\n \"amount\": 1000.0,\n \"currency\": \"USD\",\n \"payment_type\": \"ORDER_PAYMENT\",\n \"payment_method_type\": \"CARD\",\n \"payment_method\": \"CREDIT\"\n },\n \"eligible_gateway_list\": [\"stripe\", \"paypal\", \"adyen\"],\n \"ranking_algorithm\": \"SrBasedRouting\",\n \"elimination_enabled\": false\n }\n}",
+ "options": { "raw": { "language": "json" } }
+ },
+ "description": "Combines static rule-based routing with dynamic SR-based routing. Returns merged results from both engines."
+ }
+ }
+ ]
+ },
+ {
+ "name": "Score Feedback",
+ "item": [
+ {
+ "name": "Update Gateway Score",
+ "request": {
+ "method": "POST",
+ "header": [{ "key": "Content-Type", "value": "application/json" }],
+ "url": {
+ "raw": "{{baseUrl}}/update-gateway-score",
+ "host": ["{{baseUrl}}"],
+ "path": ["update-gateway-score"]
+ },
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"merchantId\": \"{{merchantId}}\",\n \"gateway\": \"stripe\",\n \"paymentId\": \"pay_001\",\n \"status\": \"CHARGED\",\n \"gatewayReferenceId\": \"stripe_ref_001\",\n \"enforceDynamicRoutingFailure\": false,\n \"txnLatency\": {\n \"gatewayLatency\": 120.5\n }\n}",
+ "options": { "raw": { "language": "json" } }
+ },
+ "description": "Feed transaction outcome back to update the success rate model.\n\nstatus options: CHARGED | AUTHENTICATION_FAILED | AUTHORIZATION_FAILED | JUSPAY_DECLINED | AUTO_REFUNDED | COD_INITIATED | STARTED | PENDING_VBV | CAPTURE_FAILED | VOID_FAILED | VOID_INITIATED | CAPTURE_INITIATED\n\nCall this after every transaction to keep SR scores accurate."
+ }
+ },
+ {
+ "name": "Update Score (legacy)",
+ "request": {
+ "method": "POST",
+ "header": [{ "key": "Content-Type", "value": "application/json" }],
+ "url": {
+ "raw": "{{baseUrl}}/update-score",
+ "host": ["{{baseUrl}}"],
+ "path": ["update-score"]
+ },
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"txn_detail\": {\n \"txnId\": \"txn_001\",\n \"orderId\": \"order_001\",\n \"merchantId\": \"{{merchantId}}\",\n \"status\": \"CHARGED\",\n \"type\": \"ORDER_PAYMENT\",\n \"txnUuid\": \"pay_001\",\n \"gateway\": \"stripe\",\n \"dateCreated\": \"2026-03-31T00:00:00Z\",\n \"txnAmount\": { \"value\": 1000, \"currency\": \"USD\" },\n \"txnObjectType\": \"ORDER_PAYMENT\",\n \"sourceObject\": \"CREDIT\",\n \"isEmi\": false\n },\n \"txn_card_info\": {\n \"id\": \"card_001\",\n \"paymentMethodType\": \"CARD\",\n \"paymentMethod\": \"CREDIT\",\n \"authType\": \"THREE_DS\",\n \"cardIsin\": \"411111\",\n \"cardType\": \"CREDIT\",\n \"dateCreated\": \"2026-03-31T00:00:00Z\"\n },\n \"log_message\": \"Transaction completed\",\n \"enforce_dynaic_routing_failure\": false,\n \"txn_latency\": {\n \"gatewayLatency\": 120.5\n }\n}",
+ "options": { "raw": { "language": "json" } }
+ },
+ "description": "Legacy score update endpoint using the full txn_detail / txn_card_info structure. Prefer /update-gateway-score for new integrations."
+ }
+ }
+ ]
+ },
+ {
+ "name": "Routing Rules (Euclid)",
+ "item": [
+ {
+ "name": "Create Routing Rule",
+ "request": {
+ "method": "POST",
+ "header": [{ "key": "Content-Type", "value": "application/json" }],
+ "url": {
+ "raw": "{{baseUrl}}/routing/create",
+ "host": ["{{baseUrl}}"],
+ "path": ["routing", "create"]
+ },
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"name\": \"My Priority Rule\",\n \"description\": \"Route US card payments: Stripe first, Adyen fallback\",\n \"created_by\": \"{{merchantId}}\",\n \"algorithm_for\": \"Payment\",\n \"algorithm\": {\n \"type\": \"priority\",\n \"data\": [\n { \"connector\": \"stripe\", \"merchant_connector_id\": null },\n { \"connector\": \"adyen\", \"merchant_connector_id\": null }\n ]\n }\n}",
+ "options": { "raw": { "language": "json" } }
+ },
+ "description": "Create a routing rule in the Euclid rules engine.\n\nalgorithm.type options:\n- \"single\": always route to one connector\n- \"priority\": ordered fallback list\n- \"volume_split\": percentage-based split across connectors\n- \"advanced\": conditional AST-based logic\n\nalgorithm_for options: Payment | Payout | ThreeDsAuthentication"
+ }
+ },
+ {
+ "name": "Activate Routing Rule",
+ "request": {
+ "method": "POST",
+ "header": [{ "key": "Content-Type", "value": "application/json" }],
+ "url": {
+ "raw": "{{baseUrl}}/routing/activate",
+ "host": ["{{baseUrl}}"],
+ "path": ["routing", "activate"]
+ },
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"created_by\": \"{{merchantId}}\",\n \"routing_algorithm_id\": \"\"\n}",
+ "options": { "raw": { "language": "json" } }
+ },
+ "description": "Activate a previously created routing rule for a merchant. Only one rule can be active at a time per merchant."
+ }
+ },
+ {
+ "name": "List Routing Rules",
+ "request": {
+ "method": "POST",
+ "header": [],
+ "url": {
+ "raw": "{{baseUrl}}/routing/list/{{merchantId}}",
+ "host": ["{{baseUrl}}"],
+ "path": ["routing", "list", "{{merchantId}}"]
+ },
+ "description": "List all routing rules created by a merchant."
+ }
+ },
+ {
+ "name": "Get Active Routing Rule",
+ "request": {
+ "method": "POST",
+ "header": [],
+ "url": {
+ "raw": "{{baseUrl}}/routing/list/active/{{merchantId}}",
+ "host": ["{{baseUrl}}"],
+ "path": ["routing", "list", "active", "{{merchantId}}"]
+ },
+ "description": "Get the currently active routing rule for a merchant."
+ }
+ },
+ {
+ "name": "Evaluate Routing Rule",
+ "request": {
+ "method": "POST",
+ "header": [{ "key": "Content-Type", "value": "application/json" }],
+ "url": {
+ "raw": "{{baseUrl}}/routing/evaluate",
+ "host": ["{{baseUrl}}"],
+ "path": ["routing", "evaluate"]
+ },
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"created_by\": \"{{merchantId}}\",\n \"fallback_output\": [\n { \"connector\": \"stripe\", \"merchant_connector_id\": null }\n ],\n \"parameters\": {\n \"payment_method\": \"card\",\n \"currency\": \"USD\",\n \"country\": \"US\",\n \"amount\": 1000\n }\n}",
+ "options": { "raw": { "language": "json" } }
+ },
+ "description": "Test/dry-run the active routing rule for a merchant with given payment parameters. Returns the connector(s) the rule would select."
+ }
+ },
+ {
+ "name": "Configure SR Dimensions",
+ "request": {
+ "method": "POST",
+ "header": [{ "key": "Content-Type", "value": "application/json" }],
+ "url": {
+ "raw": "{{baseUrl}}/config-sr-dimension",
+ "host": ["{{baseUrl}}"],
+ "path": ["config-sr-dimension"]
+ },
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"merchant_id\": \"{{merchantId}}\",\n \"dimensions\": [\"CARD_BRAND\", \"AUTH_TYPE\", \"CURRENCY\"]\n}",
+ "options": { "raw": { "language": "json" } }
+ },
+ "description": "Configure which dimensions to use when computing success rates for a merchant.\n\nPossible dimensions: CARD_BRAND | AUTH_TYPE | CURRENCY | PAYMENT_METHOD | CARD_TYPE | CARD_ISIN | COUNTRY"
+ }
+ }
+ ]
+ },
+ {
+ "name": "Rule Configuration (service config)",
+ "item": [
+ {
+ "name": "Create Rule Config",
+ "request": {
+ "method": "POST",
+ "header": [{ "key": "Content-Type", "value": "application/json" }],
+ "url": {
+ "raw": "{{baseUrl}}/rule/create",
+ "host": ["{{baseUrl}}"],
+ "path": ["rule", "create"]
+ },
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"merchant_id\": \"{{merchantId}}\",\n \"config\": {\n \"type\": \"successRate\",\n \"data\": {\n \"defaultBucketSize\": 20,\n \"defaultLatencyThreshold\": null,\n \"defaultHedgingPercent\": null\n }\n }\n}",
+ "options": { "raw": { "language": "json" } }
+ },
+ "description": "Create a service-level rule config (e.g. SR thresholds, elimination settings).\n\nconfig options: SuccessRate | Elimination | DebitRouting"
+ }
+ },
+ {
+ "name": "Get Rule Config",
+ "request": {
+ "method": "POST",
+ "header": [{ "key": "Content-Type", "value": "application/json" }],
+ "url": {
+ "raw": "{{baseUrl}}/rule/get",
+ "host": ["{{baseUrl}}"],
+ "path": ["rule", "get"]
+ },
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"merchant_id\": \"{{merchantId}}\",\n \"algorithm\": \"successRate\"\n}",
+ "options": { "raw": { "language": "json" } }
+ },
+ "description": "Retrieve a specific rule config for a merchant.\n\nalgorithm options: SuccessRate | Elimination | DebitRouting"
+ }
+ },
+ {
+ "name": "Update Rule Config",
+ "request": {
+ "method": "POST",
+ "header": [{ "key": "Content-Type", "value": "application/json" }],
+ "url": {
+ "raw": "{{baseUrl}}/rule/update",
+ "host": ["{{baseUrl}}"],
+ "path": ["rule", "update"]
+ },
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"merchant_id\": \"{{merchantId}}\",\n \"config\": {\n \"type\": \"successRate\",\n \"data\": {\n \"defaultBucketSize\": 30,\n \"defaultHedgingPercent\": 0.1\n }\n }\n}",
+ "options": { "raw": { "language": "json" } }
+ },
+ "description": "Update an existing rule config."
+ }
+ },
+ {
+ "name": "Delete Rule Config",
+ "request": {
+ "method": "POST",
+ "header": [{ "key": "Content-Type", "value": "application/json" }],
+ "url": {
+ "raw": "{{baseUrl}}/rule/delete",
+ "host": ["{{baseUrl}}"],
+ "path": ["rule", "delete"]
+ },
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"merchant_id\": \"{{merchantId}}\",\n \"algorithm\": \"successRate\"\n}",
+ "options": { "raw": { "language": "json" } }
+ },
+ "description": "Delete a rule config for a merchant."
+ }
+ }
+ ]
+ }
+ ]
+}
diff --git a/docker-compose.override.yml b/docker-compose.override.yml
new file mode 100644
index 00000000..c2720dc9
--- /dev/null
+++ b/docker-compose.override.yml
@@ -0,0 +1,3 @@
+# Local profile variants are now defined directly in docker-compose.yaml.
+# This override file is intentionally kept minimal for backward compatibility.
+services: {}
diff --git a/docker-compose.yaml b/docker-compose.yaml
index 9639b552..97443feb 100644
--- a/docker-compose.yaml
+++ b/docker-compose.yaml
@@ -1,25 +1,32 @@
services:
- open-router:
- image: ghcr.io/juspay/decision-engine:v1.2.0
+ # ==========================================
+ # Decision Engine Runtime (GHCR Images)
+ # ==========================================
+ open-router-pg-ghcr:
+ image: ghcr.io/juspay/decision-engine/postgres:${DECISION_ENGINE_TAG:-v1.4}
pull_policy: always
platform: linux/amd64
- container_name: open-router
+ profiles:
+ - postgres-ghcr
+ - dashboard-postgres-ghcr
restart: unless-stopped
ports:
- "8080:8080"
+ - "9094:9094"
+ - "9094:9094"
depends_on:
- mysql:
+ postgresql:
condition: service_healthy
redis:
condition: service_healthy
- groovy-runner:
- condition: service_healthy
- routing-config:
+ db-migrator-postgres:
condition: service_completed_successfully
volumes:
- ./config/docker-configuration.toml:/local/config/development.toml
networks:
- - open-router-network
+ open-router-network:
+ aliases:
+ - decision-engine-api
environment:
- GROOVY_RUNNER_HOST=host.docker.internal:8085
@@ -36,7 +43,7 @@ services:
- "com.docker.compose.watchfile=Cargo.lock"
image: decision-engine-open-router-local:latest
platform: linux/amd64
- container_name: open-router
+ container_name: open-router-local
restart: unless-stopped
ports:
- "8080:8080"
@@ -69,7 +76,7 @@ services:
- "com.docker.compose.watchfile=Cargo.lock"
image: decision-engine-open-router-local-pg:latest
platform: linux/amd64
- container_name: open-router
+ container_name: open-router-local-pg
restart: unless-stopped
ports:
- "8080:8080"
@@ -79,8 +86,8 @@ services:
condition: service_healthy
redis:
condition: service_healthy
- groovy-runner-local:
- condition: service_healthy
+ db-migrator-postgres:
+ condition: service_completed_successfully
volumes:
- ./config/docker-configuration.toml:/local/config/development.toml
networks:
@@ -88,32 +95,180 @@ services:
environment:
- GROOVY_RUNNER_HOST=host.docker.internal:8085
- open-router-pg:
- image: ghcr.io/juspay/decision-engine/postgres:v1.2.0
+ open-router-mysql-ghcr:
+ image: ghcr.io/juspay/decision-engine:${DECISION_ENGINE_TAG:-v1.4}
pull_policy: always
platform: linux/amd64
- container_name: open-router-pg
+ profiles:
+ - mysql-ghcr
+ - dashboard-mysql-ghcr
restart: unless-stopped
ports:
- "8080:8080"
- - "9090:9090"
depends_on:
- db-migrator-postgres:
+ mysql:
+ condition: service_healthy
+ redis:
+ condition: service_healthy
+ routing-config:
condition: service_completed_successfully
- groovy-runner-local:
+ db-migrator:
+ condition: service_completed_successfully
+ volumes:
+ - ./config/docker-configuration.toml:/local/config/development.toml
+ networks:
+ open-router-network:
+ aliases:
+ - decision-engine-api
+ environment:
+ - GROOVY_RUNNER_HOST=host.docker.internal:8085
+
+ # ==========================================
+ # Decision Engine Runtime (Local Build)
+ # ==========================================
+ open-router-pg-local:
+ build:
+ context: .
+ dockerfile: Dockerfile.postgres
+ platforms:
+ - linux/amd64
+ image: decision-engine-pg:local
+ platform: linux/amd64
+ profiles:
+ - postgres-local
+ - dashboard-postgres-local
+ restart: unless-stopped
+ ports:
+ - "8080:8080"
+ - "9094:9094"
+ depends_on:
+ postgresql:
+ condition: service_healthy
+ redis:
condition: service_healthy
+ db-migrator-postgres:
+ condition: service_completed_successfully
volumes:
- ./config/docker-configuration.toml:/local/config/development.toml
networks:
- - open-router-network
+ open-router-network:
+ aliases:
+ - decision-engine-api
environment:
- GROOVY_RUNNER_HOST=host.docker.internal:8085
- groovy-runner:
- image: ghcr.io/juspay/open-router/groovy-runner:main
+ open-router-mysql-local:
+ build:
+ context: .
+ dockerfile: Dockerfile
+ platforms:
+ - linux/amd64
+ image: decision-engine-mysql:local
+ platform: linux/amd64
+ profiles:
+ - mysql-local
+ - dashboard-mysql-local
+ restart: unless-stopped
+ ports:
+ - "8080:8080"
+ depends_on:
+ mysql:
+ condition: service_healthy
+ redis:
+ condition: service_healthy
+ routing-config:
+ condition: service_completed_successfully
+ db-migrator:
+ condition: service_completed_successfully
+ volumes:
+ - ./config/docker-configuration.toml:/local/config/development.toml
+ networks:
+ open-router-network:
+ aliases:
+ - decision-engine-api
+ environment:
+ - GROOVY_RUNNER_HOST=host.docker.internal:8085
+
+ # ==========================================
+ # Dashboard and Docs
+ # ==========================================
+ nginx:
+ image: nginx:alpine
+ profiles:
+ - dashboard-postgres-ghcr
+ - dashboard-postgres-local
+ - dashboard-mysql-ghcr
+ - dashboard-mysql-local
+ restart: unless-stopped
+ ports:
+ - "8081:80"
+ volumes:
+ - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
+ - ./website/dist:/usr/share/nginx/html/dashboard:ro
+ depends_on:
+ mintlify-docs:
+ condition: service_healthy
+ networks:
+ - open-router-network
+
+ mintlify-docs:
+ build:
+ context: .
+ dockerfile: Dockerfile.docs
+ profiles:
+ - dashboard-postgres-ghcr
+ - dashboard-postgres-local
+ - dashboard-mysql-ghcr
+ - dashboard-mysql-local
+ restart: unless-stopped
+ expose:
+ - "3000"
+ networks:
+ - open-router-network
+ healthcheck:
+ test: ["CMD-SHELL", "wget -qO- http://localhost:3000 > /dev/null 2>&1 || exit 1"]
+ interval: 10s
+ timeout: 10s
+ retries: 10
+ start_period: 60s
+
+ # ==========================================
+ # Supporting Services
+ # ==========================================
+ prometheus:
+ image: prom/prometheus:latest
+ profiles:
+ - monitoring
+ networks:
+ - open-router-network
+ volumes:
+ - ./config/prometheus.yaml:/etc/prometheus/prometheus.yml
+ ports:
+ - "9090:9090"
+ restart: unless-stopped
+
+ grafana:
+ image: grafana/grafana:latest
+ profiles:
+ - monitoring
+ ports:
+ - "3000:3000"
+ networks:
+ - open-router-network
+ restart: unless-stopped
+ environment:
+ - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin
+ - GF_AUTH_ANONYMOUS_ENABLED=true
+ - GF_AUTH_BASIC_ENABLED=false
+ volumes:
+ - ./config/grafana-datasource.yaml:/etc/grafana/provisioning/datasources/datasource.yml
+
+ groovy-runner-ghcr:
+ image: ghcr.io/juspay/decision-engine/groovy-runner:${GROOVY_RUNNER_TAG:-v1.4}
pull_policy: always
platform: linux/amd64
- container_name: groovy-runner
+ profiles:
+ - groovy-ghcr
restart: unless-stopped
ports:
- "8085:8085"
@@ -137,8 +292,11 @@ services:
labels:
- "com.docker.compose.watchfile=groovy.Dockerfile"
- "com.docker.compose.watchfile=src/Runner.groovy"
+ image: decision-engine-groovy-runner:local
platform: linux/amd64
- container_name: groovy-runner
+ profiles:
+ - groovy-local
+ container_name: groovy-runner-local
restart: unless-stopped
ports:
- "8085:8085"
@@ -151,63 +309,93 @@ services:
retries: 5
start_period: 10s
+ # ==========================================
+ # Core Infrastructure
+ # ==========================================
mysql:
image: mysql:8.0
- container_name: open-router-mysql
+ profiles:
+ - mysql-ghcr
+ - dashboard-mysql-ghcr
+ - mysql-local
+ - dashboard-mysql-local
restart: unless-stopped
environment:
- - MYSQL_ROOT_PASSWORD=root
- - MYSQL_DATABASE=jdb
- volumes:
- - mysql-data:/var/lib/mysql
+ MYSQL_ROOT_PASSWORD: root
+ MYSQL_DATABASE: jdb
+ MYSQL_USER: db_user
+ MYSQL_PASSWORD: db_pass
ports:
- "3306:3306"
+ volumes:
+ - mysql-data:/var/lib/mysql
networks:
- open-router-network
healthcheck:
- test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-uroot", "-proot"]
- interval: 5s
- timeout: 10s
- retries: 10
+ test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-proot"]
+ interval: 10s
+ timeout: 5s
+ retries: 5
+ start_period: 30s
- postgresql:
- image: postgres:latest
- container_name: open-router-postgres
- restart: unless-stopped
+ postgresql:
+ image: postgres:16
+ profiles:
+ - postgres-ghcr
+ - dashboard-postgres-ghcr
+ - postgres-local
+ - dashboard-postgres-local
+ restart: unless-stopped
+ container_name: postgres-db
environment:
- - POSTGRES_USER=db_user
- - POSTGRES_PASSWORD=db_pass
- - POSTGRES_DB=decision_engine_db
- volumes:
- - postgres-data:/var/lib/postgresql/data
- ports:
+ POSTGRES_USER: db_user
+ POSTGRES_PASSWORD: db_pass
+ POSTGRES_DB: decision_engine_db
+ ports:
- "5432:5432"
+ volumes:
+ - postgres-data:/var/lib/postgresql
networks:
- - open-router-network
+ - open-router-network
healthcheck:
- test: ["CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}"]
- interval: 5s
- retries: 3
- start_period: 5s
- timeout: 5s
+ test: ["CMD-SHELL", "pg_isready -U db_user -d decision_engine_db"]
+ interval: 10s
+ timeout: 5s
+ retries: 5
+ start_period: 30s
redis:
- image: redis:7
- container_name: open-router-redis
+ image: redis:7-alpine
+ profiles:
+ - postgres-ghcr
+ - dashboard-postgres-ghcr
+ - postgres-local
+ - dashboard-postgres-local
+ - mysql-ghcr
+ - dashboard-mysql-ghcr
+ - mysql-local
+ - dashboard-mysql-local
+ restart: unless-stopped
ports:
- "6379:6379"
+ volumes:
+ - redis-data:/data
networks:
- open-router-network
healthcheck:
- test: ["CMD-SHELL", "redis-cli ping | grep '^PONG$'"]
- interval: 5s
+ test: ["CMD", "redis-cli", "ping"]
+ interval: 10s
+ timeout: 5s
retries: 5
start_period: 5s
- timeout: 5s
db-migrator:
image: mysql:8.0
- container_name: db-migrator
+ profiles:
+ - mysql-ghcr
+ - dashboard-mysql-ghcr
+ - mysql-local
+ - dashboard-mysql-local
depends_on:
mysql:
condition: service_healthy
@@ -217,10 +405,15 @@ services:
entrypoint: ["/bin/sh", "-c", "for sql_file in $$(find /app/migrations -name 'up.sql' -type f | sort); do echo \"Running migration: $$sql_file\"; mysql -h mysql -uroot -proot jdb < \"$$sql_file\"; done"]
networks:
- open-router-network
-
+
db-migrator-postgres:
image: rust:latest
- container_name: db-migrator
+ profiles:
+ - postgres-ghcr
+ - dashboard-postgres-ghcr
+ - postgres-local
+ - dashboard-postgres-local
+ container_name: db-migrator-postgres
depends_on:
postgresql:
condition: service_healthy
@@ -230,13 +423,17 @@ services:
volumes:
- .:/app
working_dir: /app
- command: "bash -c 'cargo install diesel_cli --no-default-features --features postgres && cargo install just && just migrate-pg'"
+ command: "bash -c 'cargo install diesel_cli --no-default-features --features postgres && diesel migration run --database-url \"$$DATABASE_URL\" --migration-dir /app/migrations_pg --config-file /app/diesel_pg.toml'"
networks:
- open-router-network
routing-config:
image: python:3.10-slim
- container_name: routing-config
+ profiles:
+ - mysql-ghcr
+ - dashboard-mysql-ghcr
+ - mysql-local
+ - dashboard-mysql-local
depends_on:
mysql:
condition: service_healthy
@@ -247,6 +444,90 @@ services:
networks:
- open-router-network
+ # Analytics Infrastructure
+ zookeeper:
+ image: confluentinc/cp-zookeeper:7.4.0
+ platform: linux/amd64
+ container_name: open-router-zookeeper
+ environment:
+ ZOOKEEPER_CLIENT_PORT: 2181
+ ZOOKEEPER_TICK_TIME: 2000
+ networks:
+ - open-router-network
+ profiles:
+ - analytics
+
+ kafka:
+ image: confluentinc/cp-kafka:7.4.0
+ platform: linux/amd64
+ container_name: open-router-kafka
+ depends_on:
+ - zookeeper
+ ports:
+ - "9092:9092"
+ environment:
+ KAFKA_BROKER_ID: 1
+ KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
+ KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:29092,PLAINTEXT_HOST://localhost:9092
+ KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
+ KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
+ KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
+ KAFKA_AUTO_CREATE_TOPICS_ENABLE: "true"
+ networks:
+ - open-router-network
+ profiles:
+ - analytics
+ healthcheck:
+ test: ["CMD", "kafka-topics", "--bootstrap-server", "localhost:9092", "--list"]
+ interval: 10s
+ timeout: 10s
+ retries: 5
+
+ clickhouse:
+ image: clickhouse/clickhouse-server:latest
+ platform: linux/amd64
+ container_name: open-router-clickhouse
+ ports:
+ - "8123:8123"
+ - "9000:9000"
+ environment:
+ CLICKHOUSE_DB: decision_engine_analytics
+ CLICKHOUSE_USER: analytics_user
+ CLICKHOUSE_PASSWORD: analytics_pass
+ volumes:
+ - clickhouse-data:/var/lib/clickhouse
+ - ./analytics/clickhouse/init:/docker-entrypoint-initdb.d
+ networks:
+ - open-router-network
+ depends_on:
+ - kafka
+ - zookeeper
+ profiles:
+ - analytics
+ healthcheck:
+ test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8123/ping"]
+ interval: 10s
+ timeout: 5s
+ retries: 5
+
+ analytics-migrator:
+ image: clickhouse/clickhouse-server:latest
+ platform: linux/amd64
+ container_name: analytics-migrator
+ depends_on:
+ clickhouse:
+ condition: service_healthy
+ kafka:
+ condition: service_healthy
+ volumes:
+ - ./analytics:/analytics
+ working_dir: /analytics
+ command: sh /analytics/run_migrations.sh
+ networks:
+ - open-router-network
+ profiles:
+ - analytics
+
networks:
open-router-network:
driver: bridge
@@ -255,3 +536,4 @@ volumes:
mysql-data:
redis-data:
postgres-data:
+ clickhouse-data:
diff --git a/docs/analytics.mdx b/docs/analytics.mdx
new file mode 100644
index 00000000..6036ca9e
--- /dev/null
+++ b/docs/analytics.mdx
@@ -0,0 +1,88 @@
+---
+title: "Analytics"
+description: "Routing metrics, score snapshots, and operational summaries"
+---
+
+## What It Shows
+
+Analytics is the operator-facing view for understanding how routing is behaving in practice.
+
+The page is split into these sections:
+
+- Overview
+- Gateway Scoring
+- Decisions
+- Routing Stats
+- Logs / Summaries
+
+For single-payment inspection, use the separate Payment Audit surface documented in [`payment-audit`](payment-audit).
+
+## Data Sources
+
+The first release uses the sources already present in the repository:
+
+- Redis for live SR and latency snapshots
+- Prometheus for live counters and error-rate tiles
+- Postgres for stored analytics events, snapshots, and summaries
+
+ClickHouse is intentionally not required for the first release. If the volume or retention profile grows beyond Postgres, it can be added later as a write sink.
+
+## Scope
+
+Analytics supports two views:
+
+- current merchant
+- all merchants
+
+The current-merchant view uses the merchant selected in the top bar. The all-merchants view aggregates across the stored analytics events.
+
+Connector success-rate history is sourced from stored `score_snapshot` analytics events, not directly from Redis. Redis remains the live source for current score state. In the merchant-scoped view, the connector SR chart can be narrowed by:
+
+- `payment_method_type`
+- `payment_method`
+- connector
+
+In all-merchants mode, the chart intentionally stays connector-only so operators get a global SR trend without per-method slicing.
+
+## Generating Demo Traffic
+
+To populate Analytics and Decision Audit with real traffic, use the routing traffic generator.
+
+First apply the Postgres migration that creates `analytics_event`:
+
+```bash
+just migrate-pg
+```
+
+Then generate traffic for `merchant_space`:
+
+```bash
+bash scripts/generate-routing-traffic.sh
+```
+
+What the script does:
+
+- creates or reuses `merchant_space`
+- enables success-rate routing for that merchant through the real `/rule/create` or `/rule/update` flow
+- sends `100` real `POST /decide-gateway` requests with mixed payment-method combinations
+- follows each decision with `POST /update-gateway-score` using a mix of successful and failed outcomes
+- creates and activates a priority-based routing rule through `/routing/create` and `/routing/activate`
+- sends rule-based `POST /routing/evaluate` traffic so the rule-evaluation analytics path is populated
+
+Useful overrides:
+
+```bash
+MERCHANT_ID=merchant_space TOTAL_PAYMENTS=100 bash scripts/generate-routing-traffic.sh
+RULE_EVALUATIONS=40 bash scripts/generate-routing-traffic.sh
+CONNECTORS_CSV=stripe,adyen,checkout,paypal bash scripts/generate-routing-traffic.sh
+```
+
+After the script finishes, open `/dashboard/analytics` or `/dashboard/audit` and select `merchant_space` in the merchant picker.
+
+## Related Files
+
+- `website/src/components/pages/AnalyticsPage.tsx`
+- `website/src/components/layout/Sidebar.tsx`
+- `src/routes/analytics.rs`
+- `src/analytics/`
+- `src/metrics.rs`
diff --git a/docs/api-reference.md b/docs/api-reference.md
index 2dfeb000..8add4ea4 100644
--- a/docs/api-reference.md
+++ b/docs/api-reference.md
@@ -1,160 +1,42 @@
-# Dynamo API Reference
+# API Reference
-## Overview
+The canonical API contract for the docs site is `docs/openapi.json`.
-Dynamo provides both gRPC and HTTP APIs for its dynamic payment routing services. This reference documents the available endpoints, their parameters, and example usage.
+Use this page to find the right endpoint family. Use the OpenAPI-backed endpoint pages for request and response schema details.
----
+## Endpoint Families
-## Authentication and Headers
+### Health
-All API requests require appropriate authentication:
+- [Health Check](api-reference/endpoint/healthCheck)
-| Header | Required | Description |
-|:-------|:--------:|:------------|
-| `x-api-key` | ✅ | API key for authentication |
-| `x-tenant-id` | ✅ | Tenant identifier (*required if multi-tenancy is enabled) |
+### Merchant API
----
+- [Create Merchant](api-reference/endpoint/createMerchant)
+- [Get Merchant](api-reference/endpoint/getMerchant)
+- [Delete Merchant](api-reference/endpoint/deleteMerchant)
-## Available Services
+### Rule Based Routing
-Dynamo offers three main routing services:
+These are the `/routing/*` APIs for creating, activating, listing, and evaluating routing rules. The create endpoint supports `priority`, `single`, `volume_split`, and `advanced` Euclid programs.
-### 1. **[Success Rate Calculator](api-reference/success-rate.md)**
+- [Create Routing Rule](api-reference/endpoint/createRoutingRule)
+- [Activate Routing Rule](api-reference/endpoint/activateRoutingRule)
+- [List Routing Rules](api-reference/endpoint/listRoutingRules)
+- [Get Active Routing Rule](api-reference/endpoint/getActiveRoutingRule)
+- [Evaluate Routing Rule](api-reference/endpoint/evaluateRoutingRule)
-Routes payments to processors with the highest historical success rates.
+### Dynamic Routing APIs
-| Endpoint | Description |
-|:---------|:------------|
-| **`FetchSuccessRate`** | Get success rates for processors |
-| **`UpdateSuccessRateWindow`** | Update success/failure data |
-| **`InvalidateWindows`** | Reset success rate data |
-| **`FetchEntityAndGlobalSuccessRate`** | Get both entity and global success rates |
+These are the dynamic routing APIs for gateway decisioning, gateway score updates, and `/rule/*` configuration.
-### 2. **[Elimination Analyser](api-reference/elimination.md)**
+- [POST /decide-gateway](api-reference/endpoint/decideGateway)
+- [POST /update-gateway-score](api-reference/endpoint/updateGatewayScore)
+- [POST /rule/create](api-reference/endpoint/createRuleConfig)
+- [POST /rule/get](api-reference/endpoint/getRuleConfig)
+- [POST /rule/update](api-reference/endpoint/updateRuleConfig)
+- [POST /rule/delete](api-reference/endpoint/deleteRuleConfig)
-Prevents routing to processors that meet failure criteria.
-
-| Endpoint | Description |
-|:---------|:------------|
-| **`GetEliminationStatus`** | Check if processors should be eliminated |
-| **`UpdateEliminationBucket`** | Update failure data |
-| **`InvalidateBucket`** | Reset elimination data |
-
-### 3. **[Contract Score Calculator](api-reference/contract.md)**
-
-Routes based on contractual obligations and targets.
-
-| Endpoint | Description |
-|:---------|:------------|
-| **`FetchContractScore`** | Get contract-based scores |
-| **`UpdateContract`** | Update contract fulfillment data |
-| **`InvalidateContract`** | Reset contract data |
-
-### 4. **Health**
-
-System health checks.
-
-| Endpoint | Description |
-|:---------|:------------|
-| **`Check`** | Verify system health status |
-
-**gRPC Method**: `grpc.health.v1.Health/Check`
-
-**HTTP Endpoint**: `POST /grpc.health.v1.Health/Check`
-
-**Request**:
-
-```json
-{
- "service": "dynamo"
-}
-```
-
-**Response**:
-
-```json
-{
- "status": 1 // 1 = SERVING
-}
-```
-
----
-
-## Protocol Support
-
-All services are available via both:
-
-
-
- gRPC
- Efficient binary protocol for direct integration
-
-
- HTTP/JSON
- RESTful interface for broader compatibility
-
-
-
----
-
-## Quick Start Examples
-
-### 🔹 gRPC Example (using grpcurl)
-
-```bash
-grpcurl -d '{
- "id": "merchant_123",
- "params": "{\"payment_method\":\"card\"}",
- "labels": ["processor_A", "processor_B"],
- "config": {
- "min_aggregates_size": 10,
- "default_success_rate": 0.5
- }
-}' \
--H 'x-api-key: YOUR_API_KEY' \
--H 'x-tenant-id: tenant_001' \
--plaintext localhost:9000 success_rate.SuccessRateCalculator/FetchSuccessRate
-```
-
-### 🔹 HTTP Example (using curl)
-
-```bash
-curl -X POST \
- -H "Content-Type: application/json" \
- -H "x-api-key: YOUR_API_KEY" \
- -H "x-tenant-id: tenant_001" \
- -d '{
- "id": "merchant_123",
- "params": "{\"payment_method\":\"card\"}",
- "labels": ["processor_A", "processor_B"],
- "config": {
- "min_aggregates_size": 10,
- "default_success_rate": 0.5
- }
- }' \
- http://localhost:8080/success_rate.SuccessRateCalculator/FetchSuccessRate
-```
-
----
-
-## Error Handling
-
-All services use standard gRPC status codes:
-
-| Status Code | Description | Common Causes |
-|:------------|:------------|:--------------|
-| OK (0) | ✅ Operation completed successfully | Normal successful operation |
-| INVALID_ARGUMENT (3) | ⚠️ Validation failed | Missing required fields, invalid parameters |
-| NOT_FOUND (5) | 🔍 Required resource not found | Entity or configuration not found |
-| UNAUTHENTICATED (16) | 🔒 Authentication failed | Invalid API key |
-| PERMISSION_DENIED (7) | 🚫 Unauthorized access | Insufficient permissions |
-| INTERNAL (13) | ❌ Internal server error | Unexpected server-side errors |
-
----
-
-## Related Documentation
-
-📥 [**Installation**](installation.md) ⚙️ [**Configuration**](configuration.md) 🔄 [**Dual Protocol**](dual-protocol-layer.md)
+## Curl Examples
+For local smoke-test examples, use [API Examples](/api-reference1).
diff --git a/docs/api-reference/contract.md b/docs/api-reference/contract.md
deleted file mode 100644
index fa056339..00000000
--- a/docs/api-reference/contract.md
+++ /dev/null
@@ -1,393 +0,0 @@
-# Contract Routing API Contracts
-
-## Overview
-
-The Contract Score Calculator service provides endpoints for routing payments based on contractual obligations and targets with payment processors. This service is a key component of the Dynamo routing system, helping ensure that payment volumes are distributed according to business agreements while maintaining efficient processing.
-
-## Service Definition
-
-```protobuf
-service ContractScoreCalculator {
- rpc FetchContractScore (CalContractScoreRequest) returns (CalContractScoreResponse);
- rpc UpdateContract (UpdateContractRequest) returns (UpdateContractResponse);
- rpc InvalidateContract (InvalidateContractRequest) returns (InvalidateContractResponse);
-}
-```
-
-## Authentication
-
-All endpoints require authentication. Authentication is handled via metadata in the gRPC request. The service supports multi-tenancy, which means contract data is isolated per tenant.
-
-- Authentication requires an `x-api-key` header with a valid API key
-- The `x-tenant-id` header is required to specify the tenant context
-- Tenant ID is extracted from request metadata
-- All operations verify tenant permissions before processing
-- Multi-tenancy can be enabled/disabled via configuration
-
-## Endpoints
-
-### 1. FetchContractScore
-
-Calculates and returns contract-based routing scores for the provided processors.
-
-#### Request: `CalContractScoreRequest`
-
-```protobuf
-message CalContractScoreRequest {
- string id = 1; // Entity identifier
- string params = 2; // Additional parameters for contract calculation
- repeated string labels = 3; // Labels (processors) to calculate scores for
- CalContractScoreConfig config = 4; // Configuration for calculation
-}
-
-message CalContractScoreConfig {
- repeated double constants = 1; // Constants used in score calculation algorithm
- TimeScale time_scale = 2; // Time scale for contract calculation
-}
-
-message TimeScale {
- enum Scale {
- Day = 0; // Daily time scale
- Month = 1; // Monthly time scale
- }
- Scale time_scale = 1; // Selected time scale
-}
-```
-
-#### Response: `CalContractScoreResponse`
-
-```protobuf
-message CalContractScoreResponse {
- repeated ScoreData labels_with_score = 1; // Contract scores for each label
-}
-
-message ScoreData {
- double score = 1; // Contract score (higher values indicate higher priority)
- string label = 2; // Label (processor) identifier
- uint64 current_count = 3; // Current transaction count for this processor
-}
-```
-
-#### Behavior
-
-- Calculates contract scores based on processor targets and current usage
-- Scores are influenced by how far each processor is from meeting its target
-- Higher scores indicate processors that need more transactions to meet targets
-- Additional parameters can influence the scoring algorithm
-- Returns current transaction counts alongside scores for transparency
-
-#### Process Flow
-
-1. Extract tenant ID from request metadata
-2. Validate the request parameters
-3. Extract entity ID, parameters, and processor labels
-4. Convert the configuration to internal contract score settings
-5. Calculate contract scores for each processor based on current transaction counts and targets
-6. Return detailed score data for each processor
-
----
-
-### 2. UpdateContract
-
-Updates the contract information for specific processors, affecting future contract-based routing decisions.
-
-#### Request: `UpdateContractRequest`
-
-```protobuf
-message UpdateContractRequest {
- string id = 1; // Entity identifier
- string params = 2; // Additional parameters
- repeated LabelInformation labels_information = 3; // Contract information for processors
-}
-
-message LabelInformation {
- string label = 1; // Processor identifier
- uint64 target_count = 2; // Target transaction count in contract
- uint64 target_time = 3; // Time period for the target (in seconds)
- uint64 current_count = 4; // Current transaction count
-}
-```
-
-#### Response: `UpdateContractResponse`
-
-```protobuf
-message UpdateContractResponse {
- enum UpdationStatus {
- CONTRACT_UPDATION_SUCCEEDED = 0;
- CONTRACT_UPDATION_FAILED = 1;
- }
- UpdationStatus status = 1; // Status of the update operation
-}
-```
-
-#### Behavior
-
-- Updates contract information for the specified processors
-- Stores target counts, time periods, and current transaction counts
-- Enables the system to calculate routing scores based on contract fulfillment
-- Contract data is tenant-specific for multi-tenant deployments
-- Returns the status of the update operation
-
-#### Process Flow
-
-1. Extract tenant ID from request metadata
-2. Validate the request parameters
-3. Extract entity ID, parameters, and contract information for processors
-4. Convert the provided data to internal contract map format
-5. Update contract information for all specified processors
-6. Return success/failure status of the operation
-
----
-
-### 3. InvalidateContract
-
-Invalidates all contract data for a specific entity, effectively resetting its contract-based routing state.
-
-#### Request: `InvalidateContractRequest`
-
-```protobuf
-message InvalidateContractRequest {
- string id = 1; // Entity identifier to invalidate
-}
-```
-
-#### Response: `InvalidateContractResponse`
-
-```protobuf
-message InvalidateContractResponse {
- enum InvalidationStatus {
- CONTRACT_INVALIDATION_SUCCEEDED = 0;
- CONTRACT_INVALIDATION_FAILED = 1;
- }
- InvalidationStatus status = 1; // Status of the invalidation operation
-}
-```
-
-#### Behavior
-
-- Removes all contract data for the specified entity
-- This effectively resets the contract-based routing for this entity
-- Useful when contracts are renewed or significantly changed
-- Does not affect contract data for other entities
-- Returns the status of the invalidation operation
-
-#### Process Flow
-
-1. Extract tenant ID from request metadata
-2. Validate the request parameters
-3. Extract entity ID to invalidate
-4. Remove all contract data for the entity within the tenant context
-5. Return success/failure status of the operation
-
-## Error Handling
-
-All endpoints return standard gRPC status codes:
-
-| Status Code | Description | When Used |
-|-------------|-------------|-----------|
-| `OK (0)` | Operation completed successfully | Normal successful operation |
-| `NOT_FOUND (5)` | Required resource not found | Missing configuration, entity not found |
-| `INVALID_ARGUMENT (3)` | Validation failed | Invalid or missing required parameters |
-| `UNAUTHENTICATED (16)` | Authentication failed | Invalid or missing authentication credentials |
-| `PERMISSION_DENIED (7)` | Authenticated user lacks permission | User not authorized for the operation |
-| `INTERNAL (13)` | Internal server error | Unexpected errors during processing |
-
-## Multi-tenancy Support
-
-The service supports multi-tenancy with the following behavior:
-
-- All contract data is isolated per tenant with no cross-tenant data access
-- Tenant ID is extracted from request metadata
-- Each tenant has its own contract settings and transaction counts
-- Multi-tenancy can be disabled in configuration via `is_multi_tenancy_enabled` flag
-- When disabled, a default tenant ID is used
-
-## Performance Considerations
-
-- **Efficient Scoring Algorithm**: The contract score calculation is optimized for performance
-- **Persistent Storage**: Contract data is stored efficiently for quick access
-- **Parallel Processing**: The system can handle multiple contract score calculations simultaneously
-- **Request Validation**: Validates requests early to fail fast and save processing resources
-- **Rust Implementation**: Implementation is in Rust for maximum efficiency and safety
-- **Error Handling**: Comprehensive error handling with detailed context
-
-## Example Usage
-
-### Fetch Contract Score Example
-
-```json
-// Request
-{
- "id": "merchant_123",
- "params": "{\"payment_type\":\"card\"}",
- "labels": ["processor_A", "processor_B", "processor_C"],
- "config": {
- "constants": [0.75, 1.25, 0.5],
- "time_scale": {
- "time_scale": "Month"
- }
- }
-}
-
-// Response
-{
- "labels_with_score": [
- {
- "score": 0.85,
- "label": "processor_B",
- "current_count": 7520
- },
- {
- "score": 0.65,
- "label": "processor_A",
- "current_count": 12450
- },
- {
- "score": 0.42,
- "label": "processor_C",
- "current_count": 9870
- }
- ]
-}
-```
-
-### Update Contract Example
-
-```json
-// Request
-{
- "id": "merchant_123",
- "params": "{\"payment_type\":\"card\"}",
- "labels_information": [
- {
- "label": "processor_A",
- "target_count": 15000,
- "target_time": 2592000,
- "current_count": 12450
- },
- {
- "label": "processor_B",
- "target_count": 10000,
- "target_time": 2592000,
- "current_count": 7520
- },
- {
- "label": "processor_C",
- "target_count": 12000,
- "target_time": 2592000,
- "current_count": 9870
- }
- ]
-}
-
-// Response
-{
- "status": "CONTRACT_UPDATION_SUCCEEDED"
-}
-```
-
-### Invalidate Contract Example
-
-```json
-// Request
-{
- "id": "merchant_123"
-}
-
-// Response
-{
- "status": "CONTRACT_INVALIDATION_SUCCEEDED"
-}
-```
-
-## Integration Notes
-
-- All requests should include appropriate authentication metadata
-- JSON parameters in the `params` field should be properly escaped
-- Contract targets should be set realistically based on historical processing volumes
-- Target times should align with billing cycles (typically monthly)
-- Contract-based routing works best when combined with success rate and elimination routing
-- Maintain proper error handling for all API calls
-- Consider resetting contracts at the beginning of each billing cycle
-
-## gRPCurl Examples
-
-The following examples demonstrate how to call the Contract Score Calculator API endpoints using gRPCurl. These examples assume the service is running on localhost at port 9000.
-
-### FetchContractScore
-
-```bash
-grpcurl -plaintext -d '{
- "id": "merchant_123",
- "params": "{\"payment_type\":\"card\"}",
- "labels": ["processor_A", "processor_B", "processor_C"],
- "config": {
- "constants": [0.75, 1.25, 0.5],
- "time_scale": {
- "time_scale": "Month"
- }
- }
-}' \
--H 'x-api-key: YOUR_API_KEY' \
--H 'x-tenant-id: tenant_001' \
-localhost:9000 contract_routing.ContractScoreCalculator/FetchContractScore
-```
-
-### UpdateContract
-
-```bash
-grpcurl -plaintext -d '{
- "id": "merchant_123",
- "params": "{\"payment_type\":\"card\"}",
- "labels_information": [
- {
- "label": "processor_A",
- "target_count": 15000,
- "target_time": 2592000,
- "current_count": 12450
- },
- {
- "label": "processor_B",
- "target_count": 10000,
- "target_time": 2592000,
- "current_count": 7520
- },
- {
- "label": "processor_C",
- "target_count": 12000,
- "target_time": 2592000,
- "current_count": 9870
- }
- ]
-}' \
--H 'x-api-key: YOUR_API_KEY' \
--H 'x-tenant-id: tenant_001' \
-localhost:9000 contract_routing.ContractScoreCalculator/UpdateContract
-```
-
-### InvalidateContract
-
-```bash
-grpcurl -plaintext -d '{
- "id": "merchant_123"
-}' \
--H 'x-api-key: YOUR_API_KEY' \
--H 'x-tenant-id: tenant_001' \
-localhost:9000 contract_routing.ContractScoreCalculator/InvalidateContract
-```
-
-### Listing Available Methods
-
-To discover available methods on the service:
-
-```bash
-grpcurl -plaintext localhost:9000 list contract_routing.ContractScoreCalculator
-```
-
-### Viewing Method Details
-
-To see detailed information about a specific method:
-
-```bash
-grpcurl -plaintext localhost:9000 describe contract_routing.ContractScoreCalculator.FetchContractScore
-```
diff --git a/docs/api-reference/elimination.md b/docs/api-reference/elimination.md
deleted file mode 100644
index 0a89a8a8..00000000
--- a/docs/api-reference/elimination.md
+++ /dev/null
@@ -1,404 +0,0 @@
-# Elimination Routing API Contracts
-
-## Overview
-
-The Elimination Analyser service provides endpoints for identifying and filtering out underperforming payment processors. This service is a critical component of the Dynamo routing system, helping improve payment success rates by preventing routing to processors with consistently high failure rates.
-
-## Service Definition
-
-```protobuf
-service EliminationAnalyser {
- rpc GetEliminationStatus (EliminationRequest) returns (EliminationResponse);
- rpc UpdateEliminationBucket (UpdateEliminationBucketRequest) returns (UpdateEliminationBucketResponse);
- rpc InvalidateBucket (InvalidateBucketRequest) returns (InvalidateBucketResponse);
-}
-```
-
-## Authentication
-
-All endpoints require authentication. Authentication is handled via metadata in the gRPC request. The service supports multi-tenancy, which means elimination data is isolated per tenant.
-
-- Authentication requires an `x-api-key` header with a valid API key
-- The `x-tenant-id` header is required to specify the tenant context
-- Tenant ID is extracted from request metadata
-- All operations verify tenant permissions before processing
-- Multi-tenancy can be enabled/disabled via configuration
-
-## Endpoints
-
-### 1. GetEliminationStatus
-
-Determines which processors should be eliminated from routing consideration based on historical performance data.
-
-#### Request: `EliminationRequest`
-
-```protobuf
-message EliminationRequest {
- string id = 1; // Entity identifier
- string params = 2; // Additional parameters for elimination analysis
- repeated string labels = 3; // Labels (processors) to check for elimination
- EliminationBucketConfig config = 4; // Configuration for elimination buckets
-}
-
-message EliminationBucketConfig {
- uint64 bucket_size = 1; // Maximum failures allowed before elimination
- uint64 bucket_leak_interval_in_secs = 2; // Time interval after which failures are "forgotten"
-}
-```
-
-#### Response: `EliminationResponse`
-
-```protobuf
-message EliminationResponse {
- repeated LabelWithStatus labels_with_status = 1; // Elimination status for each label
-}
-
-message LabelWithStatus {
- string label = 1; // Label identifier
- EliminationInformation elimination_information = 2; // Elimination details
-}
-
-message EliminationInformation {
- BucketInformation entity = 1; // Entity-specific elimination information
- BucketInformation global = 2; // Global elimination information
-}
-
-message BucketInformation {
- bool is_eliminated = 1; // Whether the processor should be eliminated
- repeated string bucket_name = 2; // Bucket identifiers that triggered elimination
-}
-```
-
-#### Behavior
-
-- Evaluates each processor (label) against failure thresholds at both entity and global levels
-- Returns elimination status for each processor along with the specific buckets triggering elimination
-- A processor can be eliminated at entity level, global level, or both
-- Bucket information provides context about which failure conditions were met
-
-#### Process Flow
-
-1. Extract tenant ID from request metadata
-2. Validate the request parameters
-3. Extract entity ID, parameters, and processor labels
-4. Convert the configuration to internal elimination bucket settings
-5. Perform elimination analysis for each processor
-6. Return detailed elimination status for each processor
-
----
-
-### 2. UpdateEliminationBucket
-
-Updates the failure records for specific processors, affecting future elimination decisions.
-
-#### Request: `UpdateEliminationBucketRequest`
-
-```protobuf
-message UpdateEliminationBucketRequest {
- string id = 1; // Entity identifier
- string params = 2; // Additional parameters
- repeated LabelWithBucketName labels_with_bucket_name = 3; // Processors with bucket information
- EliminationBucketConfig config = 4; // Configuration for elimination buckets
-}
-
-message LabelWithBucketName {
- string label = 1; // Processor identifier
- string bucket_name = 2; // Bucket to update (failure type)
-}
-
-message EliminationBucketConfig {
- uint64 bucket_size = 1; // Maximum failures allowed before elimination
- uint64 bucket_leak_interval_in_secs = 2; // Time interval after which failures are "forgotten"
-}
-```
-
-#### Response: `UpdateEliminationBucketResponse`
-
-```protobuf
-message UpdateEliminationBucketResponse {
- enum UpdationStatus {
- BUCKET_UPDATION_SUCCEEDED = 0;
- BUCKET_UPDATION_FAILED = 1;
- }
- UpdationStatus status = 1; // Status of the update operation
-}
-```
-
-#### Behavior
-
-- Updates failure records for the specified processors and buckets
-- Each bucket represents a specific failure type or condition
-- Uses a "leaky bucket" algorithm where failures are counted until thresholds are met
-- After the specified leak interval, failures are gradually removed from consideration
-- Failure to update any processor's bucket will result in a failed status
-
-#### Process Flow
-
-1. Extract tenant ID from request metadata
-2. Validate the request parameters
-3. Extract entity ID, parameters, and processor-bucket mapping
-4. Convert the configuration to internal elimination bucket settings
-5. Update the elimination buckets for each processor
-6. Return success/failure status of the operation
-
----
-
-### 3. InvalidateBucket
-
-Invalidates all elimination bucket data for a specific entity, effectively resetting its processor elimination history.
-
-#### Request: `InvalidateBucketRequest`
-
-```protobuf
-message InvalidateBucketRequest {
- string id = 1; // Entity identifier to invalidate
-}
-```
-
-#### Response: `InvalidateBucketResponse`
-
-```protobuf
-message InvalidateBucketResponse {
- enum InvalidationStatus {
- BUCKET_INVALIDATION_SUCCEEDED = 0;
- BUCKET_INVALIDATION_FAILED = 1;
- }
- InvalidationStatus status = 1; // Status of the invalidation operation
-}
-```
-
-#### Behavior
-
-- Removes all elimination bucket data for the specified entity
-- This effectively resets the elimination status for all processors associated with the entity
-- Useful for handling significant processor changes or clearing problematic data
-- Does not affect global elimination data
-
-#### Process Flow
-
-1. Extract tenant ID from request metadata
-2. Validate the request parameters
-3. Extract entity ID to invalidate
-4. Remove all elimination bucket data for the entity
-5. Return success/failure status of the operation
-
-## Error Handling
-
-All endpoints return standard gRPC status codes:
-
-| Status Code | Description | When Used |
-|-------------|-------------|-----------|
-| `OK (0)` | Operation completed successfully | Normal successful operation |
-| `NOT_FOUND (5)` | Required resource not found | Missing configuration, entity not found |
-| `INVALID_ARGUMENT (3)` | Validation failed | Invalid or missing required parameters |
-| `UNAUTHENTICATED (16)` | Authentication failed | Invalid or missing authentication credentials |
-| `PERMISSION_DENIED (7)` | Authenticated user lacks permission | User not authorized for the operation |
-| `INTERNAL (13)` | Internal server error | Unexpected errors during processing |
-
-## Multi-tenancy Support
-
-The service supports multi-tenancy with the following behavior:
-
-- All elimination data is isolated per tenant with no cross-tenant data access
-- Tenant ID is extracted from request metadata
-- Each tenant has its own elimination buckets and configurations
-- Multi-tenancy can be disabled in configuration via `is_multi_tenancy_enabled` flag
-- When disabled, a default tenant ID is used
-
-## Performance Considerations
-
-- **Leaky Bucket Algorithm**: Efficiently tracks failures without unlimited growth of data
-- **Time-based Processing**: Automatically ages out old failures based on configuration
-- **Optimized Storage**: Buckets are stored efficiently to minimize memory usage
-- **Concurrent Processing**: Handles multiple elimination checks in parallel
-- **Rust Implementation**: Implementation is in Rust for maximum efficiency and safety
-- **Request Validation**: Validates requests early to fail fast and save processing resources
-
-## Example Usage
-
-### Get Elimination Status Example
-
-```json
-// Request
-{
- "id": "merchant_123",
- "params": "{\"payment_method\":\"card\"}",
- "labels": ["processor_A", "processor_B", "processor_C"],
- "config": {
- "bucket_size": 5,
- "bucket_leak_interval_in_secs": 3600
- }
-}
-
-// Response
-{
- "labels_with_status": [
- {
- "label": "processor_A",
- "elimination_information": {
- "entity": {
- "is_eliminated": false,
- "bucket_name": []
- },
- "global": {
- "is_eliminated": false,
- "bucket_name": []
- }
- }
- },
- {
- "label": "processor_B",
- "elimination_information": {
- "entity": {
- "is_eliminated": true,
- "bucket_name": ["authentication_failure"]
- },
- "global": {
- "is_eliminated": false,
- "bucket_name": []
- }
- }
- },
- {
- "label": "processor_C",
- "elimination_information": {
- "entity": {
- "is_eliminated": true,
- "bucket_name": ["network_error"]
- },
- "global": {
- "is_eliminated": true,
- "bucket_name": ["network_error", "timeout"]
- }
- }
- }
- ]
-}
-```
-
-### Update Elimination Bucket Example
-
-```json
-// Request
-{
- "id": "merchant_123",
- "params": "{\"payment_method\":\"card\"}",
- "labels_with_bucket_name": [
- {
- "label": "processor_A",
- "bucket_name": "authentication_failure"
- },
- {
- "label": "processor_B",
- "bucket_name": "network_error"
- }
- ],
- "config": {
- "bucket_size": 5,
- "bucket_leak_interval_in_secs": 3600
- }
-}
-
-// Response
-{
- "status": "BUCKET_UPDATION_SUCCEEDED"
-}
-```
-
-### Invalidate Bucket Example
-
-```json
-// Request
-{
- "id": "merchant_123"
-}
-
-// Response
-{
- "status": "BUCKET_INVALIDATION_SUCCEEDED"
-}
-```
-
-## Integration Notes
-
-- All requests should include appropriate authentication metadata
-- JSON parameters in the `params` field should be properly escaped
-- Bucket names should represent meaningful failure categories for better analytics
-- Consider the bucket_size and leak interval carefully based on traffic patterns
-- Very small bucket sizes may lead to premature elimination
-- Very large leak intervals may keep processors eliminated for too long
-- Maintain proper error handling for all API calls
-
-## gRPCurl Examples
-
-The following examples demonstrate how to call the Elimination Analyser API endpoints using gRPCurl. These examples assume the service is running on localhost at port 9000.
-
-### GetEliminationStatus
-
-```bash
-grpcurl -plaintext -d '{
- "id": "merchant_123",
- "params": "{\"payment_method\":\"card\"}",
- "labels": ["processor_A", "processor_B", "processor_C"],
- "config": {
- "bucket_size": 5,
- "bucket_leak_interval_in_secs": 3600
- }
-}' \
--H 'x-api-key: YOUR_API_KEY' \
--H 'x-tenant-id: tenant_001' \
-localhost:9000 elimination.EliminationAnalyser/GetEliminationStatus
-```
-
-### UpdateEliminationBucket
-
-```bash
-grpcurl -plaintext -d '{
- "id": "merchant_123",
- "params": "{\"payment_method\":\"card\"}",
- "labels_with_bucket_name": [
- {
- "label": "processor_A",
- "bucket_name": "authentication_failure"
- },
- {
- "label": "processor_B",
- "bucket_name": "network_error"
- }
- ],
- "config": {
- "bucket_size": 5,
- "bucket_leak_interval_in_secs": 3600
- }
-}' \
--H 'x-api-key: YOUR_API_KEY' \
--H 'x-tenant-id: tenant_001' \
-localhost:9000 elimination.EliminationAnalyser/UpdateEliminationBucket
-```
-
-### InvalidateBucket
-
-```bash
-grpcurl -plaintext -d '{
- "id": "merchant_123"
-}' \
--H 'x-api-key: YOUR_API_KEY' \
--H 'x-tenant-id: tenant_001' \
-localhost:9000 elimination.EliminationAnalyser/InvalidateBucket
-```
-
-### Listing Available Methods
-
-To discover available methods on the service:
-
-```bash
-grpcurl -plaintext localhost:9000 list elimination.EliminationAnalyser
-```
-
-### Viewing Method Details
-
-To see detailed information about a specific method:
-
-```bash
-grpcurl -plaintext localhost:9000 describe elimination.EliminationAnalyser.GetEliminationStatus
-```
diff --git a/docs/api-reference/endpoint/activateRoutingRule.mdx b/docs/api-reference/endpoint/activateRoutingRule.mdx
new file mode 100644
index 00000000..dae80c51
--- /dev/null
+++ b/docs/api-reference/endpoint/activateRoutingRule.mdx
@@ -0,0 +1,7 @@
+---
+title: "Activate Routing Rule"
+description: "Activate an existing routing algorithm for a given created_by scope."
+openapi: "POST /routing/activate"
+---
+
+Use this endpoint to make a routing algorithm active for the supplied `created_by` value.
diff --git a/docs/api-reference/endpoint/createMerchant.mdx b/docs/api-reference/endpoint/createMerchant.mdx
new file mode 100644
index 00000000..5a67650a
--- /dev/null
+++ b/docs/api-reference/endpoint/createMerchant.mdx
@@ -0,0 +1,7 @@
+---
+title: "Create Merchant"
+description: "Create a merchant account used by later routing and scoring requests."
+openapi: "POST /merchant-account/create"
+---
+
+Use this endpoint before calling routing or score-feedback APIs for a new merchant.
diff --git a/docs/api-reference/endpoint/createRoutingRule.mdx b/docs/api-reference/endpoint/createRoutingRule.mdx
new file mode 100644
index 00000000..ae6c07f9
--- /dev/null
+++ b/docs/api-reference/endpoint/createRoutingRule.mdx
@@ -0,0 +1,31 @@
+---
+title: "Create Routing Rule"
+description: "Create a routing algorithm for a given created_by scope."
+openapi: "POST /routing/create"
+---
+
+Use this endpoint to store a priority, single, volume-split, or advanced routing algorithm.
+
+## Supported algorithm shapes
+
+- `priority`: ordered connector fallback list.
+- `single`: pin the route to exactly one connector.
+- `volume_split`: distribute traffic by weighted percentages.
+- `advanced`: Euclid program for conditional routing.
+
+For `advanced` rules:
+
+- each item in `statements` is an `OR` branch
+- each item inside a single `condition` array is an `AND` block
+- `nested` lets you build deeper hierarchical checks under a matched branch
+- `default_selection` is the fallback when no rule matches
+
+The OpenAPI examples on this page include:
+
+- `priority`
+- `single`
+- `volume_split`
+- `advanced` with top-level `OR` branches
+- `advanced` with nested conditions and a volume-split output
+
+If you want curl-ready payloads for each of those variants, use [API Examples](/api-reference1).
diff --git a/docs/api-reference/endpoint/createRuleConfig.mdx b/docs/api-reference/endpoint/createRuleConfig.mdx
new file mode 100644
index 00000000..20ec9bc7
--- /dev/null
+++ b/docs/api-reference/endpoint/createRuleConfig.mdx
@@ -0,0 +1,7 @@
+---
+title: "Create Rule Config"
+description: "Create service-level rule configuration such as success-rate settings."
+openapi: "POST /rule/create"
+---
+
+Use this endpoint to create routing configuration tied to a merchant.
diff --git a/docs/api-reference/endpoint/decideGateway.mdx b/docs/api-reference/endpoint/decideGateway.mdx
new file mode 100644
index 00000000..bd264449
--- /dev/null
+++ b/docs/api-reference/endpoint/decideGateway.mdx
@@ -0,0 +1,7 @@
+---
+title: "Decide Gateway"
+description: "Evaluate the current routing logic for a payment context and eligible gateway list."
+openapi: "POST /decide-gateway"
+---
+
+This is the main routing decision endpoint exposed by the service.
diff --git a/docs/api-reference/endpoint/deleteMerchant.mdx b/docs/api-reference/endpoint/deleteMerchant.mdx
new file mode 100644
index 00000000..4408d8e3
--- /dev/null
+++ b/docs/api-reference/endpoint/deleteMerchant.mdx
@@ -0,0 +1,7 @@
+---
+title: "Delete Merchant"
+description: "Delete a merchant account by ID."
+openapi: "DELETE /merchant-account/{merchantId}"
+---
+
+Use this endpoint to remove a merchant record and its associated service-level configuration.
diff --git a/docs/api-reference/endpoint/deleteRuleConfig.mdx b/docs/api-reference/endpoint/deleteRuleConfig.mdx
new file mode 100644
index 00000000..0f2b8b1e
--- /dev/null
+++ b/docs/api-reference/endpoint/deleteRuleConfig.mdx
@@ -0,0 +1,7 @@
+---
+title: "Delete Rule Config"
+description: "Delete service-level routing configuration for a merchant."
+openapi: "POST /rule/delete"
+---
+
+Use this endpoint when a stored rule configuration should no longer apply.
diff --git a/docs/api-reference/endpoint/evaluateRoutingRule.mdx b/docs/api-reference/endpoint/evaluateRoutingRule.mdx
new file mode 100644
index 00000000..01254a1c
--- /dev/null
+++ b/docs/api-reference/endpoint/evaluateRoutingRule.mdx
@@ -0,0 +1,7 @@
+---
+title: "Evaluate Routing Rule"
+description: "Evaluate the active routing rule without calling the gateway-selection API."
+openapi: "POST /routing/evaluate"
+---
+
+Use this endpoint to inspect routing-rule output for a payment context.
diff --git a/docs/api-reference/endpoint/getActiveRoutingRule.mdx b/docs/api-reference/endpoint/getActiveRoutingRule.mdx
new file mode 100644
index 00000000..8453d0e8
--- /dev/null
+++ b/docs/api-reference/endpoint/getActiveRoutingRule.mdx
@@ -0,0 +1,7 @@
+---
+title: "Get Active Routing Rule"
+description: "Fetch the currently active routing rule for a created_by scope."
+openapi: "POST /routing/list/active/{created_by}"
+---
+
+Use this endpoint to inspect which routing algorithm is currently active.
diff --git a/docs/api-reference/endpoint/getMerchant.mdx b/docs/api-reference/endpoint/getMerchant.mdx
new file mode 100644
index 00000000..ec3e6976
--- /dev/null
+++ b/docs/api-reference/endpoint/getMerchant.mdx
@@ -0,0 +1,7 @@
+---
+title: "Get Merchant"
+description: "Retrieve a merchant account by ID."
+openapi: "GET /merchant-account/{merchantId}"
+---
+
+Use this endpoint to inspect the stored merchant account record.
diff --git a/docs/api-reference/endpoint/getRuleConfig.mdx b/docs/api-reference/endpoint/getRuleConfig.mdx
new file mode 100644
index 00000000..a00375a2
--- /dev/null
+++ b/docs/api-reference/endpoint/getRuleConfig.mdx
@@ -0,0 +1,7 @@
+---
+title: "Get Rule Config"
+description: "Fetch service-level routing configuration for a merchant."
+openapi: "POST /rule/get"
+---
+
+Use this endpoint to inspect the currently stored rule configuration for a merchant.
diff --git a/docs/api-reference/endpoint/healthCheck.mdx b/docs/api-reference/endpoint/healthCheck.mdx
new file mode 100644
index 00000000..c58182b5
--- /dev/null
+++ b/docs/api-reference/endpoint/healthCheck.mdx
@@ -0,0 +1,7 @@
+---
+title: "Health Check"
+description: "Verify that the main API server is responding."
+openapi: "GET /health"
+---
+
+Use this endpoint for the simplest local or deployment liveness check.
diff --git a/docs/api-reference/endpoint/listRoutingRules.mdx b/docs/api-reference/endpoint/listRoutingRules.mdx
new file mode 100644
index 00000000..c71d203e
--- /dev/null
+++ b/docs/api-reference/endpoint/listRoutingRules.mdx
@@ -0,0 +1,7 @@
+---
+title: "List Routing Rules"
+description: "List stored routing algorithms for a created_by scope."
+openapi: "POST /routing/list/{created_by}"
+---
+
+Use this endpoint to inspect the routing algorithms stored for a merchant or platform scope.
diff --git a/docs/api-reference/endpoint/updateGatewayScore.mdx b/docs/api-reference/endpoint/updateGatewayScore.mdx
new file mode 100644
index 00000000..ff080b2e
--- /dev/null
+++ b/docs/api-reference/endpoint/updateGatewayScore.mdx
@@ -0,0 +1,7 @@
+---
+title: "Update Gateway Score"
+description: "Record a transaction outcome for later routing decisions."
+openapi: "POST /update-gateway-score"
+---
+
+Use this endpoint after a payment outcome is known so score data can be updated.
diff --git a/docs/api-reference/endpoint/updateRuleConfig.mdx b/docs/api-reference/endpoint/updateRuleConfig.mdx
new file mode 100644
index 00000000..8c194563
--- /dev/null
+++ b/docs/api-reference/endpoint/updateRuleConfig.mdx
@@ -0,0 +1,7 @@
+---
+title: "Update Rule Config"
+description: "Update stored service-level routing configuration for a merchant."
+openapi: "POST /rule/update"
+---
+
+Use this endpoint to modify an existing rule configuration without recreating it.
diff --git a/docs/api-reference/success-rate.md b/docs/api-reference/success-rate.md
deleted file mode 100644
index baa073f2..00000000
--- a/docs/api-reference/success-rate.md
+++ /dev/null
@@ -1,485 +0,0 @@
-# Success Rate API Contracts
-
-## Overview
-
-The Success Rate Calculator service provides endpoints for calculating, updating, and managing success rates for payment routing decisions. This service is a core component of the Dynamo routing system, helping optimize payment flows by directing transactions to processors with the highest historical success rates.
-
-## Service Definition
-
-```protobuf
-service SuccessRateCalculator {
- rpc FetchSuccessRate (CalSuccessRateRequest) returns (CalSuccessRateResponse);
- rpc UpdateSuccessRateWindow (UpdateSuccessRateWindowRequest) returns (UpdateSuccessRateWindowResponse);
- rpc InvalidateWindows (InvalidateWindowsRequest) returns (InvalidateWindowsResponse);
- rpc FetchEntityAndGlobalSuccessRate (CalGlobalSuccessRateRequest) returns (CalGlobalSuccessRateResponse);
-}
-```
-
-## Authentication
-
-All endpoints require authentication. Authentication is handled via metadata in the gRPC request. The service supports multi-tenancy, which means data and routing decisions are isolated per tenant.
-
-- Authentication is performed using the `Authenticate` trait
-- Authentication requires an `x-api-key` header with a valid API key
-- The `x-tenant-id` header is required to specify the tenant context
-- Tenant and merchant IDs are extracted from authentication info
-- All operations verify authentication before processing
-
-## Endpoints
-
-### 1. FetchSuccessRate
-
-Calculates and returns success rates for a specific entity and its associated labels.
-
-#### Request: `CalSuccessRateRequest`
-
-```protobuf
-message CalSuccessRateRequest {
- string id = 1; // Entity identifier
- string params = 2; // Additional parameters for success rate calculation
- repeated string labels = 3; // Labels to calculate success rates for
- CalSuccessRateConfig config = 4; // Configuration for calculation
-}
-
-message CalSuccessRateConfig {
- uint32 min_aggregates_size = 1; // Minimum number of data points required
- double default_success_rate = 2; // Default rate to use if insufficient data
- optional SuccessRateSpecificityLevel specificity_level = 3; // ENTITY or GLOBAL level
-}
-
-enum SuccessRateSpecificityLevel {
- ENTITY = 0;
- GLOBAL = 1;
-}
-```
-
-#### Response: `CalSuccessRateResponse`
-
-```protobuf
-message CalSuccessRateResponse {
- repeated LabelWithScore labels_with_score = 1; // Success rates for each label
-}
-
-message LabelWithScore {
- double score = 1; // Success rate score (0.0 to 1.0)
- string label = 2; // Label identifier
-}
-```
-
-#### Behavior
-
-- Returns calculated success rates for requested labels based on historical data
-- If insufficient data exists for a label, uses the default success rate
-- Applied specificity level determines if entity-specific or global data is used
-- Success rates are returned as scores between 0.0 and 1.0 (or as percentages)
-- Labels are returned in descending order of scores
-
-#### Process Flow
-
-1. Authenticate the request and extract tenant/merchant information
-2. Fetch configuration settings for the tenant
-3. Extract tenant ID from request (for multi-tenancy support)
-4. Validate the request parameters
-5. Extract entity ID, parameters, and labels
-6. Calculate success rates based on historical data
-7. Return the scores with associated labels
-
-#### Metrics
-
-- `SUCCESS_BASED_ROUTING_REQUEST`: Counts total requests
-- `SUCCESS_BASED_ROUTING_DECISION_REQUEST_TIME`: Measures processing time
-- `SUCCESS_BASED_ROUTING_SUCCESSFUL_RESPONSE_COUNT`: Counts successful responses
-
----
-
-### 2. UpdateSuccessRateWindow
-
-Updates the success/failure status for a set of labels, affecting future routing decisions.
-
-#### Request: `UpdateSuccessRateWindowRequest`
-
-```protobuf
-message UpdateSuccessRateWindowRequest {
- string id = 1; // Entity identifier
- string params = 2; // Additional parameters
- repeated LabelWithStatus labels_with_status = 3; // Entity-specific labels with success/failure status
- UpdateSuccessRateWindowConfig config = 4; // Update configuration
- repeated LabelWithStatus global_labels_with_status = 5; // Global labels with success/failure status
-}
-
-message LabelWithStatus {
- string label = 1; // Label identifier
- bool status = 2; // Success (true) or failure (false) status
-}
-
-message UpdateSuccessRateWindowConfig {
- uint32 max_aggregates_size = 1; // Maximum size of aggregation window
- CurrentBlockThreshold current_block_threshold = 2; // Threshold configuration
-}
-
-message CurrentBlockThreshold {
- optional uint64 duration_in_mins = 1; // Duration-based threshold in minutes
- uint64 max_total_count = 2; // Count-based threshold
-}
-```
-
-#### Response: `UpdateSuccessRateWindowResponse`
-
-```protobuf
-message UpdateSuccessRateWindowResponse {
- enum UpdationStatus {
- WINDOW_UPDATION_SUCCEEDED = 0;
- WINDOW_UPDATION_FAILED = 1;
- }
- UpdationStatus status = 1; // Status of the update operation
-}
-```
-
-#### Behavior
-
-- Updates both entity-specific and global success rate windows
-- Applies the provided status (success/failure) to each label
-- Maintains a sliding window of transaction results based on configuration
-- Will return failure status if either entity or global updates fail
-- Uses configured thresholds to determine when to rotate windows
-
-#### Process Flow
-
-1. Authenticate the request and extract tenant/merchant information
-2. Fetch configuration settings for the tenant
-3. Extract tenant ID from request (for multi-tenancy support)
-4. Validate the request parameters
-5. Extract entity ID, parameters, and label status information
-6. Update the entity-specific success rate window
-7. Set the specificity level to Global
-8. Update the global success rate window
-9. Return success/failure status of the operation
-
-#### Metrics
-
-- `SUCCESS_BASED_ROUTING_UPDATE_WINDOW_DECISION_REQUEST_TIME`: Measures processing time
-- `SUCCESS_BASED_ROUTING_UPDATE_WINDOW_COUNT`: Counts window update requests
-
----
-
-### 3. InvalidateWindows
-
-Invalidates success rate windows for a specific entity, effectively resetting its success rate history.
-
-#### Request: `InvalidateWindowsRequest`
-
-```protobuf
-message InvalidateWindowsRequest {
- string id = 1; // Entity identifier to invalidate
-}
-```
-
-#### Response: `InvalidateWindowsResponse`
-
-```protobuf
-message InvalidateWindowsResponse {
- enum InvalidationStatus {
- WINDOW_INVALIDATION_SUCCEEDED = 0;
- WINDOW_INVALIDATION_FAILED = 1;
- }
- InvalidationStatus status = 1; // Status of the invalidation operation
-}
-```
-
-#### Behavior
-
-- Removes all success rate window data for the specified entity
-- This effectively resets the success rate calculation for this entity
-- Useful for handling significant processor changes or clearing problematic data
-- Does not affect global success rate data
-
-#### Process Flow
-
-1. Authenticate the request
-2. Extract tenant ID from request (for multi-tenancy support)
-3. Validate the request parameters
-4. Extract entity ID to invalidate
-5. Remove all success rate window data for the entity
-6. Return success/failure status of the operation
-
----
-
-### 4. FetchEntityAndGlobalSuccessRate
-
-Fetches both entity-specific and global success rates in a single request.
-
-#### Request: `CalGlobalSuccessRateRequest`
-
-```protobuf
-message CalGlobalSuccessRateRequest {
- string entity_id = 1; // Entity identifier
- string entity_params = 2; // Entity-specific parameters
- repeated string entity_labels = 3; // Labels for entity-specific calculation
- repeated string global_labels = 4; // Labels for global calculation
- CalGlobalSuccessRateConfig config = 5; // Configuration
-}
-
-message CalGlobalSuccessRateConfig {
- uint32 entity_min_aggregates_size = 1; // Minimum aggregates for entity calculation
- double entity_default_success_rate = 2; // Default success rate for entity
-}
-```
-
-#### Response: `CalGlobalSuccessRateResponse`
-
-```protobuf
-message CalGlobalSuccessRateResponse {
- repeated LabelWithScore entity_scores_with_labels = 1; // Entity-specific success rates
- repeated LabelWithScore global_scores_with_labels = 2; // Global success rates
-}
-```
-
-#### Behavior
-
-- Performs parallel calculation of both entity and global success rates
-- Allows for comparison between entity-specific and global performance
-- Useful for analytics and decision-making about routing strategies
-- Returns both sets of scores ordered by success rate
-
-#### Process Flow
-
-1. Authenticate the request
-2. Extract tenant ID from request (for multi-tenancy support)
-3. Validate the request parameters
-4. Extract entity ID, parameters, and labels for both entity and global calculations
-5. Create entity-specific and global configurations
-6. Perform both calculations in parallel using tokio::try_join!
-7. Format the results into the response structure
-8. Return both sets of success rates
-
-#### Metrics
-
-- `SUCCESS_BASED_ROUTING_METRICS_REQUEST`: Counts metrics requests
-- `SUCCESS_BASED_ROUTING_METRICS_DECISION_REQUEST_TIME`: Measures processing time
-- `SUCCESS_BASED_ROUTING__METRICS_SUCCESSFUL_RESPONSE_COUNT`: Counts successful responses
-
-## Error Handling
-
-All endpoints return standard gRPC status codes:
-
-| Status Code | Description | When Used |
-| ----------------------- | ----------------------------------- | --------------------------------------------- |
-| `OK (0)` | Operation completed successfully | Normal successful operation |
-| `NOT_FOUND (5)` | Required resource not found | Missing configuration, entity not found |
-| `INVALID_ARGUMENT (3)` | Validation failed | Invalid or missing required parameters |
-| `UNAUTHENTICATED (16)` | Authentication failed | Invalid or missing authentication credentials |
-| `PERMISSION_DENIED (7)` | Authenticated user lacks permission | User not authorized for the operation |
-| `INTERNAL (13)` | Internal server error | Unexpected errors during processing |
-
-## Multi-tenancy Support
-
-The service supports multi-tenancy with the following behavior:
-
-- All data is isolated per tenant with no cross-tenant data access
-- Tenant ID is extracted from request metadata using authentication info
-- Each tenant has its own success rate windows and calculations
-- Multi-tenancy can be disabled in configuration via `is_multi_tenancy_enabled` flag
-- When disabled, a default tenant ID is used
-
-## Performance Considerations
-
-- **Optimized Processing**: The service is optimized for high throughput and low latency
-- **Caching**: Success rate calculations are cached for performance
-- **Efficient Storage**: Windows are stored efficiently to minimize memory usage
-- **Metrics Collection**: Comprehensive metrics are collected for performance monitoring
-- **Rust Implementation**: Implementation is in Rust for maximum efficiency and safety
-- **Parallel Processing**: Uses concurrent processing where appropriate (e.g., in FetchEntityAndGlobalSuccessRate)
-- **Request Validation**: Validates requests early to fail fast and save processing resources
-
-## Example Usage
-
-### Fetch Success Rate Example
-
-```json
-// Request
-{
- "id": "merchant_123",
- "params": "{\"payment_method\":\"card\"}",
- "labels": ["processor_A", "processor_B", "processor_C"],
- "config": {
- "min_aggregates_size": 10,
- "default_success_rate": 0.5,
- "specificity_level": "ENTITY"
- }
-}
-
-// Response
-{
- "labels_with_score": [
- {"score": 0.95, "label": "processor_A"},
- {"score": 0.82, "label": "processor_B"},
- {"score": 0.73, "label": "processor_C"}
- ]
-}
-```
-
-### Update Success Rate Window Example
-
-```json
-// Request
-{
- "id": "merchant_123",
- "params": "{\"payment_method\":\"card\"}",
- "labels_with_status": [
- {"label": "processor_A", "status": true},
- {"label": "processor_B", "status": false}
- ],
- "global_labels_with_status": [
- {"label": "processor_A", "status": true},
- {"label": "processor_B", "status": false}
- ],
- "config": {
- "max_aggregates_size": 100,
- "current_block_threshold": {
- "duration_in_mins": 60,
- "max_total_count": 1000
- }
- }
-}
-
-// Response
-{
- "status": "WINDOW_UPDATION_SUCCEEDED"
-}
-```
-
-### Invalidate Windows Example
-
-```json
-// Request
-{
- "id": "merchant_123"
-}
-
-// Response
-{
- "status": "WINDOW_INVALIDATION_SUCCEEDED"
-}
-```
-
-### Fetch Entity and Global Success Rate Example
-
-```json
-// Request
-{
- "entity_id": "merchant_123",
- "entity_params": "{\"payment_method\":\"card\"}",
- "entity_labels": ["processor_A", "processor_B", "processor_C"],
- "global_labels": ["processor_A", "processor_B", "processor_C", "processor_D"],
- "config": {
- "entity_min_aggregates_size": 10,
- "entity_default_success_rate": 0.5
- }
-}
-
-// Response
-{
- "entity_scores_with_labels": [
- {"score": 0.95, "label": "processor_A"},
- {"score": 0.82, "label": "processor_B"},
- {"score": 0.73, "label": "processor_C"}
- ],
- "global_scores_with_labels": [
- {"score": 0.92, "label": "processor_A"},
- {"score": 0.85, "label": "processor_C"},
- {"score": 0.78, "label": "processor_B"},
- {"score": 0.70, "label": "processor_D"}
- ]
-}
-```
-
-## Integration Notes
-
-- All requests should include appropriate authentication metadata
-- JSON parameters in the `params` field should be properly escaped
-- Review metrics to monitor system performance
-- Consider implementing client-side retries for transient failures
-- Cache routing decisions where appropriate to improve performance
-- Maintain proper error handling for all API calls
-
-## gRPCurl Examples
-
-The following examples demonstrate how to call the Success Rate API endpoints using gRPCurl. These examples assume the service is running on localhost at port 9000.
-We wouldn't require configs as Dynamo will automatically fetch that from he specified profile.
-
-### FetchSuccessRate
-
-```bash
-grpcurl -plaintext -d '{
- "id": "merchant_123",
- "params": "{\"payment_method\":\"card\"}",
- "labels": ["processor_A", "processor_B", "processor_C"],
-}' \
--H 'x-api-key: YOUR_API_KEY' \
--H 'x-tenant-id: tenant_001' \
--H 'x-profile-id: profile_id' \
-localhost:9000 success_rate.SuccessRateCalculator/FetchSuccessRate
-```
-
-### UpdateSuccessRateWindow
-
-```bash
-grpcurl -plaintext -d '{
- "id": "merchant_123",
- "params": "{\"payment_method\":\"card\"}",
- "labels_with_status": [
- {"label": "processor_A", "status": true},
- {"label": "processor_B", "status": false}
- ],
- "global_labels_with_status": [
- {"label": "processor_A", "status": true},
- {"label": "processor_B", "status": false}
- ]
-}' \
--H 'x-api-key: YOUR_API_KEY' \
--H 'x-tenant-id: tenant_001' \
--H 'x-profile-id: profile_id' \
-localhost:9000 success_rate.SuccessRateCalculator/UpdateSuccessRateWindow
-```
-
-### InvalidateWindows
-
-```bash
-grpcurl -plaintext -d '{
- "id": "merchant_123"
-}' \
--H 'x-api-key: YOUR_API_KEY' \
--H 'x-tenant-id: tenant_001' \
-localhost:9000 success_rate.SuccessRateCalculator/InvalidateWindows
-```
-
-### FetchEntityAndGlobalSuccessRate
-
-```bash
-grpcurl -plaintext -d '{
- "entity_id": "merchant_123",
- "entity_params": "{\"payment_method\":\"card\"}",
- "entity_labels": ["processor_A", "processor_B", "processor_C"],
- "global_labels": ["processor_A", "processor_B", "processor_C", "processor_D"]
-}' \
--H 'x-api-key: YOUR_API_KEY' \
--H 'x-tenant-id: tenant_001' \
--H 'x-profile-id: profile_id' \
-localhost:9000 success_rate.SuccessRateCalculator/FetchEntityAndGlobalSuccessRate
-```
-
-### Listing Available Methods
-
-To discover available methods on the service:
-
-```bash
-grpcurl -plaintext localhost:9000 list success_rate.SuccessRateCalculator
-```
-
-### Viewing Method Details
-
-To see detailed information about a specific method:
-
-```bash
-grpcurl -plaintext localhost:9000 describe success_rate.SuccessRateCalculator.FetchSuccessRate
-```
diff --git a/docs/api-reference1.md b/docs/api-reference1.md
index 75638e3e..811746a8 100644
--- a/docs/api-reference1.md
+++ b/docs/api-reference1.md
@@ -1,995 +1,379 @@
-# API REFERENCE
+# API Examples
-## Decision Gateway API
+Use these examples for local smoke tests. For request and response schemas, use the OpenAPI-backed endpoint pages and `docs/openapi.json`.
-### Sample curl for decide-gateway
+Base URL:
-#### Request: SR BASED ROUTING
```bash
-curl --location 'http://localhost:8080/decide-gateway' \
---header 'Content-Type: application/json' \
---data '{
- "merchantId": "test_merchant1",
- "eligibleGatewayList": ["GatewayA", "GatewayB", "GatewayC"],
- "rankingAlgorithm": "SR_BASED_ROUTING",
- "eliminationEnabled": true,
- "paymentInfo": {
- "paymentId": "PAY12359",
- "amount": 100.50,
- "currency": "USD",
- "customerId": "CUST12345",
- "udfs": null,
- "preferredGateway": null,
- "paymentType": "ORDER_PAYMENT",
- "metadata": null,
- "internalMetadata": null,
- "isEmi": false,
- "emiBank": null,
- "emiTenure": null,
- "paymentMethodType": "UPI",
- "paymentMethod": "UPI_PAY",
- "paymentSource": null,
- "authType": null,
- "cardIssuerBankName": null,
- "cardIsin": null,
- "cardType": null,
- "cardSwitchProvider": null
- }
-}'
-```
-
-#### Response:
-```json
-{
- "decided_gateway": "GatewayA",
- "gateway_priority_map": {
- "GatewayA": 1.0,
- "GatewayB": 1.0,
- "GatewayC": 1.0
- },
- "filter_wise_gateways": null,
- "priority_logic_tag": null,
- "routing_approach": "SR_SELECTION_V3_ROUTING",
- "gateway_before_evaluation": "GatewayA",
- "priority_logic_output": {
- "isEnforcement": false,
- "gws": [
- "GatewayA",
- "GatewayB",
- "GatewayC"
- ],
- "priorityLogicTag": null,
- "gatewayReferenceIds": {},
- "primaryLogic": null,
- "fallbackLogic": null
- },
- "reset_approach": "NO_RESET",
- "routing_dimension": "ORDER_PAYMENT, UPI, UPI_PAY",
- "routing_dimension_level": "PM_LEVEL",
- "is_scheduled_outage": false,
- "is_dynamic_mga_enabled": false,
- "gateway_mga_id_map": null
-}
-```
-##### Routing Approach
-This field available in the response for the decide-gateway api call provides visibility into the routing logic applied by the decision engine for a transaction. The possible values are as follows:
-
-- **SR_SELECTION_V3_ROUTING** : Routing is based on the gateway with the highest Success Rate (SR) score for the merchant, evaluated at the dimension on which routing is happening
-
-- **SR_V3_DOWNTIME_ROUTING** : Routing uses SR-based selection, but one or more (not all) eligible gateways have been deprioritized due to downtime (i.e., having a score below the elimination threshold). The system selects the best available gateway (based on SR) amongst the gateways which are not facing downtime.
-
-- **SR_V3_ALL_DOWNTIME_ROUTING** : All eligible gateways are facing downtime and have been deprioritized via elimination. Routing still uses SR scores at the configured dimension level to select the best among the degraded options.
-
-- **SR_V3_HEDGING** : Routing is done across all eligible gateways irrespective of their SR performance. This mode is used for exploration and evaluation of gateway SR performance and is controlled via configuration in the SR routing setup.
-
-- **SR_V3_DOWNTIME_HEDGING** : Routing follows the hedging strategy, where SR performance is not a strict criterion. However, one or more (but not all) eligible gateways are facing downtime. The system prefers gateways that are currently healthy while maintaining the exploration objective.
-
-- **SR_V3_ALL_DOWNTIME_HEDGING** : Routing follows the configured hedging strategy, but all eligible gateways are experiencing downtime. In this scenario, routing proceeds without reprioritization, in accordance with the defined hedging configuration.
-
-#### Request: DEBIT ROUTING
-```bash
-curl --location 'http://localhost:8080/decide-gateway' \
---header 'Content-Type: application/json' \
---data '{
- "merchantId": "pro_OiJkBiFuCYbYAkCG9X02",
- "eligibleGatewayList": ["PAYU", "RAZORPAY", "PAYTM_V2"],
- "rankingAlgorithm": "NTW_BASED_ROUTING",
- "eliminationEnabled": true,
- "paymentInfo": {
- "paymentId": "PAY12345",
- "amount": 100.50,
- "currency": "USD",
- "customerId": "CUST12345",
- "udfs": null,
- "preferredGateway": null,
- "paymentType": "ORDER_PAYMENT",
- "metadata": "{\"merchant_category_code\":\"merchant_category_code_0001\",\"acquirer_country\":\"US\"}",
- "internalMetadata": null,
- "isEmi": false,
- "emiBank": null,
- "emiTenure": null,
- "paymentMethodType": "UPI",
- "paymentMethod": "UPI_PAY",
- "paymentSource": null,
- "authType": null,
- "cardIssuerBankName": null,
- "cardIsin": "440000",
- "cardType": null,
- "cardSwitchProvider": null
- }
-}'
-```
-
-#### Response:
-```json
-{
- "decided_gateway": "PAYU",
- "gateway_priority_map": null,
- "filter_wise_gateways": null,
- "priority_logic_tag": null,
- "routing_approach": "NONE",
- "gateway_before_evaluation": null,
- "priority_logic_output": null,
- "debit_routing_output": {
- "co_badged_card_networks": [
- "STAR",
- "VISA"
- ],
- "issuer_country": "US",
- "is_regulated": false,
- "regulated_name": "GOVERNMENT EXEMPT INTERCHANGE FEE",
- "card_type": "debit"
- },
- "reset_approach": "NO_RESET",
- "routing_dimension": null,
- "routing_dimension_level": null,
- "is_scheduled_outage": false,
- "is_dynamic_mga_enabled": false,
- "gateway_mga_id_map": null
-}
+export BASE_URL=http://localhost:8080
```
-## Update Gateway Score API
+## Health
-### Sample curl for update-gateway-score
-
-#### Request:
```bash
-curl --location 'http://localhost:8080/update-gateway-score' \
---header 'Content-Type: application/json' \
---data '{
- "merchantId" : "test_merchant1",
- "gateway": "RAZORPAY",
- "gatewayReferenceId": null,
- "status": "FAILURE",
- "paymentId": "PAY12359",
- "enforceDynamicRoutingFailure" : null
-}'
+curl "$BASE_URL/health"
```
-#### Response:
-```
-Success
-```
+## Create Merchant
-## Config APIs
-
-#### Request: Success Rate Config Create
```bash
-curl -X POST http://localhost:8080/rule/create \
+curl -X POST "$BASE_URL/merchant-account/create" \
-H "Content-Type: application/json" \
-d '{
- "merchant_id": "test_merchant_123423",
- "config": {
- "type": "successRate",
- "data": {
- "defaultLatencyThreshold": 90,
- "defaultSuccessRate": 0.5,
- "defaultBucketSize": 200,
- "defaultHedgingPercent": 5,
- "subLevelInputConfig": [
- {
- "paymentMethodType": "upi",
- "paymentMethod": "upi_collect",
- "bucketSize": 250,
- "hedgingPercent": 1
- }
- ]
- }
- }
+ "merchant_id": "demo_merchant",
+ "gateway_success_rate_based_decider_input": null
}'
```
-#### Response:
-```json
-{
- "Success Rate Configuration created successfully"
-}
-```
+## Decide Gateway
-#### Request: Success Rate Config retrieve
```bash
-curl -X POST http://localhost:8080/rule/get \
- -H "Content-Type: application/json" \
- -d '{
- "merchant_id": "test_merchant_123423",
- "algorithm": "successRate"
- }'
+curl -X POST "$BASE_URL/decide-gateway" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "merchantId": "demo_merchant",
+ "paymentInfo": {
+ "paymentId": "pay_001",
+ "amount": 1000.0,
+ "currency": "USD",
+ "paymentType": "ORDER_PAYMENT",
+ "paymentMethodType": "CARD",
+ "paymentMethod": "CREDIT"
+ },
+ "eligibleGatewayList": ["stripe", "paypal", "adyen"],
+ "rankingAlgorithm": "SrBasedRouting",
+ "eliminationEnabled": false
+ }'
```
-#### Response:
-```json
-{
- "merchant_id": "test_merchant_123423",
- "config": {
- "type": "successRate",
- "data": {
- "defaultLatencyThreshold": 90,
- "defaultSuccessRate": 0.5,
- "defaultBucketSize": 200,
- "defaultHedgingPercent": 5,
- "subLevelInputConfig": [
- {
- "paymentMethodType": "upi",
- "paymentMethod": "upi_collect",
- "bucketSize": 250,
- "hedgingPercent": 1
- }
- ]
- }
- }
-}
-```
+## Update Gateway Score
-#### Request: Success Rate Config update
```bash
-curl -X POST http://localhost:8080/rule/update \
+curl -X POST "$BASE_URL/update-gateway-score" \
-H "Content-Type: application/json" \
-d '{
- "merchant_id": "test_merchant_123423",
- "config": {
- "type": "successRate",
- "data": {
- "defaultLatencyThreshold": 90,
- "defaultSuccessRate": 0.5,
- "defaultBucketSize": 200,
- "defaultHedgingPercent": 5,
- "subLevelInputConfig": [
- {
- "paymentMethodType": "upi",
- "paymentMethod": "upi_collect",
- "bucketSize": 250,
- "hedgingPercent": 1
- }
- ]
- }
- }
+ "merchantId": "demo_merchant",
+ "gateway": "stripe",
+ "paymentId": "pay_001",
+ "status": "CHARGED",
+ "gatewayReferenceId": null,
+ "enforceDynamicRoutingFailure": null
}'
```
-#### Response:
-```json
-{
- "Success Rate Configuration updated successfully"
-}
-```
-
-#### Request: Success Rate Config delete
-```bash
-curl -X POST http://localhost:8080/rule/delete \
- -H "Content-Type: application/json" \
- -d '{
- "merchant_id": "test_merchant_123423",
- "algorithm": "successRate"
- }'
-```
+## Create Routing Rule
-#### Response:
-```json
-{
- "Success Rate Configuration deleted successfully"
-}
-```
+### Priority rule
-#### Request: Elimination Config Create
```bash
-curl -X POST http://localhost:8080/rule/create \
+curl -X POST "$BASE_URL/routing/create" \
-H "Content-Type: application/json" \
-d '{
- "merchant_id": "test_merchant_123423",
- "config": {
- "type": "elimination",
- "data": {
- "threshold": 0.35
- }
+ "name": "default-priority",
+ "description": "route to stripe first",
+ "created_by": "demo_merchant",
+ "algorithm_for": "payment",
+ "algorithm": {
+ "type": "priority",
+ "data": [
+ { "gateway_name": "stripe", "gateway_id": null },
+ { "gateway_name": "paypal", "gateway_id": null }
+ ]
}
}'
```
-#### Response:
-```json
-{
- "Elimination Configuration created successfully"
-}
-```
+### Single connector rule
-#### Request: Elimination Config retrieve
```bash
-curl -X POST http://localhost:8080/rule/get \
- -H "Content-Type: application/json" \
- -d '{
- "merchant_id": "test_merchant_123423",
- "algorithm": "elimination"
- }'
-```
-
-#### Response:
-```json
-{
- "merchant_id": "test_merchant_123423",
- "config": {
- "type": "elimination",
- "data": {
- "threshold": 0.35
- }
- }
-}
-```
-
-#### Request: Elimination Config update
-```bash
-curl -X POST http://localhost:8080/rule/update \
+curl -X POST "$BASE_URL/routing/create" \
-H "Content-Type: application/json" \
-d '{
- "merchant_id": "test_merchant_123423",
- "config": {
- "type": "elimination",
+ "name": "always-stripe",
+ "description": "Pin all traffic to stripe",
+ "created_by": "demo_merchant",
+ "algorithm_for": "payment",
+ "algorithm": {
+ "type": "single",
"data": {
- "threshold": 0.35
+ "gateway_name": "stripe",
+ "gateway_id": null
}
}
}'
```
-#### Response:
-```json
-{
- "Elimination Configuration updated successfully"
-}
-```
-
-#### Request: Elimination Config delete
-```bash
-curl -X POST http://localhost:8080/rule/delete \
- -H "Content-Type: application/json" \
- -d '{
- "merchant_id": "test_merchant_123423",
- "algorithm": "elimination"
- }'
-```
-
-#### Response:
-```json
-{
- "Elimination Configuration deleted successfully"
-}
-```
-
-#### Request: Merchant account create
-```bash
-curl --location --request POST 'http://localhost:8080/merchant-account/create' \
---header 'Content-Type: application/json' \
---data-raw '{
- "merchant_id": "test_merchant_123423"
-}'
-```
-
-#### Response:
-```json
-{
- "Merchant account created successfully"
-}
-```
-
-#### Request: Merchant account retrieve
-```bash
-curl -X GET http://localhost:8080/merchant-account/test_merchant_123423
-```
-
-#### Response:
-```json
-{
- "merchant_id": "test_merchant_123423",
- "gateway_success_rate_based_decider_input": null
-}
-```
-
-#### Request: Merchant account delete
-```bash
-curl -X DELETE http://localhost:8080/merchant-account/test_merchant_123423
-```
-
-#### Response:
-```json
-{
- "Merchant account deleted successfully"
-}
-```
-
-# Priority Logic V2
----
-
-**A rule engine to enable merchants to create complex logical expressions based on various payment related [parameters](https://github.com/juspay/decision-engine/blob/main/config/development.toml). These rules are executed on the payment payload to evaluate the gateway to be used.**
-
-## Table of Contents
-1. [API Components](#components)
-2. [API Reference](#PL-api-reference)
- 2.1 [Create](#create)
- 2.2 [Evaluate](#evaluate)
- 2.3 [Operations](#operations)
- 2.3.1 [List](#list)
- 2.3.2 [Activate](#activate)
- 2.3.e [List-Activated](#list_activated)
-3. [Algorithm Types](#algorithm-types)
- 3.1 Advanced Logic
- 3.1.1 [AND](#and-rule)
- 3.1.2 [OR](#or-rule)
- 3.1.3 [AND-OR (Nested)](#and-or-rule)
- 3.1.4 [Enum variant](#enum-variant)
- 3.1.5 [Number array](#number-array)
- 3.1.6 [Number comparison array](#number-comparison-array)
- 3.2 [Priority](#priority)
- 3.3 [Single Connector](#single)
- 3.4 [Volume Split](#volume-split)
-
----
-
-## 1 · API Components
-
-| Components | Description & Accepted Values |
-|------------------------------|----------------------------------------------------------------------------------------------------------------|
-| `name` | Name of the rule (**string**, required) |
-| `created_by` | Merchant or platform ID (**string**, required) |
-| `description` | Rule description (**string**) |
-| `algorithm_for` | Routing scope (**enum**): `payment` (default), `payout`, `three_ds_authentication` |
-| `algorithm.type` | Routing algorithm type (**enum**): [`advanced`](#advanced), [`single`](#single), [`priority`](#priority), [`volume_split`](#volume-split) |
-| `algorithm.data.globals` | Optional constants (**object**): reusable values for expressions |
-| `default_selection` | Fallback connectors if no rule matches (**object**) with `priority: [{ gateway_name, gateway_id }]` |
-| `rules[].name` | Name of an individual rule (**string**) |
-| `rules[].routing_type` | Rule behavior (**enum**): `priority`, `volume_split`, Required only in advanced rule. |
-| `output.priority[]` | Priority connector list (**array**): `[ { gateway_name, gateway_id } ]` |
-| `output.volume_split[]` | Volume split rule (**array**): `[ { split: number, output: { gateway_name, gateway_id } } ]`, either priority or volume can be present at once in output. |
-| `statements[].condition[]` | AND logic conditions (**array**): each with `lhs`, `comparison`, `value`, and optional `metadata` |
-| `condition.lhs` | Field to evaluate (**string**): e.g., `amount`, `payment_method`, `card_network`. Can be checked from development.toml. |
-| `condition.comparison` | Comparator (**enum**): `equal`, `greater_than`, `less_than`, `greater_than_equals`, etc. |
-| `condition.value.type` | Value type (**enum**): `number`, [`number_array`](#number-array), [`enum_variant`](#enum-variant), `str_value`, [`number_comparison_array`](#number-comparison-array), etc. |
-| `condition.value.value` | Value being compared (**any**): e.g., `100`, `"card"`, `[1000, 2000]` |
-| `condition.metadata` | Optional metadata for tracing/debug (**object**) |
-| `statements[].nested` | Nested OR conditions (**array**) of `condition[]` blocks |
-| `algorithm.metadata` | Algorithm-level metadata (**object**, optional) |
-| `rules[].metadata` | Rule-level metadata (**object**, optional) |
-
-
-**Tip**: Use multiple `statements[]` blocks for OR logic. Use `nested` inside a `statement` for AND+OR nesting.
-
----
-
-
-## 2 · API Reference
-
-### 2.1 Create Routing Algorithm
+### Volume split rule
```bash
-curl --location 'http://127.0.0.1:8082/routing/create' \
---header 'Content-Type: application/json' \
---data '
-{
- "name": "Priority rule",
- "created_by": "merchant_1234",
- "description": "this is my priority rule",
+curl -X POST "$BASE_URL/routing/create" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "name": "card-ab-test",
+ "description": "Split card traffic between stripe and checkout",
+ "created_by": "demo_merchant",
"algorithm_for": "payment",
"algorithm": {
- "type": "advanced",
- "data": {
- "globals": {},
- "default_selection": {
- "priority": [
- {
- "gateway_name": "stripe",
- "gateway_id": "mca_111"
- },
- {
- "gateway_name": "adyen",
- "gateway_id": "mca_112"
- },
- {
- "gateway_name": "checkout",
- "gateway_id": "mca_113"
- }
- ]
- },
- "rules": [
- {
- "name": "Card Rule",
- "routingType": "priority",
- "output": {
- "priority": [
- {
- "gateway_name": "Paytm",
- "gateway_id": "mca_114"
- },
- {
- "gateway_name": "adyen",
- "gateway_id": "mca_112"
- }
- ]
- },
- "statements": [
- {
- "condition": [
- {
- "lhs": "payment_method",
- "comparison": "equal",
- "value": {
- "type": "enum_variant",
- "value": "card"
- },
- "metadata": {}
- }
- ]
- },
- {
- "condition": [
- {
- "lhs": "amount",
- "comparison": "greater_than",
- "value": {
- "type": "number",
- "value": 100
- },
- "metadata": {}
- }
- ]
- }
- ]
- }
- ]
- }
- },
- "metadata": {}
-}
-'
-```
-
-**Success Response**
-```json
-{
- "rule_id": "routing_e641380c-6f24-4405-8454-5ae6cbceb7a0",
- "name": "Priority rule",
- "created_at": "2025-04-22 11:45:03.411134513",
- "modified_at": "2025-04-22 11:45:03.411134513"
-}
-```
-
----
-
-### 2.2 Evaluate Routing Algorithm
-
-```bash
-curl --location 'http://127.0.0.1:8082/routing/evaluate' \
---header 'Content-Type: application/json' \
---data '{
- "created_by": "merchant_1234",
- "parameters": {
- "payment_method": { "type": "enum_variant", "value": "upi" },
- "amount": { "type": "number", "value": 10 }
- }
-}'
-```
-
-**Example Response**
-```json
-{
- "status": "default_selection",
- "output": {
- "type": "priority",
- "connectors": [
- { "gateway_name": "stripe", "gateway_id": "mca_111" },
- { "gateway_name": "adyen", "gateway_id": "mca_112" },
- { "gateway_name": "checkout", "gateway_id": "mca_113" }
- ]
- },
- "evaluated_output": [
- { "gateway_name": "stripe", "gateway_id": "mca_111" }
- ],
- "eligible_connectors": []
-}
-```
-
----
-
-## 2.3 Operations
-
-### 2.3.1 List Algorithms
-
-```bash
-curl --request POST 'http://127.0.0.1:8082/routing/list/merchant_1234'
-```
-
-Returns an array of algorithms for `merchant_1234`.
-
-### 2.3.2 Activate Algorithm
-
-```bash
-curl --location 'http://127.0.0.1:8082/routing/activate' \
---header 'Content-Type: application/json' \
---data '{
- "created_by": "merchant_1234",
- "routing_algorithm_id": "routing_8711ce52-33e2-473f-9c8f-91a406acb850"
-}'
-```
-At a given time one algorithm for each transaction_type (`payment`, `payout`, `three_ds_authentication`) can be active for one created_by id.
-HTTP 200 ⇒ algorithm is now active.
-
-### 2.3.3 List Activated algorithm
-
-```bash
-curl --location --request POST 'http://127.0.0.1:8082/routing/list/active/merchant_31' \
---header 'Content-Type: application/json'
-```
-
-Returns algorithms currently active for the merchant.
-
----
-
-## 3 · Algorithm Types
-
-### 3.1 Advanced Logic (AND / OR / AND-OR)
-
-| Use-case | Description |
-|---------------------|--------------------------------------|
-| **AND** | All conditions must be true |
-| **OR** | Any one condition may be true |
-| **AND-OR (nested)** | Parent condition + any nested match |
-
----
-Note: for advanced algorithm kinds we always require statements to be evaluated upoun, unlike the below priority, single and volume_split, which donot requires any statements and directly provide output.
-
-AND Rule
-
-```json
-{
- "name": "HDFC Rule",
- "routing_type": "volume_split",
- "output": {
- "volume_split": [
- {
- "split": 60,
- "output": { "gateway_name": "hdfc", "gateway_id": "mca_114" }
- },
- {
- "split": 40,
- "output": { "gateway_name": "instamojo", "gateway_id": "mca_115" }
- }
- ]
- },
- "statements": [
- {
- "condition": [
+ "type": "volume_split",
+ "data": [
{
- "lhs": "amount",
- "comparison": "greater_than",
- "value": { "type": "number", "value": 100 }
+ "split": 70,
+ "output": { "gateway_name": "stripe", "gateway_id": null }
},
{
- "lhs": "billing_country",
- "comparison": "equal",
- "value": { "type": "enum_variant", "value": "Netherlands" }
+ "split": 30,
+ "output": { "gateway_name": "checkout", "gateway_id": null }
}
]
}
- ]
-}
+ }'
```
-All conditions must match → volume split applies
-
-
----
-
-
-OR Rule
-
-```json
-{
- "name": "Card Rule",
- "routing_type": "priority",
- "output": {
- "priority": [
- { "gateway_name": "Paytm", "gateway_id": "mca_114" },
- { "gateway_name": "adyen", "gateway_id": "mca_112" }
- ]
- },
- "statements": [
- {
- "condition": [
- {
- "lhs": "payment_method",
- "comparison": "equal",
- "value": { "type": "enum_variant", "value": "card" }
- }
- ]
- },
- {
- "condition": [
- {
- "lhs": "amount",
- "comparison": "greater_than",
- "value": { "type": "number", "value": 100 }
- }
- ]
- }
- ]
-}
-```
+### Advanced rule with OR branches
-Any one condition match triggers the rule
-
-
----
-
-
-AND + OR (Nested)
-
-```json
-{
- "name": "RBL Rule",
- "routing_type": "priority",
- "output": {
- "priority": [
- { "gateway_name": "rbl", "gateway_id": "mca_114" },
- { "gateway_name": "instamojo", "gateway_id": "mca_115" }
- ]
- },
- "statements": [
- {
- "condition": [
- {
- "lhs": "amount",
- "comparison": "greater_than",
- "value": { "type": "number", "value": 10 }
- }
- ],
- "nested": [
- {
- "condition": [
- {
- "lhs": "card_network",
- "comparison": "equal",
- "value": { "type": "enum_variant", "value": "Visa" }
- }
+`statements` are OR branches. Each `condition` array is an AND block.
+
+```bash
+curl -X POST "$BASE_URL/routing/create" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "name": "wallet-or-credit-card",
+ "description": "Route wallet traffic to checkout and credit cards to stripe first",
+ "created_by": "demo_merchant",
+ "algorithm_for": "payment",
+ "algorithm": {
+ "type": "advanced",
+ "data": {
+ "globals": {},
+ "default_selection": {
+ "priority": [
+ { "gateway_name": "adyen", "gateway_id": null }
]
},
- {
- "condition": [
- {
- "lhs": "billing_country",
- "comparison": "equal",
- "value": { "type": "enum_variant", "value": "India" }
- }
- ]
- }
- ]
- }
- ]
-}
-```
-
-Main condition must match + any one nested condition
-
-
----
-
-
-Enum variant
-
-```json
-{
- "name": "Card Rule",
- "routing_type": "priority",
- "output": {
- "priority": [
- {
- "gateway_name": "rbl",
- "gateway_id": "mca_114"
- }
- ]
- },
- "statements": [
- {
- "condition": [
- {
- "lhs": "card_network",
+ "rules": [
+ {
+ "name": "wallet_or_credit_card",
+ "routing_type": "priority",
+ "output": {
+ "priority": [
+ { "gateway_name": "checkout", "gateway_id": null },
+ { "gateway_name": "stripe", "gateway_id": null }
+ ]
+ },
+ "statements": [
+ {
+ "condition": [
+ {
+ "lhs": "payment_method",
"comparison": "equal",
- "value": {
- "type": "enum_variant_array",
- "value": [
- "Visa",
- "Mastercard"
- ]
- },
+ "value": { "type": "enum_variant", "value": "wallet" },
"metadata": {}
- }
- ]
- }
- ]
-}
-```
-
-The input for evaluation parameter must be one of the mentioned types in array.
-
-
----
-
-
-Number array
-
-```json
-{
- "name": "Card Rule",
- "routing_type": "priority",
- "output": {
- "priority": [
- {
- "gateway_name": "rbl",
- "gateway_id": "mca_114"
- }
- ]
- },
- "statements": [
- {
- "condition": [
- {
- "lhs": "amount",
+ }
+ ],
+ "nested": null
+ },
+ {
+ "condition": [
+ {
+ "lhs": "payment_method",
"comparison": "equal",
- "value": {
- "type": "number_array",
- "value": [
- 1000,
- 2000,
- 5000
- ]
- },
+ "value": { "type": "enum_variant", "value": "card" },
"metadata": {}
- }
+ },
+ {
+ "lhs": "card_type",
+ "comparison": "equal",
+ "value": { "type": "enum_variant", "value": "credit" },
+ "metadata": {}
+ }
+ ],
+ "nested": null
+ }
]
- }
- ]
-}
+ }
+ ],
+ "metadata": {}
+ }
+ }
+ }'
```
-The input for evaluation parameter must be one of the mentioned values in array.
-
+### Advanced rule with nested conditions
----
-
-Number comparison array
+Use `nested` when the second block should only run after the parent condition matched.
-```json
-{
- "name": "Card Rule",
- "routing_type": "priority",
- "output": {
- "priority": [
+```bash
+curl -X POST "$BASE_URL/routing/create" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "name": "visa-usd-nested-routing",
+ "description": "Use nested card checks, then split matched traffic by percentage",
+ "created_by": "demo_merchant",
+ "algorithm_for": "payment",
+ "algorithm": {
+ "type": "advanced",
+ "data": {
+ "globals": {},
+ "default_selection": {
+ "volume_split": [
{
- "gateway_name": "rbl",
- "gateway_id": "mca_114"
+ "split": 60,
+ "output": { "gateway_name": "stripe", "gateway_id": null }
+ },
+ {
+ "split": 40,
+ "output": { "gateway_name": "checkout", "gateway_id": null }
}
- ]
- },
- "statements": [
- {
- "condition": [
+ ]
+ },
+ "rules": [
+ {
+ "name": "card_credit_visa",
+ "routing_type": "volume_split",
+ "output": {
+ "volume_split": [
{
- "lhs": "amount",
+ "split": 80,
+ "output": { "gateway_name": "stripe", "gateway_id": null }
+ },
+ {
+ "split": 20,
+ "output": { "gateway_name": "adyen", "gateway_id": null }
+ }
+ ]
+ },
+ "statements": [
+ {
+ "condition": [
+ {
+ "lhs": "payment_method",
"comparison": "equal",
- "value": {
- "type": "number_comparison_array",
- "value": [
- {
- "comparison_type": "greater_than",
- "number": 1000
- },
- {
- "comparison_type": "less_than_equal",
- "number": 5000
- }
- ]
- },
+ "value": { "type": "enum_variant", "value": "card" },
"metadata": {}
- }
+ }
+ ],
+ "nested": [
+ {
+ "condition": [
+ {
+ "lhs": "card_type",
+ "comparison": "equal",
+ "value": { "type": "enum_variant", "value": "credit" },
+ "metadata": {}
+ }
+ ],
+ "nested": [
+ {
+ "condition": [
+ {
+ "lhs": "card_network",
+ "comparison": "equal",
+ "value": { "type": "enum_variant", "value": "visa" },
+ "metadata": {}
+ },
+ {
+ "lhs": "currency",
+ "comparison": "equal",
+ "value": { "type": "enum_variant", "value": "USD" },
+ "metadata": {}
+ }
+ ],
+ "nested": null
+ }
+ ]
+ }
+ ]
+ }
]
- }
- ]
-}
+ }
+ ],
+ "metadata": {}
+ }
+ }
+ }'
```
-The input for evaluation parameter must be in the specifed thresholds.
-
-
----
+## List Routing Rules
+```bash
+curl -X POST "$BASE_URL/routing/list/demo_merchant"
+```
-### 3.2 Priority Routing
+## Activate Routing Rule
```bash
-curl --location 'http://127.0.0.1:8082/routing/create' \
---header 'Content-Type: application/json' \
---data '{
- "name": "priority rule test",
- "created_by": "merchant_123",
- "algorithm": {
- "type": "priority",
- "data": [
- { "gateway_name": "stripe", "gateway_id": "mca_001" },
- { "gateway_name": "razorpay", "gateway_id": "mca_002" }
- ]
- }
-}'
+curl -X POST "$BASE_URL/routing/activate" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "created_by": "demo_merchant",
+ "routing_algorithm_id": "rule_id_here"
+ }'
```
-Always returns the connectors **in the given order**.
+## Get Active Routing Rule
----
+```bash
+curl -X POST "$BASE_URL/routing/list/active/demo_merchant"
+```
-### 3.3 Single Connector (straight-through)
+## Create Euclid Rule Config
```bash
-curl --location 'http://127.0.0.1:8082/routing/create' \
---header 'Content-Type: application/json' \
---data '{
- "name": "single connector rule",
- "created_by": "merchant_123",
- "algorithm": {
- "type": "single",
- "data": { "gateway_name": "stripe", "gateway_id": "mca_00123" }
- }
-}'
+curl -X POST "$BASE_URL/rule/create" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "merchant_id": "demo_merchant",
+ "config": {
+ "type": "successRate",
+ "data": {
+ "defaultLatencyThreshold": 90,
+ "defaultSuccessRate": 0.5,
+ "defaultBucketSize": 200,
+ "defaultHedgingPercent": 5,
+ "subLevelInputConfig": []
+ }
+ }
+ }'
```
-Regardless of parameters, Routing decision will always be **Stripe (mca_00123)**.
+## Get Euclid Rule Config
----
+```bash
+curl -X POST "$BASE_URL/rule/get" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "merchant_id": "demo_merchant",
+ "algorithm": "successRate"
+ }'
+```
-### 3.4 Volume Split
+## Update Euclid Rule Config
```bash
-curl --location 'http://127.0.0.1:8082/routing/create' \
---header 'Content-Type: application/json' \
---data '{
- "name": "volume split test rule",
- "created_by": "merchant_31",
- "algorithm_for": "payout",
- "algorithm": {
- "type": "volume_split",
- "data": [
- {
- "split": 70,
- "output": { "gateway_name": "stripe", "gateway_id": "mca_001" }
- },
- {
- "split": 30,
- "output": { "gateway_name": "paytm", "gateway_id": "mca_002" }
+curl -X POST "$BASE_URL/rule/update" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "merchant_id": "demo_merchant",
+ "config": {
+ "type": "successRate",
+ "data": {
+ "defaultLatencyThreshold": 95,
+ "defaultSuccessRate": 0.5,
+ "defaultBucketSize": 250,
+ "defaultHedgingPercent": 5,
+ "subLevelInputConfig": []
}
- ]
- }
-}'
+ }
+ }'
```
-Provides **70 %** of decisions as Stripe and **30 %** as Paytm.
-
----
+## Delete Euclid Rule Config
-**Note:** Full routing rule example is provided in the [initial request section](#create). Use that as template to compose complex rules (AND / OR / AND-OR).
-
----
+```bash
+curl -X POST "$BASE_URL/rule/delete" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "merchant_id": "demo_merchant",
+ "algorithm": "successRate"
+ }'
+```
diff --git a/docs/configuration.md b/docs/configuration.md
index fc4d0f28..5ab4636f 100644
--- a/docs/configuration.md
+++ b/docs/configuration.md
@@ -1,176 +1,118 @@
# Configuration Guide
-Dynamo uses TOML configuration files to customize its behavior. This guide explains the available configuration options and how to use them effectively.
+This page describes the runtime configuration model used by Decision Engine.
-## Configuration File Location
+## How Configuration Is Loaded
-By default, Dynamo looks for configuration files in the following locations:
+The application loads config in this order:
-- Development mode: `config/development.toml`
-- Production mode: `config/production.toml`
+1. file selected by `APP_ENV`
+2. environment overrides with the `DECISION_ENGINE__` prefix
-You can also specify a custom configuration file using environment variables.
+From `src/config.rs`:
-## Configuration Format
+- `APP_ENV=dev` or unset -> `config/development.toml`
+- `APP_ENV=sandbox` -> `config/sandbox.toml`
+- `APP_ENV=production` -> `config/production.toml`
-Below is an explanation of the main configuration sections:
+Environment overrides use `__` as the separator.
-### Server Configuration
+Example:
-```toml
-[server]
-host = "127.0.0.1" # The address to bind the server to
-port = 8000 # The port to listen on
-type = "grpc" # Server type: "grpc" or "http"
+```bash
+DECISION_ENGINE__SERVER__PORT=8080
+DECISION_ENGINE__METRICS__PORT=9090
```
-### Metrics Server Configuration
+## Primary Files
-```toml
-[metrics]
-host = "127.0.0.1" # The address to bind the metrics server to
-port = 9000 # The port for the metrics server
-```
+- `config.example.toml`: sample config
+- `config/development.toml`: source-run default
+- `config/docker-configuration.toml`: Compose-mounted config
+- `src/config.rs`: actual config structs and load rules
-### Logging Configuration
+For deployment behavior, also inspect:
-```toml
-[log.console]
-enabled = true # Whether to enable console logging
-level = "DEBUG" # Log level: DEBUG, INFO, WARN, ERROR
-log_format = "default" # Log format: "default" or "json"
-```
+- `docker-compose.yaml`
+- `helm-charts/templates/*`
-### Redis Configuration
+## Main Config Sections
-```toml
-[redis]
-host = "127.0.0.1"
-port = 6379
-pool_size = 5 # Number of connections to keep open
-reconnect_max_attempts = 5 # Maximum reconnection attempts
-reconnect_delay = 5 # Delay between attempts in milliseconds
-use_legacy_version = false # Use RESP2 protocol for Redis < 6
-```
+The runtime config model in `src/config.rs` includes:
-### TTL for Keys
+- `log`
+- `server`
+- `metrics`
+- `database` or `pg_database`
+- `redis`
+- `cache_config`
+- `tenant_secrets`
+- `tls`
+- `api_client`
+- `routing_config`
+- `pm_filters`
+- `debit_routing_config`
+- `compression_filepath`
-```toml
-[ttl_for_keys]
-aggregates = 300 # Time to live for aggregates keys (seconds)
-current_block = 900 # Time to live for current_block keys (seconds)
-elimination_bucket = 900 # Time to live for elimination buckets (seconds)
-contract_ttl = 900 # Time to live for contracts (seconds)
-```
+## Common Areas
-### Global Routing Configurations
+### Server
```toml
-[global_routing_configs.success_rate]
-min_aggregates_size = 5 # Minimum number of buckets for SR calculation
-default_success_rate = 100 # Default SR when insufficient data
-max_aggregates_size = 10 # Maximum number of aggregates to store
-
-[global_routing_configs.success_rate.current_block_threshold]
-duration_in_mins = 10 # Current block duration in minutes
-max_total_count = 5 # Maximum transaction count for current block
-
-[global_routing_configs.elimination_rate]
-bucket_size = 5 # Capacity of buckets
-bucket_leak_interval_in_secs = 300 # Leak rate of buckets in seconds
+[server]
+host = "0.0.0.0"
+port = 8080
```
-### Multi-Tenancy
+### Metrics
```toml
-[multi_tenancy]
-enabled = true # Enable multi-tenant mode
-```
-
-## Environment Variables
-
-You can override configuration values using environment variables with the prefix `DYNAMO__`:
-
-```bash
-# Override Redis host and port
-export DYNAMO__REDIS__HOST=redis-server
-export DYNAMO__REDIS__PORT=6380
-
-# Override server port
-export DYNAMO__SERVER__PORT=9000
+[metrics]
+host = "0.0.0.0"
+port = 9090
```
-## Configuration Examples
-
-### Development Configuration
+### Logging
```toml
[log.console]
enabled = true
level = "DEBUG"
log_format = "default"
-
-[server]
-host = "127.0.0.1"
-port = 8000
-type = "grpc"
-
-[redis]
-host = "127.0.0.1"
-port = 6379
```
-### Production Configuration
+### Database
-```toml
-[log.console]
-enabled = true
-level = "INFO"
-log_format = "json"
+Use one backend path:
-[server]
-host = "0.0.0.0" # Listen on all interfaces
-port = 8000
-type = "grpc"
+- MySQL via `[database]`
+- PostgreSQL via `[pg_database]`
-[redis]
-host = "redis-server" # Use service name in production
-port = 6379
-pool_size = 20
-reconnect_max_attempts = 10
-```
-
-### High-Availability Configuration
+### Redis
```toml
-[server]
-host = "0.0.0.0"
-port = 8000
-type = "grpc"
-
[redis]
-host = "redis-master"
+host = "127.0.0.1"
port = 6379
-pool_size = 30
-reconnect_max_attempts = 15
-reconnect_delay = 2
```
-## Advanced Configuration
+### TLS
-### Using Multiple Redis Instances
+TLS is optional and configured through the `tls` section.
-While not directly supported in the configuration file, you can set up Redis Sentinel or Redis Cluster for high availability and implement a custom client.
+### Tenant Config
-### Configuring Routing Strategies
+Tenant-aware behavior is driven by `tenant_secrets` and tenant-specific app-state wiring in `src/tenant.rs`.
-Each routing strategy has specific configuration parameters:
+## Deployment Notes
-1. **Success Rate Routing**: Configure weight factors, time windows, and default values
-2. **Elimination Routing**: Configure bucket sizes, leak rates, and thresholds
-3. **Contract Routing**: Configure contract scores, targets, and time scales
+- Source runs default to `config/development.toml`
+- Compose mounts `config/docker-configuration.toml` at `/local/config/development.toml`
+- Helm behavior should be verified against the chart templates directly
-## Next Steps
+## Related Docs
-- [Installation Guide](setup-guide.md)
-- [API Reference](api-reference.md)
+- [Local Setup Guide](local-setup.md)
+- [PostgreSQL Setup Guide](setup-guide-postgres.md)
+- [MySQL Setup Guide](setup-guide-mysql.md)
+- [API Overview](api-reference.md)
diff --git a/docs/dashboard.mdx b/docs/dashboard.mdx
new file mode 100644
index 00000000..91b6a953
--- /dev/null
+++ b/docs/dashboard.mdx
@@ -0,0 +1,50 @@
+---
+title: "Dashboard"
+description: "Local dashboard routes and how they are served"
+---
+
+## Availability
+
+The dashboard is available in the `dashboard-*` Docker Compose profiles.
+
+Example:
+
+```bash
+docker compose --profile dashboard-postgres-ghcr up -d
+```
+
+Then open:
+
+- `http://localhost:8081/dashboard/`
+
+The dashboard is served by Nginx from the built assets in `website/dist`.
+
+## What It Includes
+
+Based on the React routes in `website/src/App.tsx`, the dashboard exposes:
+
+- `/dashboard/`
+- `/dashboard/routing`
+- `/dashboard/routing/sr`
+- `/dashboard/routing/rules`
+- `/dashboard/routing/volume`
+- `/dashboard/routing/debit`
+- `/dashboard/decisions`
+- `/dashboard/analytics`
+- `/dashboard/audit`
+
+## Docs And API In The Same Profile
+
+The same `dashboard-*` profiles also expose:
+
+- Mintlify docs at `http://localhost:8081/introduction`
+- the API at `http://localhost:8080`
+
+Proxy behavior is defined in `nginx/nginx.conf`.
+
+## Related Files
+
+- `website/src/App.tsx`
+- `website/src/components/pages/*`
+- `docker-compose.yaml`
+- `nginx/nginx.conf`
diff --git a/docs/dual-protocol-layer.md b/docs/dual-protocol-layer.md
deleted file mode 100644
index a897e432..00000000
--- a/docs/dual-protocol-layer.md
+++ /dev/null
@@ -1,79 +0,0 @@
-# Dual Protocol Layer: gRPC and HTTP
-
-## Overview
-
-Dynamo implements a unique dual-protocol layer that allows services to be exposed via both gRPC and HTTP simultaneously. This enables clients to interact with Dynamo using their preferred protocol without requiring separate service implementations.
-
-## Architecture
-
-The implementation uses a custom generator that extends Tonic's standard gRPC code generation to automatically create corresponding HTTP endpoints for each gRPC service. This is done through a specialized WebGenerator in the build process.
-
-### Key Components
-
-- **Protocol Buff Definition**: Service interfaces are defined once in `.proto` files
-- **Code Generation**: Build process generates both gRPC and HTTP handlers
-- **Axum Integration**: HTTP endpoints are implemented using the Axum framework
-- **Automatic Conversion**: Seamless serialization/deserialization between gRPC and HTTP formats
-
-## How It Works
-
-1. **Define Once**: Services are defined once using Protocol Buffers
-2. **Generate Both**: Build scripts generate both gRPC service code and HTTP routes
-3. **Single Implementation**: Service logic is implemented only once
-4. **Configure at Runtime**: Choose protocol through configuration settings
-
-The system automatically handles conversion between HTTP and gRPC formats, including:
-- Converting gRPC metadata to HTTP headers and vice versa
-- Mapping gRPC status codes to HTTP status codes
-- Handling serialization differences between the protocols
-
-## Benefits
-
-1. **Protocol Flexibility**: Clients can choose between gRPC or HTTP based on their needs
-2. **Unified Codebase**: Service logic is implemented only once
-3. **No Duplication**: Avoid duplicating endpoint logic and type definitions
-4. **Simple Configuration**: Switch between protocols with a single configuration option
-5. **Testing Ease**: Test services using simple HTTP clients like cURL
-
-## Using the Dual Protocol Layer
-
-### Configuration
-
-In your configuration file, specify the protocol:
-
-```toml
-[server]
-type = "grpc" # or "http"
-```
-
-### Client Options
-
-Clients can interact with the service using either protocol:
-
-**gRPC Client**:
-- Better performance for high-throughput scenarios
-- Efficient binary serialization
-- Built-in streaming support
-- Strong typing via generated client code
-
-**HTTP Client**:
-- Works in environments where gRPC isn't supported (e.g., browsers)
-- Simpler to debug and inspect with standard tools
-- Easier integration with existing HTTP-based systems
-- No need for protocol buffer compilation
-
-## Technical Considerations
-
-1. **Performance**: gRPC generally offers better performance for service-to-service communication
-2. **Compatibility**: HTTP offers broader compatibility but without some gRPC advantages
-3. **Streaming**: gRPC excels at bidirectional streaming; HTTP is more limited
-4. **Headers/Metadata**: Slight differences in how metadata is handled between protocols
-
-## Future Directions
-
-- Enhanced streaming support for HTTP endpoints
-- WebSocket alternatives for bidirectional communication in HTTP mode
-- Automatic OpenAPI/Swagger documentation generation
-- Support for protocol-specific optimizations
-
-This innovative approach allows Dynamo to be more accessible to a wider range of clients while maintaining a clean and maintainable codebase.
diff --git a/docs/favicon.svg b/docs/favicon.svg
new file mode 100644
index 00000000..5ae09a6b
--- /dev/null
+++ b/docs/favicon.svg
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/docs/installation.md b/docs/installation.md
index 675014e1..f5a6433a 100644
--- a/docs/installation.md
+++ b/docs/installation.md
@@ -1,168 +1,30 @@
# Installation Guide
-This guide provides detailed instructions for installing Dynamo on different platforms.
+Use this page to choose the right installation path. For actual commands, use the linked guides.
-## Prerequisites
+## Supported Paths
-- Rust 1.78.0 or later
-- Redis server 6.0 or later
-- Git
+| Path | Best for | Primary doc |
+|------|----------|-------------|
+| Docker Compose with published images | fastest local or on-prem style bring-up | [Local Setup Guide](local-setup.md) |
+| Docker Compose with local builds | validating local source changes | [Local Setup Guide](local-setup.md) |
+| Source build | backend debugging and feature-specific runs | [Local Setup Guide](local-setup.md) |
+| Helm | Kubernetes and on-prem deployment work | [Local Setup Guide](local-setup.md) and `helm-charts/README.md` |
-## From Source
+## Database-Specific Shortcuts
-### 1. Clone the Repository
+- PostgreSQL commands: [PostgreSQL Setup Guide](setup-guide-postgres.md)
+- MySQL commands: [MySQL Setup Guide](setup-guide-mysql.md)
-```bash
-git clone https://github.com/yourusername/dynamo.git
-cd dynamo
-```
+## Dashboard And Docs
-### 2. Install Dependencies
+If you want the React dashboard and Mintlify docs, use one of the `dashboard-*` compose profiles from [Local Setup Guide](local-setup.md).
-#### Ubuntu/Debian
+That exposes:
-```bash
-# Install system dependencies
-sudo apt-get update
-sudo apt-get install -y pkg-config libssl-dev protobuf-compiler libpq-dev
+- Dashboard: `http://localhost:8081/dashboard/`
+- Docs: `http://localhost:8081/introduction`
-# Install Rust (if not already installed)
-curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
-source $HOME/.cargo/env
-```
+## Canonical Source
-#### macOS
-
-```bash
-# Using Homebrew
-brew install pkg-config openssl protobuf postgresql
-
-# Install Rust (if not already installed)
-curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
-source $HOME/.cargo/env
-```
-
-### 3. Build Dynamo
-
-```bash
-# Build in release mode
-cargo build --release
-```
-
-### 4. Set Up Configuration
-
-```bash
-# Copy example configuration
-cp config/config.example.toml config/development.toml
-
-# Edit configuration as needed
-# vi config/development.toml
-```
-
-### 5. Run Redis
-
-Make sure Redis is running on your system:
-
-```bash
-# Install Redis if needed
-sudo apt-get install redis-server # Ubuntu/Debian
-brew install redis # macOS
-
-# Start Redis server
-redis-server
-```
-
-### 6. Run Dynamo
-
-```bash
-# Run with development configuration
-./target/release/dynamo
-```
-
-## Using Docker
-
-### 1. Pull the Docker Image
-
-```bash
-docker pull yourusername/dynamo:latest
-```
-
-Or build it yourself:
-
-```bash
-docker build -t dynamo:latest .
-```
-
-### 2. Run with Docker
-
-```bash
-# Run with default configuration
-docker run -p 8000:8000 -p 9000:9000 dynamo:latest
-
-# Run with custom configuration
-docker run -p 8000:8000 -p 9000:9000 \
- -v $(pwd)/config:/app/config \
- dynamo:latest
-```
-
-### 3. Docker Compose Setup
-
-Create a `docker-compose.yml` file:
-
-```yaml
-version: '3'
-services:
- dynamo:
- image: yourusername/dynamo:latest
- ports:
- - "8000:8000"
- - "9000:9000"
- volumes:
- - ./config:/app/config
- depends_on:
- - redis
-
- redis:
- image: redis:latest
- ports:
- - "6379:6379"
-```
-
-Run with Docker Compose:
-
-```bash
-docker-compose up -d
-```
-
-## Building the WebAssembly Module
-
-The `procesmo` module can be built for web use:
-
-```bash
-# Install wasm-pack if needed
-cargo install wasm-pack
-
-# Build the WebAssembly module
-cd crates/procesmo
-wasm-pack build --target web
-```
-
-## Verifying Installation
-
-To verify that Dynamo is running correctly:
-
-```bash
-# Check health status
-curl http://localhost:8000/grpc.health.v1.Health/Check
-
-# Or using grpcurl
-grpcurl -plaintext localhost:8000 grpc.health.v1.Health/Check
-```
-
-You should see a response indicating the service is running.
-
-## Next Steps
-
-- [Configure Dynamo](configuration.md) for your environment
-- [Explore the API](api-reference.md)
-- [See usage examples](examples.md)
+Treat [Local Setup Guide](local-setup.md) as the canonical installation and startup document for this repository.
diff --git a/docs/introduction.mdx b/docs/introduction.mdx
new file mode 100644
index 00000000..0e23b67d
--- /dev/null
+++ b/docs/introduction.mdx
@@ -0,0 +1,98 @@
+---
+title: "Decision Engine"
+description: "Routing API, local run paths, dashboard, and docs entrypoints"
+---
+
+
+
+
+
+
+
+ Juspay Decision Engine
+
+ Routing infrastructure docs for setup, operations, analytics, and API usage.
+
+
+
+## What It Is
+
+Decision Engine is a Rust service that picks a gateway from an eligible list and records transaction outcomes for later routing decisions.
+
+The repository currently ships:
+
+- the routing API
+- merchant and routing configuration APIs
+- Docker Compose profiles for local bring-up
+- Helm chart assets
+- a React dashboard under `/dashboard/`
+- an Analytics surface under `/analytics`
+- Mintlify docs served in the dashboard profiles
+
+## Main API Surface
+
+The main endpoint groups are:
+
+- `GET /health`
+- `POST /decide-gateway`
+- `POST /update-gateway-score`
+- `POST /merchant-account/create`
+- `GET /merchant-account/{merchantId}`
+- `DELETE /merchant-account/{merchantId}`
+- `POST /routing/*`
+- `POST /rule/*`
+- `GET /analytics/*`
+
+Use the OpenAPI-backed endpoint pages for request and response schemas.
+
+## Run Locally
+
+For API only:
+
+```bash
+docker compose --profile postgres-ghcr up -d
+curl http://localhost:8080/health
+```
+
+For API + dashboard + docs:
+
+```bash
+docker compose --profile dashboard-postgres-ghcr up -d
+```
+
+URLs:
+
+- API: `http://localhost:8080`
+- Dashboard: `http://localhost:8081/dashboard/`
+- Docs: `http://localhost:8081/introduction`
+
+Use [Local Setup](local-setup) for the full Compose, source-build, and Helm matrix.
+
+## Dashboard Routes
+
+When the dashboard profile is running, the React app is available at:
+
+- `/dashboard/`
+- `/dashboard/routing`
+- `/dashboard/routing/sr`
+- `/dashboard/routing/rules`
+- `/dashboard/routing/volume`
+- `/dashboard/routing/debit`
+- `/dashboard/decisions`
+- `/dashboard/analytics`
+
+Use [Dashboard](dashboard) for route-by-route details.
+
+## Where To Go Next
+
+- [Installation](installation)
+- [Local Setup](local-setup)
+- [Configuration](configuration)
+- [Dashboard](dashboard)
+- [Analytics](analytics)
+- [API Overview](api-reference)
+- [API Examples](api-reference1)
diff --git a/docs/local-setup.md b/docs/local-setup.md
new file mode 100644
index 00000000..d3f86c71
--- /dev/null
+++ b/docs/local-setup.md
@@ -0,0 +1,182 @@
+# Local Setup Guide
+
+This is the canonical local startup guide for Decision Engine.
+
+## Prerequisites
+
+- Docker 20+
+- Docker Compose v2+
+- Git 2+
+
+Optional for source runs:
+
+- Rust 1.85+
+- `just`
+- PostgreSQL or MySQL
+- Redis
+
+## Runtime Tracks
+
+Decision Engine supports two local tracks:
+
+1. published-image track: pull existing images
+2. local-build track: build images or binaries from the current source tree
+
+Default tags used in this repo:
+
+- `DECISION_ENGINE_TAG=v1.4`
+- `GROOVY_RUNNER_TAG=v1.4`
+
+## Docker Compose Profiles
+
+You must pass at least one profile.
+
+### Core runtime profiles
+
+| Profile | DB | Includes |
+|---|---|---|
+| `postgres-ghcr` | PostgreSQL | API + PostgreSQL + Redis + PG migrations |
+| `postgres-local` | PostgreSQL | API + PostgreSQL + Redis + PG migrations |
+| `mysql-ghcr` | MySQL | API + MySQL + Redis + MySQL migrations + routing-config |
+| `mysql-local` | MySQL | API + MySQL + Redis + MySQL migrations + routing-config |
+
+### Dashboard profiles
+
+| Profile | DB | Includes |
+|---|---|---|
+| `dashboard-postgres-ghcr` | PostgreSQL | core PG stack + dashboard + Mintlify docs |
+| `dashboard-postgres-local` | PostgreSQL | core PG stack + dashboard + Mintlify docs |
+| `dashboard-mysql-ghcr` | MySQL | core MySQL stack + dashboard + Mintlify docs |
+| `dashboard-mysql-local` | MySQL | core MySQL stack + dashboard + Mintlify docs |
+
+### Optional profiles
+
+| Profile | Adds |
+|---|---|
+| `monitoring` | Prometheus + Grafana |
+| `groovy-ghcr` | Groovy runner image |
+| `groovy-local` | Groovy runner built from local source |
+
+## Fastest Bring-Up
+
+### API Only
+
+```bash
+docker compose --profile postgres-ghcr up -d
+```
+
+### API + Dashboard + Docs
+
+```bash
+docker compose --profile dashboard-postgres-ghcr up -d
+```
+
+### With Monitoring
+
+```bash
+docker compose --profile postgres-ghcr --profile monitoring up -d
+```
+
+## Make Targets
+
+Common wrappers:
+
+```bash
+make init-pg-ghcr
+make init-pg-local
+make init-mysql-ghcr
+make init-mysql-local
+make run-pg-ghcr
+make run-mysql-local
+make stop
+```
+
+## Source Build And Run
+
+### PostgreSQL
+
+```bash
+cargo build --release --no-default-features --features middleware,kms-aws,postgres
+just migrate-pg
+RUSTFLAGS="-Awarnings" cargo run --no-default-features --features postgres
+```
+
+### MySQL
+
+```bash
+cargo build --release --features release
+RUSTFLAGS="-Awarnings" cargo run --features release
+```
+
+## Docker Builds Without Compose
+
+```bash
+docker build --platform=linux/amd64 -t decision-engine-mysql:local -f Dockerfile .
+docker build --platform=linux/amd64 -t decision-engine-pg:local -f Dockerfile.postgres .
+```
+
+Example container run:
+
+```bash
+docker run --platform=linux/amd64 \
+ -v $(pwd)/config/docker-configuration.toml:/local/config/development.toml \
+ -p 8080:8080 \
+ decision-engine-pg:local
+```
+
+## Helm
+
+Chart location: `helm-charts/`
+
+```bash
+cd helm-charts
+helm dependency build
+helm install my-release .
+```
+
+For image overrides, use `image.repository`, `image.version`, and `image.pullPolicy`. Verify the rendered templates directly when troubleshooting chart behavior.
+
+## Verification
+
+```bash
+curl http://localhost:8080/health
+```
+
+Expected response:
+
+```json
+{"message":"Health is good"}
+```
+
+Dashboard profiles also expose:
+
+- Dashboard: `http://localhost:8081/dashboard/`
+- Docs: `http://localhost:8081/introduction`
+
+Monitoring profile also exposes:
+
+- Prometheus: `http://localhost:9090`
+- Grafana: `http://localhost:3000`
+
+## Troubleshooting
+
+### Recreate a profile with clean volumes
+
+```bash
+docker compose --profile postgres-ghcr down -v
+docker compose --profile postgres-ghcr up -d
+```
+
+### Inspect migration jobs
+
+```bash
+docker compose logs db-migrator-postgres
+docker compose logs db-migrator
+```
+
+### Common next files to inspect
+
+- `docker-compose.yaml`
+- `config/docker-configuration.toml`
+- `src/config.rs`
+- `src/app.rs`
diff --git a/docs/logo/dark.svg b/docs/logo/dark.svg
new file mode 100644
index 00000000..57d3d833
--- /dev/null
+++ b/docs/logo/dark.svg
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/logo/decision-engine-dark.svg b/docs/logo/decision-engine-dark.svg
new file mode 100644
index 00000000..d96f4aed
--- /dev/null
+++ b/docs/logo/decision-engine-dark.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+ JUSPAY
+ Decision Engine
+
diff --git a/docs/logo/decision-engine-docs-dark.svg b/docs/logo/decision-engine-docs-dark.svg
new file mode 100644
index 00000000..5230088e
--- /dev/null
+++ b/docs/logo/decision-engine-docs-dark.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+ JUSPAY
+ Decision Engine
+
diff --git a/docs/logo/decision-engine-docs-light.svg b/docs/logo/decision-engine-docs-light.svg
new file mode 100644
index 00000000..ffba1dc0
--- /dev/null
+++ b/docs/logo/decision-engine-docs-light.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+ JUSPAY
+ Decision Engine
+
diff --git a/docs/logo/decision-engine-light.svg b/docs/logo/decision-engine-light.svg
new file mode 100644
index 00000000..5c18998b
--- /dev/null
+++ b/docs/logo/decision-engine-light.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+ JUSPAY
+ Decision Engine
+
diff --git a/docs/logo/light.svg b/docs/logo/light.svg
new file mode 100644
index 00000000..57d3d833
--- /dev/null
+++ b/docs/logo/light.svg
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/mint.json b/docs/mint.json
new file mode 100644
index 00000000..c2a73111
--- /dev/null
+++ b/docs/mint.json
@@ -0,0 +1,83 @@
+{
+ "$schema": "https://mintlify.com/schema.json",
+ "name": "Juspay Decision Engine",
+ "logo": {
+ "dark": "/logo/decision-engine-docs-dark.svg",
+ "light": "/logo/decision-engine-docs-light.svg"
+ },
+ "favicon": "/favicon.svg",
+ "colors": {
+ "primary": "#0069ED",
+ "light": "#4D9CFF",
+ "dark": "#0050B4"
+ },
+ "openapi": [
+ "openapi.json"
+ ],
+ "api": {
+ "baseUrl": "http://localhost:8080",
+ "playground": {
+ "mode": "show"
+ }
+ },
+ "navigation": [
+ {
+ "group": "Overview",
+ "pages": [
+ "introduction",
+ "installation",
+ "local-setup",
+ "configuration",
+ "dashboard",
+ "analytics",
+ "payment-audit",
+ "api-reference"
+ ]
+ },
+ {
+ "group": "Database Setup",
+ "pages": [
+ "setup-guide-postgres",
+ "setup-guide-mysql"
+ ]
+ },
+ {
+ "group": "Health",
+ "pages": [
+ "api-reference/endpoint/healthCheck"
+ ]
+ },
+ {
+ "group": "Merchant API",
+ "pages": [
+ "api-reference/endpoint/createMerchant",
+ "api-reference/endpoint/getMerchant",
+ "api-reference/endpoint/deleteMerchant"
+ ]
+ },
+ {
+ "group": "Rule Based Routing",
+ "pages": [
+ "api-reference/endpoint/createRoutingRule",
+ "api-reference/endpoint/activateRoutingRule",
+ "api-reference/endpoint/listRoutingRules",
+ "api-reference/endpoint/getActiveRoutingRule",
+ "api-reference/endpoint/evaluateRoutingRule"
+ ]
+ },
+ {
+ "group": "Dynamic Routing APIs",
+ "pages": [
+ "api-reference/endpoint/decideGateway",
+ "api-reference/endpoint/updateGatewayScore",
+ "api-reference/endpoint/createRuleConfig",
+ "api-reference/endpoint/getRuleConfig",
+ "api-reference/endpoint/updateRuleConfig",
+ "api-reference/endpoint/deleteRuleConfig"
+ ]
+ }
+ ],
+ "footerSocials": {
+ "github": "https://github.com/juspay/decision-engine"
+ }
+}
diff --git a/docs/openapi.json b/docs/openapi.json
new file mode 100644
index 00000000..a886da84
--- /dev/null
+++ b/docs/openapi.json
@@ -0,0 +1,1407 @@
+{
+ "openapi": "3.1.0",
+ "info": {
+ "title": "Decision Engine",
+ "description": "HTTP API for gateway decisions, score feedback, merchant configuration, and routing rule management.",
+ "version": "1.2.1",
+ "contact": {
+ "name": "Juspay",
+ "url": "https://github.com/juspay/decision-engine"
+ },
+ "license": {
+ "name": "AGPL-3.0",
+ "url": "https://www.gnu.org/licenses/agpl-3.0.html"
+ }
+ },
+ "servers": [
+ {
+ "url": "http://localhost:8080",
+ "description": "Local development"
+ }
+ ],
+ "tags": [
+ {
+ "name": "Health",
+ "description": "Service liveness check"
+ },
+ {
+ "name": "Dynamic Routing APIs",
+ "description": "Dynamic routing APIs for gateway decisioning, score updates, and /rule/* configuration."
+ },
+ {
+ "name": "Merchant API",
+ "description": "Merchant account management APIs."
+ },
+ {
+ "name": "Rule Based Routing",
+ "description": "APIs under /routing/* for rule-based routing creation, activation, listing, and evaluation."
+ }
+ ],
+ "paths": {
+ "/health": {
+ "get": {
+ "operationId": "healthCheck",
+ "tags": [
+ "Health"
+ ],
+ "summary": "Health check",
+ "description": "Returns a simple health status. Use this to verify the service is running.",
+ "responses": {
+ "200": {
+ "description": "Service is healthy",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HealthResponse"
+ },
+ "example": {
+ "message": "Health is good"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/decide-gateway": {
+ "post": {
+ "operationId": "decideGateway",
+ "tags": [
+ "Dynamic Routing APIs"
+ ],
+ "summary": "POST /decide-gateway",
+ "description": "Core routing decision API. Given a payment context and a list of eligible gateways, returns the optimal gateway to route to.\n\nThe engine applies a sequence of filters (currency, card brand, auth type, EMI, etc.) then scores remaining gateways using success rate history, elimination status, and contract obligations.",
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/DecideGatewayRequest"
+ },
+ "examples": {
+ "sr_routing": {
+ "summary": "SR-based routing",
+ "value": {
+ "merchantId": "test_merchant",
+ "paymentInfo": {
+ "paymentId": "pay_001",
+ "amount": 1000.0,
+ "currency": "USD",
+ "country": "US",
+ "customerId": "cust_123",
+ "paymentType": "ORDER_PAYMENT",
+ "paymentMethodType": "CARD",
+ "paymentMethod": "CREDIT",
+ "authType": "THREE_DS",
+ "cardIsin": "411111"
+ },
+ "eligibleGatewayList": [
+ "stripe",
+ "paypal",
+ "adyen"
+ ],
+ "rankingAlgorithm": "SrBasedRouting",
+ "eliminationEnabled": false
+ }
+ },
+ "debit_routing": {
+ "summary": "Debit/network-based routing",
+ "value": {
+ "merchantId": "test_merchant",
+ "paymentInfo": {
+ "paymentId": "pay_002",
+ "amount": 500.0,
+ "currency": "USD",
+ "paymentType": "ORDER_PAYMENT",
+ "paymentMethodType": "CARD",
+ "paymentMethod": "DEBIT"
+ },
+ "eligibleGatewayList": [
+ "stripe",
+ "braintree"
+ ],
+ "rankingAlgorithm": "NtwBasedRouting",
+ "eliminationEnabled": false
+ }
+ }
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Gateway decision result",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/DecidedGateway"
+ },
+ "example": {
+ "decided_gateway": "stripe",
+ "routing_approach": "SR_SELECTION_V3_ROUTING",
+ "gateway_priority_map": {
+ "stripe": 0.94,
+ "adyen": 0.87,
+ "paypal": 0.72
+ },
+ "routing_dimension": "CARD_BRAND",
+ "routing_dimension_level": "visa",
+ "reset_approach": "NoReset",
+ "is_scheduled_outage": false,
+ "is_rust_based_decider": true,
+ "latency": 8
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Bad request",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/update-gateway-score": {
+ "post": {
+ "operationId": "updateGatewayScore",
+ "tags": [
+ "Dynamic Routing APIs"
+ ],
+ "summary": "POST /update-gateway-score",
+ "description": "Feed a transaction outcome back into the success-rate model. Call this after every transaction so the engine has accurate SR data for future routing decisions.\n\nA `CHARGED` status increases the gateway's SR; failure statuses (`AUTHENTICATION_FAILED`, `AUTHORIZATION_FAILED`, etc.) decrease it.",
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UpdateGatewayScoreRequest"
+ },
+ "example": {
+ "merchantId": "test_merchant",
+ "gateway": "stripe",
+ "paymentId": "pay_001",
+ "status": "CHARGED",
+ "gatewayReferenceId": "stripe_ref_001",
+ "enforceDynamicRoutingFailure": false
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Score updated",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UpdateScoreResponse"
+ },
+ "example": {
+ "message": "Score updated",
+ "merchant_id": "test_merchant",
+ "gateway": "stripe",
+ "payment_id": "pay_001"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/merchant-account/create": {
+ "post": {
+ "operationId": "createMerchant",
+ "tags": [
+ "Merchant API"
+ ],
+ "summary": "Create merchant",
+ "description": "Register a new merchant account. The merchant ID is the primary identifier used in all subsequent routing and scoring calls.",
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/CreateMerchantRequest"
+ },
+ "example": {
+ "merchant_id": "my_merchant",
+ "gateway_success_rate_based_decider_input": null
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Merchant created",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/MerchantAccount"
+ },
+ "example": {
+ "message": "Merchant created",
+ "merchant_id": "my_merchant",
+ "gateway_success_rate_based_decider_input": null
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/merchant-account/{merchantId}": {
+ "get": {
+ "operationId": "getMerchant",
+ "tags": [
+ "Merchant API"
+ ],
+ "summary": "Get merchant",
+ "description": "Retrieve a merchant account by ID.",
+ "parameters": [
+ {
+ "name": "merchantId",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ },
+ "example": "my_merchant"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Merchant account",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/MerchantAccount"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Merchant not found",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ }
+ }
+ },
+ "delete": {
+ "operationId": "deleteMerchant",
+ "tags": [
+ "Merchant API"
+ ],
+ "summary": "Delete merchant",
+ "description": "Delete a merchant account and all associated routing configuration.",
+ "parameters": [
+ {
+ "name": "merchantId",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ },
+ "example": "my_merchant"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Merchant deleted",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/DeleteResponse"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/routing/create": {
+ "post": {
+ "operationId": "createRoutingRule",
+ "tags": [
+ "Rule Based Routing"
+ ],
+ "summary": "POST /routing/create",
+ "description": "Create a routing rule for a merchant. Supported algorithm types are `priority`, `single`, `volume_split`, and `advanced`. For `advanced`, same-level `statements` act as OR branches, each `condition` array is an AND block, and `nested` allows deeper hierarchical matching.",
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/CreateRoutingRuleRequest"
+ },
+ "examples": {
+ "priority": {
+ "summary": "Priority-based rule",
+ "value": {
+ "name": "default-priority",
+ "description": "Route to stripe first, fallback to paypal",
+ "created_by": "test_merchant",
+ "algorithm_for": "payment",
+ "algorithm": {
+ "type": "priority",
+ "data": [
+ {
+ "gateway_name": "stripe",
+ "gateway_id": null
+ },
+ {
+ "gateway_name": "paypal",
+ "gateway_id": null
+ },
+ {
+ "gateway_name": "adyen",
+ "gateway_id": null
+ }
+ ]
+ }
+ }
+ },
+ "volume_split": {
+ "summary": "Volume split rule",
+ "value": {
+ "name": "ab-test-split",
+ "description": "",
+ "created_by": "test_merchant",
+ "algorithm_for": "payment",
+ "algorithm": {
+ "type": "volume_split",
+ "data": [
+ {
+ "split": 70,
+ "output": {
+ "gateway_name": "stripe",
+ "gateway_id": null
+ }
+ },
+ {
+ "split": 30,
+ "output": {
+ "gateway_name": "paypal",
+ "gateway_id": null
+ }
+ }
+ ]
+ }
+ }
+ },
+ "single": {
+ "summary": "Single connector rule",
+ "value": {
+ "name": "always-stripe",
+ "description": "Always route to stripe",
+ "created_by": "test_merchant",
+ "algorithm_for": "payment",
+ "algorithm": {
+ "type": "single",
+ "data": {
+ "gateway_name": "stripe",
+ "gateway_id": null
+ }
+ }
+ }
+ },
+ "advanced_or": {
+ "summary": "Advanced rule with OR branches",
+ "value": {
+ "name": "wallet-or-credit-card",
+ "description": "Route wallet traffic to checkout and credit cards to stripe first",
+ "created_by": "test_merchant",
+ "algorithm_for": "payment",
+ "algorithm": {
+ "type": "advanced",
+ "data": {
+ "globals": {},
+ "default_selection": {
+ "priority": [
+ {
+ "gateway_name": "adyen",
+ "gateway_id": null
+ }
+ ]
+ },
+ "rules": [
+ {
+ "name": "wallet_or_credit_card",
+ "routing_type": "priority",
+ "output": {
+ "priority": [
+ {
+ "gateway_name": "checkout",
+ "gateway_id": null
+ },
+ {
+ "gateway_name": "stripe",
+ "gateway_id": null
+ }
+ ]
+ },
+ "statements": [
+ {
+ "condition": [
+ {
+ "lhs": "payment_method",
+ "comparison": "equal",
+ "value": {
+ "type": "enum_variant",
+ "value": "wallet"
+ },
+ "metadata": {}
+ }
+ ],
+ "nested": null
+ },
+ {
+ "condition": [
+ {
+ "lhs": "payment_method",
+ "comparison": "equal",
+ "value": {
+ "type": "enum_variant",
+ "value": "card"
+ },
+ "metadata": {}
+ },
+ {
+ "lhs": "card_type",
+ "comparison": "equal",
+ "value": {
+ "type": "enum_variant",
+ "value": "credit"
+ },
+ "metadata": {}
+ }
+ ],
+ "nested": null
+ }
+ ]
+ }
+ ],
+ "metadata": {}
+ }
+ }
+ }
+ },
+ "advanced_nested": {
+ "summary": "Advanced rule with nested conditions",
+ "value": {
+ "name": "visa-usd-nested-routing",
+ "description": "Use nested card checks, then split matched traffic by percentage",
+ "created_by": "test_merchant",
+ "algorithm_for": "payment",
+ "algorithm": {
+ "type": "advanced",
+ "data": {
+ "globals": {},
+ "default_selection": {
+ "volume_split": [
+ {
+ "split": 60,
+ "output": {
+ "gateway_name": "stripe",
+ "gateway_id": null
+ }
+ },
+ {
+ "split": 40,
+ "output": {
+ "gateway_name": "checkout",
+ "gateway_id": null
+ }
+ }
+ ]
+ },
+ "rules": [
+ {
+ "name": "card_credit_visa",
+ "routing_type": "volume_split",
+ "output": {
+ "volume_split": [
+ {
+ "split": 80,
+ "output": {
+ "gateway_name": "stripe",
+ "gateway_id": null
+ }
+ },
+ {
+ "split": 20,
+ "output": {
+ "gateway_name": "adyen",
+ "gateway_id": null
+ }
+ }
+ ]
+ },
+ "statements": [
+ {
+ "condition": [
+ {
+ "lhs": "payment_method",
+ "comparison": "equal",
+ "value": {
+ "type": "enum_variant",
+ "value": "card"
+ },
+ "metadata": {}
+ }
+ ],
+ "nested": [
+ {
+ "condition": [
+ {
+ "lhs": "card_type",
+ "comparison": "equal",
+ "value": {
+ "type": "enum_variant",
+ "value": "credit"
+ },
+ "metadata": {}
+ }
+ ],
+ "nested": [
+ {
+ "condition": [
+ {
+ "lhs": "card_network",
+ "comparison": "equal",
+ "value": {
+ "type": "enum_variant",
+ "value": "visa"
+ },
+ "metadata": {}
+ },
+ {
+ "lhs": "currency",
+ "comparison": "equal",
+ "value": {
+ "type": "enum_variant",
+ "value": "USD"
+ },
+ "metadata": {}
+ }
+ ],
+ "nested": null
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "metadata": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Routing rule created",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/RoutingRule"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/routing/activate": {
+ "post": {
+ "operationId": "activateRoutingRule",
+ "tags": [
+ "Rule Based Routing"
+ ],
+ "summary": "POST /routing/activate",
+ "description": "Activate a routing rule for a merchant.",
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ActivateRoutingRuleRequest"
+ },
+ "example": {
+ "created_by": "test_merchant",
+ "routing_algorithm_id": "rule_abc123"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Rule activated",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/RoutingRule"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/routing/list/{created_by}": {
+ "post": {
+ "operationId": "listRoutingRules",
+ "tags": [
+ "Rule Based Routing"
+ ],
+ "summary": "POST /routing/list/{created_by}",
+ "description": "List routing rules for a merchant.",
+ "parameters": [
+ {
+ "name": "created_by",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ },
+ "example": "test_merchant"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "List of routing rules",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/RoutingRule"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/routing/list/active/{created_by}": {
+ "post": {
+ "operationId": "getActiveRoutingRule",
+ "tags": [
+ "Rule Based Routing"
+ ],
+ "summary": "POST /routing/list/active/{created_by}",
+ "description": "Get the active routing rule for a merchant.",
+ "parameters": [
+ {
+ "name": "created_by",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ },
+ "example": "test_merchant"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Active routing rule",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/RoutingRule"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "No active rule",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/routing/evaluate": {
+ "post": {
+ "operationId": "evaluateRoutingRule",
+ "tags": [
+ "Rule Based Routing"
+ ],
+ "summary": "POST /routing/evaluate",
+ "description": "Evaluate routing output for the provided payment context.",
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/EvaluateRoutingRequest"
+ },
+ "example": {
+ "merchantId": "test_merchant",
+ "paymentInfo": {
+ "paymentId": "pay_001",
+ "amount": 1000.0,
+ "currency": "USD",
+ "paymentType": "ORDER_PAYMENT",
+ "paymentMethodType": "CARD",
+ "paymentMethod": "CREDIT"
+ }
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Evaluation result with ordered gateway list",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/rule/create": {
+ "post": {
+ "operationId": "createRuleConfig",
+ "tags": [
+ "Dynamic Routing APIs"
+ ],
+ "summary": "POST /rule/create",
+ "description": "Create Euclid rule configuration for success-rate, elimination, or debit-routing settings.",
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/RuleConfigRequest"
+ },
+ "examples": {
+ "success_rate": {
+ "summary": "Success rate config",
+ "value": {
+ "merchant_id": "test_merchant",
+ "config": {
+ "type": "successRate",
+ "data": {
+ "defaultBucketSize": 20,
+ "defaultLatencyThreshold": null,
+ "defaultHedgingPercent": null
+ }
+ }
+ }
+ },
+ "elimination": {
+ "summary": "Elimination config",
+ "value": {
+ "merchant_id": "test_merchant",
+ "config": {
+ "type": "elimination",
+ "data": {
+ "bucketSize": 5,
+ "eliminationThreshold": 0.2
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Rule config created",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/RuleConfigResponse"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/rule/get": {
+ "post": {
+ "operationId": "getRuleConfig",
+ "tags": [
+ "Dynamic Routing APIs"
+ ],
+ "summary": "POST /rule/get",
+ "description": "Fetch Euclid rule configuration for a merchant and algorithm type.",
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/RuleConfigGetRequest"
+ },
+ "example": {
+ "merchant_id": "test_merchant",
+ "algorithm": "successRate"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Rule config",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/RuleConfigResponse"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/rule/update": {
+ "post": {
+ "operationId": "updateRuleConfig",
+ "tags": [
+ "Dynamic Routing APIs"
+ ],
+ "summary": "POST /rule/update",
+ "description": "Update Euclid rule configuration for a merchant.",
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/RuleConfigRequest"
+ },
+ "example": {
+ "merchant_id": "test_merchant",
+ "config": {
+ "type": "successRate",
+ "data": {
+ "defaultBucketSize": 30,
+ "defaultHedgingPercent": 0.1
+ }
+ }
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Rule config updated",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/RuleConfigResponse"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/rule/delete": {
+ "post": {
+ "operationId": "deleteRuleConfig",
+ "tags": [
+ "Dynamic Routing APIs"
+ ],
+ "summary": "POST /rule/delete",
+ "description": "Delete Euclid rule configuration for a merchant and algorithm type.",
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/RuleConfigGetRequest"
+ },
+ "example": {
+ "merchant_id": "test_merchant",
+ "algorithm": "successRate"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Rule config deleted",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/DeleteResponse"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "HealthResponse": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "Health is good"
+ }
+ }
+ },
+ "ErrorResponse": {
+ "type": "object",
+ "properties": {
+ "error": {
+ "type": "string"
+ },
+ "message": {
+ "type": "string"
+ }
+ }
+ },
+ "DeleteResponse": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string"
+ }
+ }
+ },
+ "PaymentInfo": {
+ "type": "object",
+ "required": [
+ "paymentId",
+ "amount",
+ "currency",
+ "paymentType",
+ "paymentMethodType",
+ "paymentMethod"
+ ],
+ "properties": {
+ "paymentId": {
+ "type": "string",
+ "example": "pay_001"
+ },
+ "amount": {
+ "type": "number",
+ "format": "float",
+ "example": 1000.0
+ },
+ "currency": {
+ "type": "string",
+ "example": "USD"
+ },
+ "country": {
+ "type": "string",
+ "example": "US"
+ },
+ "customerId": {
+ "type": "string",
+ "example": "cust_123"
+ },
+ "paymentType": {
+ "type": "string",
+ "enum": [
+ "ORDER_PAYMENT",
+ "MANDATE_PAYMENT"
+ ],
+ "example": "ORDER_PAYMENT"
+ },
+ "paymentMethodType": {
+ "type": "string",
+ "enum": [
+ "CARD",
+ "UPI",
+ "WALLET",
+ "NETBANKING"
+ ],
+ "example": "CARD"
+ },
+ "paymentMethod": {
+ "type": "string",
+ "enum": [
+ "CREDIT",
+ "DEBIT"
+ ],
+ "example": "CREDIT"
+ },
+ "authType": {
+ "type": "string",
+ "enum": [
+ "THREE_DS",
+ "NO_THREE_DS"
+ ],
+ "example": "THREE_DS"
+ },
+ "cardIsin": {
+ "type": "string",
+ "example": "411111"
+ }
+ }
+ },
+ "DecideGatewayRequest": {
+ "type": "object",
+ "required": [
+ "merchantId",
+ "paymentInfo",
+ "eligibleGatewayList",
+ "rankingAlgorithm"
+ ],
+ "properties": {
+ "merchantId": {
+ "type": "string",
+ "example": "test_merchant"
+ },
+ "paymentInfo": {
+ "$ref": "#/components/schemas/PaymentInfo"
+ },
+ "eligibleGatewayList": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "example": [
+ "stripe",
+ "paypal",
+ "adyen"
+ ]
+ },
+ "rankingAlgorithm": {
+ "type": "string",
+ "enum": [
+ "SrBasedRouting",
+ "PlBasedRouting",
+ "NtwBasedRouting"
+ ],
+ "example": "SrBasedRouting"
+ },
+ "eliminationEnabled": {
+ "type": "boolean",
+ "default": false
+ }
+ }
+ },
+ "DecidedGateway": {
+ "type": "object",
+ "properties": {
+ "decided_gateway": {
+ "type": "string",
+ "example": "stripe"
+ },
+ "routing_approach": {
+ "type": "string",
+ "example": "SR_SELECTION_V3_ROUTING"
+ },
+ "gateway_priority_map": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "number"
+ },
+ "example": {
+ "stripe": 0.94,
+ "adyen": 0.87,
+ "paypal": 0.72
+ }
+ },
+ "routing_dimension": {
+ "type": "string"
+ },
+ "routing_dimension_level": {
+ "type": "string"
+ },
+ "reset_approach": {
+ "type": "string"
+ },
+ "is_scheduled_outage": {
+ "type": "boolean"
+ },
+ "is_rust_based_decider": {
+ "type": "boolean"
+ },
+ "latency": {
+ "type": "number"
+ }
+ }
+ },
+ "UpdateGatewayScoreRequest": {
+ "type": "object",
+ "required": [
+ "merchantId",
+ "gateway",
+ "paymentId",
+ "status"
+ ],
+ "properties": {
+ "merchantId": {
+ "type": "string",
+ "example": "test_merchant"
+ },
+ "gateway": {
+ "type": "string",
+ "example": "stripe"
+ },
+ "paymentId": {
+ "type": "string",
+ "example": "pay_001"
+ },
+ "status": {
+ "type": "string",
+ "enum": [
+ "CHARGED",
+ "AUTHENTICATION_FAILED",
+ "AUTHORIZATION_FAILED",
+ "JUSPAY_DECLINED",
+ "FAILURE"
+ ],
+ "example": "CHARGED"
+ },
+ "gatewayReferenceId": {
+ "type": "string",
+ "example": "stripe_ref_001"
+ },
+ "enforceDynamicRoutingFailure": {
+ "type": "boolean",
+ "default": false
+ }
+ }
+ },
+ "UpdateScoreResponse": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string"
+ },
+ "merchant_id": {
+ "type": "string"
+ },
+ "gateway": {
+ "type": "string"
+ },
+ "payment_id": {
+ "type": "string"
+ }
+ }
+ },
+ "CreateMerchantRequest": {
+ "type": "object",
+ "required": [
+ "merchant_id"
+ ],
+ "properties": {
+ "merchant_id": {
+ "type": "string",
+ "example": "my_merchant"
+ },
+ "gateway_success_rate_based_decider_input": {
+ "type": "string",
+ "nullable": true
+ }
+ }
+ },
+ "MerchantAccount": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string"
+ },
+ "merchant_id": {
+ "type": "string",
+ "example": "my_merchant"
+ },
+ "gateway_success_rate_based_decider_input": {
+ "type": "string",
+ "nullable": true
+ }
+ }
+ },
+ "CreateRoutingRuleRequest": {
+ "type": "object",
+ "required": [
+ "name",
+ "created_by",
+ "algorithm"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "example": "default-priority"
+ },
+ "description": {
+ "type": "string",
+ "example": ""
+ },
+ "created_by": {
+ "type": "string",
+ "example": "test_merchant"
+ },
+ "algorithm_for": {
+ "type": "string",
+ "enum": [
+ "payment",
+ "payout",
+ "three_ds_authentication"
+ ],
+ "default": "payment"
+ },
+ "algorithm": {
+ "$ref": "#/components/schemas/RoutingAlgorithm"
+ }
+ }
+ },
+ "RoutingAlgorithm": {
+ "type": "object",
+ "required": [
+ "type",
+ "data"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "priority",
+ "single",
+ "volume_split",
+ "advanced"
+ ],
+ "example": "priority"
+ },
+ "data": {
+ "description": "Depends on type: array of ConnectorInfo ({gateway_name, gateway_id}) for `priority`; single ConnectorInfo for `single`; array of {split, connectors} for `volume_split`; Euclid AST Program for `advanced`"
+ }
+ }
+ },
+ "ActivateRoutingRuleRequest": {
+ "type": "object",
+ "required": [
+ "created_by",
+ "routing_algorithm_id"
+ ],
+ "properties": {
+ "created_by": {
+ "type": "string",
+ "example": "test_merchant"
+ },
+ "routing_algorithm_id": {
+ "type": "string",
+ "example": "rule_abc123"
+ }
+ }
+ },
+ "RoutingRule": {
+ "type": "object",
+ "properties": {
+ "rule_id": {
+ "type": "string",
+ "nullable": true,
+ "example": "rule_abc123"
+ },
+ "name": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ },
+ "created_by": {
+ "type": "string",
+ "example": "test_merchant"
+ },
+ "algorithm_for": {
+ "type": "string"
+ },
+ "algorithm": {
+ "$ref": "#/components/schemas/RoutingAlgorithm"
+ }
+ }
+ },
+ "EvaluateRoutingRequest": {
+ "type": "object",
+ "required": [
+ "merchantId",
+ "paymentInfo"
+ ],
+ "properties": {
+ "merchantId": {
+ "type": "string",
+ "example": "test_merchant"
+ },
+ "paymentInfo": {
+ "$ref": "#/components/schemas/PaymentInfo"
+ }
+ }
+ },
+ "RuleConfigRequest": {
+ "type": "object",
+ "required": [
+ "merchant_id",
+ "config"
+ ],
+ "properties": {
+ "merchant_id": {
+ "type": "string",
+ "example": "test_merchant"
+ },
+ "config": {
+ "type": "object",
+ "description": "Tagged config variant. `type` is `successRate`, `elimination`, or `debitRouting`. `data` holds the variant-specific fields."
+ }
+ }
+ },
+ "RuleConfigGetRequest": {
+ "type": "object",
+ "required": [
+ "merchant_id",
+ "algorithm"
+ ],
+ "properties": {
+ "merchant_id": {
+ "type": "string",
+ "example": "test_merchant"
+ },
+ "algorithm": {
+ "type": "string",
+ "enum": [
+ "successRate",
+ "elimination",
+ "debitRouting"
+ ],
+ "example": "successRate"
+ }
+ }
+ },
+ "RuleConfigResponse": {
+ "type": "object",
+ "properties": {
+ "merchant_id": {
+ "type": "string"
+ },
+ "config": {
+ "type": "object"
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/docs/payment-audit.mdx b/docs/payment-audit.mdx
new file mode 100644
index 00000000..371fa1a8
--- /dev/null
+++ b/docs/payment-audit.mdx
@@ -0,0 +1,83 @@
+---
+title: "Payment Audit"
+description: "Search a payment or request and inspect the full routing timeline"
+---
+
+## What It Shows
+
+Payment Audit is the operator-facing timeline view for a single payment or request.
+
+Use it when you want to answer questions like:
+
+- which gateway was decided for this payment
+- which priority rule was hit
+- whether a score update succeeded or failed
+- what structured event payload was captured at each step
+
+The page is designed for exact lookups first and broad operator filtering second.
+
+## Search Inputs
+
+The page supports these filters:
+
+- `payment_id`
+- `request_id`
+- `gateway`
+- `route`
+- `status`
+- `event_type`
+- time window: `15m`, `1h`, `24h`
+- scope: current merchant or all merchants
+
+Use an exact `payment_id` when you have it. If you only have a request trace, use `request_id`.
+
+## Timeline Stages
+
+The timeline is built from analytics events captured by the live request flows.
+
+Current stages include:
+
+- `gateway_decided`
+- `rule_applied`
+- `score_updated`
+- `request_failed`
+- `validation_failed`
+- `request_parse_failed`
+- `score_update_failed`
+
+The raw event type remains visible as well, for example `decision`, `rule_hit`, `score_snapshot`, or `error`.
+
+## Data Sources
+
+Payment Audit reads from the same `analytics_event` store used by the analytics surface.
+
+Relevant fields include:
+
+- `payment_id`
+- `request_id`
+- `event_stage`
+- `route`
+- `gateway`
+- `routing_approach`
+- `rule_name`
+- `status`
+- `error_code`
+- `error_message`
+- `details`
+
+The `details` field is shown as structured JSON when available.
+
+## Route
+
+When the dashboard profile is running, open:
+
+- `http://localhost:8081/dashboard/audit`
+
+## Related Files
+
+- `website/src/components/pages/PaymentAuditPage.tsx`
+- `src/routes/analytics.rs`
+- `src/analytics/models.rs`
+- `src/analytics/service.rs`
+- `src/decider/gatewaydecider/`
+- `src/feedback/gateway_scoring_service.rs`
diff --git a/docs/readme/analytics-overview.gif b/docs/readme/analytics-overview.gif
new file mode 100644
index 00000000..426597ff
Binary files /dev/null and b/docs/readme/analytics-overview.gif differ
diff --git a/docs/readme/analytics-overview.png b/docs/readme/analytics-overview.png
new file mode 100644
index 00000000..690ac212
Binary files /dev/null and b/docs/readme/analytics-overview.png differ
diff --git a/docs/setup-guide-mysql.md b/docs/setup-guide-mysql.md
index 7b17c83e..cd3b051a 100644
--- a/docs/setup-guide-mysql.md
+++ b/docs/setup-guide-mysql.md
@@ -1,247 +1,55 @@
-# Setup Instructions:
+# MySQL Setup Guide
-Follow the steps below to set up and run the project locally.
+Use this page when the task is explicitly MySQL-specific. For the full local matrix, use [Local Setup Guide](local-setup.md).
-## 1. Clone the Repository
+## Compose Commands
-```bash
-git clone https://github.com/juspay/decision-engine.git
-cd decision-engine
-```
----
-
-## 2. Install Docker
-
-Make sure Docker is installed on your system.
-You can download and install Docker Desktop from the below links.
-
-- Mac - https://docs.docker.com/desktop/setup/install/mac-install/
-- Windows - https://docs.docker.com/desktop/setup/install/windows-install/
-- Linux - https://docs.docker.com/desktop/setup/install/linux/
-
----
-
-## 3. Run the Project
-
-### a. First-Time Setup
-
-If you're setting up the environment for the first time, run:
+### Published-image track
```bash
-make init
+export DECISION_ENGINE_TAG=v1.4
+docker compose --profile mysql-ghcr up -d
```
-To build it with postgres DB use this instead
-```
-make init-pg
-```
-
-This command performs the following under the hood:
+### Published-image track with dashboard + docs
```bash
-docker-compose run --rm db-migrator && docker-compose up open-router
+docker compose --profile dashboard-mysql-ghcr up -d
```
-This will:
-- Set up the environment
-- Set up the database with the required schema
-- Sets up redis and the server for running the application
-- Push the configs defined in the config.yaml & the static rules defined for routing in priority_logic.txt to the DB
-### b. Start the Server (without resetting DB)
-
-If the DB schema is already set up and you don't want to reset the DB, use:
+### Local-build track
```bash
-make run
+docker compose --profile mysql-local up -d --build
```
-**System Requirements:** Approximately 2GB of disk space
-
-After successful setup, the server will start running.
-### c. Update Configs / Static Rules
-To update the configs (from the config.yaml file) or the static rules (from priority_logic.txt), run:
+### Local-build track with dashboard + docs
```bash
-make update-config
+docker compose --profile dashboard-mysql-local up -d --build
```
-### d. Stop Running Instances
-
-To stop the running Docker instances:
+## Make Targets
```bash
-make stop
+make init-mysql-ghcr
+make init-mysql-local
```
----
-
-## 4. Running Local Code Changes
-
-If you've made changes to the code locally and want to test them:
-
-### a. Initialize Local Environment
+## Source Run
```bash
-make init-local
+cargo build --release --features release
+RUSTFLAGS="-Awarnings" cargo run --features release
```
-This command performs the following under the hood:
+## Verify
```bash
-docker-compose run --rm db-migrator && docker-compose up open-router-local
+curl http://localhost:8080/health
```
-### b. Run Locally
-
-```bash
-make run-local
-```
-
-## Using the Decision Engine APIs
-
-
-
-### 1. Get the Gateway Decision
-
-Use the following cURL with payment info to get the gateway-decision:
-
-```bash
-curl --location 'http://localhost:8080/decide-gateway' \
---header 'Content-Type: application/json' \
---data '{
- "merchantId": "test_merchant1",
- "eligibleGatewayList": ["PAYU", "RAZORPAY", "PAYTM_V2"],
- "rankingAlgorithm": "SR_BASED_ROUTING",
- "eliminationEnabled": true,
- "paymentInfo": {
- "paymentId": "PAY12345",
- "amount": 100.50,
- "currency": "USD",
- "customerId": "CUST12345",
- "udfs": null,
- "preferredGateway": null,
- "paymentType": "ORDER_PAYMENT",
- "metadata": null,
- "internalMetadata": null,
- "isEmi": false,
- "emiBank": null,
- "emiTenure": null,
- "paymentMethodType": "UPI",
- "paymentMethod": "UPI_PAY",
- "paymentSource": null,
- "authType": null,
- "cardIssuerBankName": null,
- "cardIsin": null,
- "cardType": null,
- "cardSwitchProvider": null
- }
-}'
-```
-
-#### Response Example
-
-```json
-{
- "decided_gateway": "PAYTM_V2",
- "gateway_priority_map": {
- "PAYU": 1.0,
- "RAZORPAY": 1.0,
- "PAYTM_V2": 1.0
- },
- "filter_wise_gateways": null,
- "priority_logic_tag": "PL_TEST",
- "routing_approach": "PRIORITY_LOGIC",
- "gateway_before_evaluation": "RAZORPAY",
- "priority_logic_output": {
- "isEnforcement": false,
- "gws": [],
- "priorityLogicTag": "PL_TEST",
- "gatewayReferenceIds": {},
- "primaryLogic": {
- "name": "PL_TEST",
- "status": "SUCCESS",
- "failure_reason": "NO_ERROR"
- },
- "fallbackLogic": null
- },
- "reset_approach": "NO_RESET",
- "routing_dimension": "ORDER_PAYMENT, UPI, UPI_PAY",
- "routing_dimension_level": "PM_LEVEL",
- "is_scheduled_outage": false,
- "gateway_mga_id_map": null
-}
-```
-
-### 2. Update Gateway Score
-
-This will update the decision-engine with the transaction status to optimize for future decisions:
-
-```bash
-curl --location 'http://localhost:8080/update-gateway-score' \
---header 'Content-Type: application/json' \
---data '{
- "merchantId": "test_merchant1",
- "gateway": "PAYU",
- "gatewayReferenceId": null,
- "status": "PENDING_VBV",
- "paymentId": "123"
-}'
-```
+Dashboard profiles also expose:
-## Glossary
-
-### Gateway Decision API Parameters
-
-| Parameter | Description |
-|-----------|-------------|
-| `merchantId` | Unique identifier assigned to the merchant using the API |
-| `eligibleGatewayList` | List of gateways eligible to process the transaction |
-| `rankingAlgorithm` | Specifies the routing algorithm to use (`SR_BASED_ROUTING` or `PL_BASED_ROUTING`) |
-| `eliminationEnabled` | Boolean flag to enable/disable downtime detection in routing decisions |
-
-#### Payment Info Parameters
-
-| Parameter | Description |
-|-----------|-------------|
-| `paymentId` | Unique identifier for the transaction (mandatory) |
-| `amount` | Transaction amount to be processed |
-| `currency` | Currency code for the transaction (e.g., INR, USD) |
-| `paymentType` | Indicates payment purpose (e.g., `ORDER_PAYMENT`, `MANDATE_REGISTER`, `EMANDATE_REGISTER`) |
-| `paymentMethodType` | Type of payment method (e.g., `CARD`, `UPI`, `WALLET`, `NET BANKING`) |
-| `paymentMethod` | Specific subcategory within the chosen paymentMethodType |
-
-### Response Fields
-
-| Field | Description |
-|-------|-------------|
-| `decided_gateway` | The gateway chosen by the decision engine for routing the transaction |
-| `gateway_priority_map` | Scores for each gateway used in making the routing decision |
-| `filter_wise_gateways` | List of eligible connectors (if Eligibility Check/Orchestration is used) |
-| `priority_logic_tag` | Unique identifier for the specific Static Rule defined in the YAML file |
-| `routing_approach` | The specific routing approach used for processing the transaction |
-| `gateway_before_evaluation` | The gateway decided before downtime evaluation |
-| `routing_dimension` | The dimensions on which routing decisions are made |
-| `routing_dimension_level` | The level at which routing decisions are made (e.g., `PM_LEVEL`) |
-| `is_scheduled_outage` | Returns true if the routing decision is impacted by scheduled outages |
-
-### Update Gateway Score Parameters
-
-| Parameter | Description |
-|-----------|-------------|
-| `merchantId` | Unique identifier assigned to the merchant using the API |
-| `gateway` | The gateway to which the transaction was routed |
-| `gatewayReferenceId` | Reference ID from the gateway |
-| `status` | Transaction status used to update the routing score |
-| `paymentId` | Unique identifier for the transaction |
-
-### Configuration YAML Parameters
-
-| Parameter | Description |
-|-----------|-------------|
-| `merchant_id` | Unique identifier assigned to the merchant |
-| `priority_logic.script` | The file name in which static rules are defined |
-| `priority_logic.tag` | Unique identifier for a static rule defined |
-| `elimination_config.threshold` | PG health threshold (PGs below this are deprioritized) |
-| `defaultBucketSize` | Last 'n' transactions to consider for computing SR scores |
-| `defaultHedgingPercent` | Percentage of traffic for exploration of lower-ranked gateways |
-| `subLevelInputConfig` | Define granular configs at PMT/PM level |
+- `http://localhost:8081/dashboard/`
+- `http://localhost:8081/introduction`
diff --git a/docs/setup-guide-postgres.md b/docs/setup-guide-postgres.md
index 187fd616..d6a47758 100644
--- a/docs/setup-guide-postgres.md
+++ b/docs/setup-guide-postgres.md
@@ -1,195 +1,56 @@
-# PostgreSQL Setup Guide for Decision Engine
+# PostgreSQL Setup Guide
-This guide provides instructions on how to set up the Decision Engine with PostgreSQL as the database. There are several ways to achieve this, depending on your preference for using Docker or a local PostgreSQL installation.
+Use this page when the task is explicitly PostgreSQL-specific. For the complete local matrix, use [Local Setup Guide](local-setup.md).
-## Prerequisites
+## Compose Commands
-Before you begin, ensure you have the necessary tools installed based on your chosen setup method.
+### Published-image track
-**Common Tools (potentially needed for all methods):**
+```bash
+export DECISION_ENGINE_TAG=v1.4
+docker compose --profile postgres-ghcr up -d
+```
-* A text editor or IDE for viewing/editing configuration files.
-* Git for cloning the project repository.
-* Rust and Cargo: Essential to build and run the Decision Engine application from source directly on your host machine.
+### Published-image track with dashboard + docs
-**For All Docker-Based Setups:**
+```bash
+docker compose --profile dashboard-postgres-ghcr up -d
+```
-* **Docker and Docker Compose**: Essential for running the application and database in containers.
+### Local-build track
+```bash
+docker compose --profile postgres-local up -d --build
+```
-**For Full Local Development Setup:**
+### Local-build track with dashboard + docs
-* **PostgreSQL**: Needed if you are managing a local PostgreSQL instance directly (e.g., for creating databases, running `just resurrect`).
-* **Just**: A command runner used for some of the local setup scripts (e.g., `just resurrect`, `just migrate-pg`). You can install it by following the instructions [here](https://github.com/casey/just#installation).
-* **Diesel CLI (with PostgreSQL feature)**: Required for managing database migrations when running against a local PostgreSQL database. Install using:
+```bash
+docker compose --profile dashboard-postgres-local up -d --build
+```
- ```bash
- cargo install diesel_cli --no-default-features --features postgres
- ```
+## Make Targets
-## Setup Options
+```bash
+make init-pg-ghcr
+make init-pg-local
+```
-Choose one of the following methods to set up the Decision Engine with PostgreSQL:
+## Source Run
-### 1. Using Pre-built Docker Image (Recommended for quick setup)
+```bash
+cargo build --release --no-default-features --features middleware,kms-aws,postgres
+just migrate-pg
+RUSTFLAGS="-Awarnings" cargo run --no-default-features --features postgres
+```
-This method uses pre-built Docker images for both the application and the PostgreSQL database. It's the simplest way to get started.
+## Verify
-**Steps:**
+```bash
+curl http://localhost:8080/health
+```
-1. Navigate to the root directory of the `decision-engine` project.
-2. Run the following command:
+Dashboard profiles also expose:
- ```bash
- make init-pg
- ```
-
- This command will:
- * Pull the necessary Docker images.
- * Start a PostgreSQL container.
- * Run database migrations using a `db-migrator-postgres` service defined in `docker-compose.yaml`.
- * Start the Decision Engine application container (`open-router-pg`), configured to connect to the PostgreSQL database.
-
-The application should now be running and accessible.
-
-### 2. Using Local Changes with PostgreSQL in Docker
-
-This method is useful if you are making changes to the Decision Engine codebase and want to test them with a PostgreSQL database running in Docker.
-
-**Steps:**
-
-1. Navigate to the root directory of the `decision-engine` project.
-2. Run the following command:
-
- ```bash
- make init-local-pg
- ```
-
- This command will:
- * Start a PostgreSQL container.
- * Run database migrations using the `db-migrator-postgres` service.
- * Build the Decision Engine application from your local source code within a Docker container (`open-router-local-pg`).
- * Start the newly built application container, connected to the PostgreSQL database.
-
-This allows you to test your local code changes in an environment where PostgreSQL is managed by Docker.
-
-### 3. Using Local Changes with a Local PostgreSQL Installation
-
-This method is for developers who have PostgreSQL installed and running directly on their local machine (not in Docker).
-
-**Steps:**
-
-1. **Ensure PostgreSQL is Running:**
- Make sure your local PostgreSQL server is running and accessible.
-
-2. **Set up Environment Variables (Optional but Recommended):**
- The application and `diesel` CLI use environment variables to connect to the database.
-
- The `Justfile` provides defaults if these are not set:
- * `DB_USER` (default: `db_user`)
- * `DB_PASSWORD` (default: `db_pass`)
- * `DB_HOST` (default: `localhost`)
- * `DB_PORT` (default: `5432`)
- * `DB_NAME` (default: `decision_engine_db`)
- * `DATABASE_URL` (derived default: `postgresql://db_user:db_pass@localhost:5432/decision_engine_db`)
-
- **Example of exporting variables in your shell (using default values):**
- ```bash
- export DB_USER="db_user"
- export DB_PASSWORD="db_pass"
- export DB_HOST="localhost"
- export DB_PORT="5432"
- export DB_NAME="decision_engine_db"
- # DATABASE_URL will be constructed by the application or Justfile if not set,
- ```
-3. **Drop Database if Exist:**
-
- ```bash
- just resurrect
- ```
- This command will drop the Database and create a new one.
-4. **Run Database Migrations:**
- Apply the database schema migrations to your local PostgreSQL database:
-
- ```bash
- just migrate-pg
- ```
- This command uses `diesel migration run` with the PostgreSQL specific migration directory (`migrations_pg`) and configuration file (`diesel_pg.toml`).
-
-5. **Run the Application:**
- Compile and run the Decision Engine application, ensuring it's built with PostgreSQL features:
- ```bash
- RUSTFLAGS="-Awarnings" cargo run --no-default-features --features postgres
- ```
- * `RUSTFLAGS="-Awarnings"`: Suppresses warnings during compilation (optional).
- * `--no-default-features --features postgres`: Ensures the application is compiled specifically for PostgreSQL, excluding default features (like MySQL support if it's a default) and including the `postgres` feature.
-
-The application will start and connect to your local PostgreSQL database.
-
-## Configuration
-
-The database connection URL is typically configured in:
-
-* `config/development.toml` (for local cargo runs)
-* `config/docker-configuration.toml` (often mapped into Docker containers)
-
-Ensure the `[database.url]` points to your PostgreSQL instance. For example:
-`url = "postgresql://db_user:db_pass@localhost:5432/decision_engine_db"`
-
-For Docker setups (`make init-pg`, `make init-local-pg`), the `docker-compose.yaml` file handles the service linking and environment variables to ensure the application container can connect to the PostgreSQL container (usually aliased as `postgres` or a similar hostname within the Docker network).
-
-## Troubleshooting
-
-* **Connection Issues:**
- * Verify `DATABASE_URL` is correct and the PostgreSQL server is accessible from where the application is running (your local machine or Docker container).
- * Check PostgreSQL logs for any connection errors.
- * Ensure firewalls are not blocking the connection.
-* **Migration Failures:**
- * Check `diesel_pg.toml` for correct configuration.
- * Ensure the migration files in `migrations_pg/` are correctly formatted.
- * If you encounter issues with a "dirty" database state after a failed migration, you might need to manually resolve it in the database or use `diesel migration redo` (with caution).
-* **`just` command not found:**
- * Install `just` by following its official installation guide.
-* **`diesel` command not found:**
- * Install `diesel_cli` with PostgreSQL support: `cargo install diesel_cli --no-default-features --features postgres`.
-
-This guide should help you get the Decision Engine up and running with PostgreSQL.
-
-
-# Metrics
-
-This document provides an overview of the metrics implementation in the routing layer.
-
-## Overview
-
-The metrics server is responsible for exposing key performance indicators of the application. It uses the `prometheus` crate to register and expose metrics in a format that can be scraped by a Prometheus server.
-
-## How it works
-
-The metrics server is built using `axum` and runs on a separate port from the main application server. It exposes a `/metrics` endpoint that returns the current state of all registered metrics.
-
-The server is initialized in the `metrics_server_builder` function in `src/metrics.rs`. This function creates a new `axum` router and binds it to the address specified in the configuration.
-
-## Available Metrics
-
-The following metrics are exposed by the server:
-
-### Counters
-
-- `api_requests_total`: A counter that tracks the total number of API requests received by the application. It has a single label, `endpoint`, which is the path of the API endpoint that was called.
-
-- `api_requests_by_status`: A counter that tracks the number of API requests grouped by endpoint and result status. It has two labels: `endpoint` and `status`.
-
-### Histograms
-
-- `api_latency_seconds`: A histogram that measures the latency of API calls. It has a single label, `endpoint`, and uses exponential buckets to provide a detailed view of the latency distribution.
-
-## How to check metrics
-
-To check the metrics, you can hit the following endpoint:
-
-```sh
-curl http://127.0.0.1:9090/metrics
-````
-
-This will return a text-based representation of the current metrics, which can be ingested by a Prometheus server.
+- `http://localhost:8081/dashboard/`
+- `http://localhost:8081/introduction`
diff --git a/docs/setup-guide.md b/docs/setup-guide.md
index 89012211..f0ce7bc8 100644
--- a/docs/setup-guide.md
+++ b/docs/setup-guide.md
@@ -1,167 +1,18 @@
-# Installation Guide
+# Setup Guide
-This guide provides detailed instructions for installing Dynamo on different platforms.
+Use this page as an index, not as the primary source.
-## Prerequisites
+## Canonical Guide
-- Rust 1.78.0 or later
-- Redis server 6.0 or later
-- Git
+- [Local Setup Guide](local-setup.md)
-## From Source
+## Database-Specific Guides
-### 1. Clone the Repository
+- [PostgreSQL Setup Guide](setup-guide-postgres.md)
+- [MySQL Setup Guide](setup-guide-mysql.md)
-```bash
-git clone https://github.com/yourusername/dynamo.git
-cd dynamo
-```
+## When To Use Which Page
-### 2. Install Dependencies
-
-#### Ubuntu/Debian
-
-```bash
-# Install system dependencies
-sudo apt-get update
-sudo apt-get install -y pkg-config libssl-dev protobuf-compiler libpq-dev
-
-# Install Rust (if not already installed)
-curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
-source $HOME/.cargo/env
-```
-
-#### macOS
-
-```bash
-# Using Homebrew
-brew install pkg-config openssl protobuf postgresql
-
-# Install Rust (if not already installed)
-curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
-source $HOME/.cargo/env
-```
-
-### 3. Build Dynamo
-
-```bash
-# Build in release mode
-cargo build --release
-```
-
-### 4. Set Up Configuration
-
-```bash
-# Copy example configuration
-cp config/config.example.toml config/development.toml
-
-# Edit configuration as needed
-# vi config/development.toml
-```
-
-### 5. Run Redis
-
-Make sure Redis is running on your system:
-
-```bash
-# Install Redis if needed
-sudo apt-get install redis-server # Ubuntu/Debian
-brew install redis # macOS
-
-# Start Redis server
-redis-server
-```
-
-### 6. Run Dynamo
-
-```bash
-# Run with development configuration
-./target/release/dynamo
-```
-
-## Using Docker
-
-### 1. Pull the Docker Image
-
-```bash
-docker pull yourusername/dynamo:latest
-```
-
-Or build it yourself:
-
-```bash
-docker build -t dynamo:latest .
-```
-
-### 2. Run with Docker
-
-```bash
-# Run with default configuration
-docker run -p 8000:8000 -p 9000:9000 dynamo:latest
-
-# Run with custom configuration
-docker run -p 8000:8000 -p 9000:9000 \
- -v $(pwd)/config:/app/config \
- dynamo:latest
-```
-
-### 3. Docker Compose Setup
-
-Create a `docker-compose.yml` file:
-
-```yaml
-version: '3'
-services:
- dynamo:
- image: yourusername/dynamo:latest
- ports:
- - "8000:8000"
- - "9000:9000"
- volumes:
- - ./config:/app/config
- depends_on:
- - redis
-
- redis:
- image: redis:latest
- ports:
- - "6379:6379"
-```
-
-Run with Docker Compose:
-
-```bash
-docker-compose up -d
-```
-
-## Building the WebAssembly Module
-
-The `procesmo` module can be built for web use:
-
-```bash
-# Install wasm-pack if needed
-cargo install wasm-pack
-
-# Build the WebAssembly module
-cd crates/procesmo
-wasm-pack build --target web
-```
-
-## Verifying Installation
-
-To verify that Dynamo is running correctly:
-
-```bash
-# Check health status
-curl http://localhost:8000/grpc.health.v1.Health/Check
-
-# Or using grpcurl
-grpcurl -plaintext localhost:8000 grpc.health.v1.Health/Check
-```
-
-You should see a response indicating the service is running.
-
-## Next Steps
-
-- [Configure Dynamo](configuration.md) for your environment
-- [Explore the API](api-reference.md)
+- full local bring-up, Compose profiles, source builds, and Helm: `local-setup.md`
+- PostgreSQL-specific shortcuts: `setup-guide-postgres.md`
+- MySQL-specific shortcuts: `setup-guide-mysql.md`
diff --git a/helm-charts/Chart.lock b/helm-charts/Chart.lock
index d2744324..ec96fdf4 100644
--- a/helm-charts/Chart.lock
+++ b/helm-charts/Chart.lock
@@ -1,12 +1,12 @@
dependencies:
- name: postgresql
repository: https://charts.bitnami.com/bitnami
- version: 12.5.9
+ version: 18.5.14
- name: mysql
repository: https://charts.bitnami.com/bitnami
- version: 13.0.0
+ version: 13.0.4
- name: redis
repository: https://charts.bitnami.com/bitnami
- version: 17.11.8
-digest: sha256:a30a5d9f1cd2bdc84f9f36f3909d75b6702b996ad454cff2737cd738303b6420
-generated: "2025-06-04T21:08:21.265499+05:30"
+ version: 25.3.9
+digest: sha256:9d54be26fed3d4599bdc5426e4a22ede83361404744e227266b41bee4b7d3ffd
+generated: "2026-03-31T14:29:48.785567+05:30"
diff --git a/helm-charts/Chart.yaml b/helm-charts/Chart.yaml
index aa8323d7..ecb6082d 100644
--- a/helm-charts/Chart.yaml
+++ b/helm-charts/Chart.yaml
@@ -6,14 +6,14 @@ version: 0.1.0
appVersion: "1.0.0"
dependencies:
- name: postgresql
- version: ~12.5.5
+ version: ~18.5.14
repository: https://charts.bitnami.com/bitnami
condition: postgresql.enabled
- name: mysql
- version: ~13.0.0
+ version: ~13.0.4
repository: https://charts.bitnami.com/bitnami
condition: mysql.enabled
- name: redis
- version: ~17.11.3
+ version: ~25.3.9
repository: https://charts.bitnami.com/bitnami
condition: redis.enabled
diff --git a/helm-charts/README.md b/helm-charts/README.md
index e2531b15..6a3c457c 100644
--- a/helm-charts/README.md
+++ b/helm-charts/README.md
@@ -60,6 +60,24 @@ Then, to install the chart with the release name `my-release`:
helm install my-release .
```
+To pin a specific on-prem image version (for example `v1.4`):
+
+```bash
+helm install my-release . \
+ --set image.repository=ghcr.io/juspay/decision-engine/postgres \
+ --set image.version=v1.4 \
+ --set image.pullPolicy=Always
+```
+
+To use an internal/private registry:
+
+```bash
+helm install my-release . \
+ --set image.repository=/decision-engine/postgres \
+ --set image.version= \
+ --set image.pullPolicy=IfNotPresent
+```
+
The command deploys Decision Engine on the Kubernetes cluster with the default configuration. The [Parameters](#parameters) section lists the parameters that can be configured during installation.
## Uninstalling the Chart
@@ -77,8 +95,8 @@ helm delete my-release
| Name | Description | Value |
|---------------------|---------------------------------------------------------------------------------------|-----------------|
| `replicaCount` | Number of Decision Engine replicas | `1` |
-| `image.repository` | Decision Engine image repository | `decision-engine` |
-| `image.version` | Decision Engine image tag | `latest` |
+| `image.repository` | Decision Engine image repository | `ghcr.io/juspay/decision-engine/postgres` |
+| `image.version` | Decision Engine image tag | `v1.4` |
| `image.pullPolicy` | Decision Engine image pull policy | `Always` |
| `imagePullSecrets` | Image pull secrets | `[]` |
| `nameOverride` | Override the name of the chart | `""` |
@@ -136,8 +154,8 @@ helm delete my-release
| Name | Description | Value |
|-----------------------------------------|------------------------------------------------------------|-----------------|
| `groovyRunner.enabled` | Deploy Groovy Runner | `true` |
-| `groovyRunner.image.repository` | Groovy Runner image repository | `"groovy-runner"` |
-| `groovyRunner.image.version` | Groovy Runner image tag | `"latest"` |
+| `groovyRunner.image.repository` | Groovy Runner image repository | `"ghcr.io/juspay/decision-engine/groovy-runner"` |
+| `groovyRunner.image.version` | Groovy Runner image tag | `"v1.4"` |
| `groovyRunner.image.pullPolicy` | Groovy Runner image pull policy | `"Always"` |
| `groovyRunner.service.port` | Groovy Runner service port | `8085` |
| `groovyRunner.resources` | Groovy Runner resources | `{}` |
diff --git a/helm-charts/charts/mysql-13.0.0.tgz b/helm-charts/charts/mysql-13.0.0.tgz
deleted file mode 100644
index ab18090b..00000000
Binary files a/helm-charts/charts/mysql-13.0.0.tgz and /dev/null differ
diff --git a/helm-charts/charts/mysql-13.0.4.tgz b/helm-charts/charts/mysql-13.0.4.tgz
new file mode 100644
index 00000000..12c0e3b6
Binary files /dev/null and b/helm-charts/charts/mysql-13.0.4.tgz differ
diff --git a/helm-charts/charts/postgresql-12.5.9.tgz b/helm-charts/charts/postgresql-12.5.9.tgz
deleted file mode 100644
index 490097c4..00000000
Binary files a/helm-charts/charts/postgresql-12.5.9.tgz and /dev/null differ
diff --git a/helm-charts/charts/postgresql-18.5.14.tgz b/helm-charts/charts/postgresql-18.5.14.tgz
new file mode 100644
index 00000000..41fb11ae
Binary files /dev/null and b/helm-charts/charts/postgresql-18.5.14.tgz differ
diff --git a/helm-charts/charts/redis-17.11.8.tgz b/helm-charts/charts/redis-17.11.8.tgz
deleted file mode 100644
index 1aed4703..00000000
Binary files a/helm-charts/charts/redis-17.11.8.tgz and /dev/null differ
diff --git a/helm-charts/charts/redis-25.3.9.tgz b/helm-charts/charts/redis-25.3.9.tgz
new file mode 100644
index 00000000..4a388783
Binary files /dev/null and b/helm-charts/charts/redis-25.3.9.tgz differ
diff --git a/helm-charts/config/development.toml b/helm-charts/config/development.toml
new file mode 120000
index 00000000..7f052ec6
--- /dev/null
+++ b/helm-charts/config/development.toml
@@ -0,0 +1 @@
+../../config/development.toml
\ No newline at end of file
diff --git a/helm-charts/templates/configmap.yaml b/helm-charts/templates/configmap.yaml
index deb33f26..dfa1a13d 100644
--- a/helm-charts/templates/configmap.yaml
+++ b/helm-charts/templates/configmap.yaml
@@ -6,159 +6,4 @@ metadata:
{{- include "decision-engine.labels" . | nindent 4 }}
data:
development.toml: |-
- {{- include "decision-engine.configFile" . | nindent 4 }}
-
- [routing_config.keys]
- billing_country = {type = "enum", values = "Afghanistan, AlandIslands, Albania, Algeria, AmericanSamoa, Andorra, Angola, Anguilla, Antarctica, AntiguaAndBarbuda, Argentina, Armenia, Aruba, Australia, Austria, Azerbaijan, Bahamas, Bahrain, Bangladesh, Barbados, Belarus, Belgium, Belize, Benin, Bermuda, Bhutan, BoliviaPlurinationalState, BonaireSintEustatiusAndSaba, BosniaAndHerzegovina, Botswana, BouvetIsland, Brazil, BritishIndianOceanTerritory, BruneiDarussalam, Bulgaria, BurkinaFaso, Burundi, CaboVerde, Cambodia, Cameroon, Canada, CaymanIslands, CentralAfricanRepublic, Chad, Chile, China, ChristmasIsland, CocosKeelingIslands, Colombia, Comoros, Congo, CongoDemocraticRepublic, CookIslands, CostaRica, CotedIvoire, Croatia, Cuba, Curacao, Cyprus, Czechia, Denmark, Djibouti, Dominica, DominicanRepublic, Ecuador, Egypt, ElSalvador, EquatorialGuinea, Eritrea, Estonia, Ethiopia, FalklandIslandsMalvinas, FaroeIslands, Fiji, Finland, France, FrenchGuiana, FrenchPolynesia, FrenchSouthernTerritories, Gabon, Gambia, Georgia, Germany, Ghana, Gibraltar, Greece, Greenland, Grenada, Guadeloupe, Guam, Guatemala, Guernsey, Guinea, GuineaBissau, Guyana, Haiti, HeardIslandAndMcDonaldIslands, HolySee, Honduras, HongKong, Hungary, Iceland, India, Indonesia, IranIslamicRepublic, Iraq, Ireland, IsleOfMan, Israel, Italy, Jamaica, Japan, Jersey, Jordan, Kazakhstan, Kenya, Kiribati, KoreaDemocraticPeoplesRepublic, KoreaRepublic, Kuwait, Kyrgyzstan, LaoPeoplesDemocraticRepublic, Latvia, Lebanon, Lesotho, Liberia, Libya, Liechtenstein, Lithuania, Luxembourg, Macao, MacedoniaTheFormerYugoslavRepublic, Madagascar, Malawi, Malaysia, Maldives, Mali, Malta, MarshallIslands, Martinique, Mauritania, Mauritius, Mayotte, Mexico, MicronesiaFederatedStates, MoldovaRepublic, Monaco, Mongolia, Montenegro, Montserrat, Morocco, Mozambique, Myanmar, Namibia, Nauru, Nepal, Netherlands, NewCaledonia, NewZealand, Nicaragua, Niger, Nigeria, Niue, NorfolkIsland, NorthernMarianaIslands, Norway, Oman, Pakistan, Palau, PalestineState, Panama, PapuaNewGuinea, Paraguay, Peru, Philippines, Pitcairn, Poland, Portugal, PuertoRico, Qatar, Reunion, Romania, RussianFederation, Rwanda, SaintBarthelemy, SaintHelenaAscensionAndTristandaCunha, SaintKittsAndNevis, SaintLucia, SaintMartinFrenchpart, SaintPierreAndMiquelon, SaintVincentAndTheGrenadines, Samoa, SanMarino, SaoTomeAndPrincipe, SaudiArabia, Senegal, Serbia, Seychelles, SierraLeone, Singapore, SintMaartenDutchpart, Slovakia, Slovenia, SolomonIslands, Somalia, SouthAfrica, SouthGeorgiaAndTheSouthSandwichIslands, SouthSudan, Spain, SriLanka, Sudan, Suriname, SvalbardAndJanMayen, Swaziland, Sweden, Switzerland, SyrianArabRepublic, TaiwanProvinceOfChina, Tajikistan, TanzaniaUnitedRepublic, Thailand, TimorLeste, Togo, Tokelau, Tonga, TrinidadAndTobago, Tunisia, Turkey, Turkmenistan, TurksAndCaicosIslands, Tuvalu, Uganda, Ukraine, UnitedArabEmirates, UnitedKingdomOfGreatBritainAndNorthernIreland, UnitedStatesOfAmerica, UnitedStatesMinorOutlyingIslands, Uruguay, Uzbekistan, Vanuatu, VenezuelaBolivarianRepublic, Vietnam, VirginIslandsBritish, VirginIslandsUS, WallisAndFutuna, WesternSahara, Yemen, Zambia, Zimbabwe"}
- business_country = {type = "enum", values = "Afghanistan, AlandIslands, Albania, Algeria, AmericanSamoa, Andorra, Angola, Anguilla, Antarctica, AntiguaAndBarbuda, Argentina, Armenia, Aruba, Australia, Austria, Azerbaijan, Bahamas, Bahrain, Bangladesh, Barbados, Belarus, Belgium, Belize, Benin, Bermuda, Bhutan, BoliviaPlurinationalState, BonaireSintEustatiusAndSaba, BosniaAndHerzegovina, Botswana, BouvetIsland, Brazil, BritishIndianOceanTerritory, BruneiDarussalam, Bulgaria, BurkinaFaso, Burundi, CaboVerde, Cambodia, Cameroon, Canada, CaymanIslands, CentralAfricanRepublic, Chad, Chile, China, ChristmasIsland, CocosKeelingIslands, Colombia, Comoros, Congo, CongoDemocraticRepublic, CookIslands, CostaRica, CotedIvoire, Croatia, Cuba, Curacao, Cyprus, Czechia, Denmark, Djibouti, Dominica, DominicanRepublic, Ecuador, Egypt, ElSalvador, EquatorialGuinea, Eritrea, Estonia, Ethiopia, FalklandIslandsMalvinas, FaroeIslands, Fiji, Finland, France, FrenchGuiana, FrenchPolynesia, FrenchSouthernTerritories, Gabon, Gambia, Georgia, Germany, Ghana, Gibraltar, Greece, Greenland, Grenada, Guadeloupe, Guam, Guatemala, Guernsey, Guinea, GuineaBissau, Guyana, Haiti, HeardIslandAndMcDonaldIslands, HolySee, Honduras, HongKong, Hungary, Iceland, India, Indonesia, IranIslamicRepublic, Iraq, Ireland, IsleOfMan, Israel, Italy, Jamaica, Japan, Jersey, Jordan, Kazakhstan, Kenya, Kiribati, KoreaDemocraticPeoplesRepublic, KoreaRepublic, Kuwait, Kyrgyzstan, LaoPeoplesDemocraticRepublic, Latvia, Lebanon, Lesotho, Liberia, Libya, Liechtenstein, Lithuania, Luxembourg, Macao, MacedoniaTheFormerYugoslavRepublic, Madagascar, Malawi, Malaysia, Maldives, Mali, Malta, MarshallIslands, Martinique, Mauritania, Mauritius, Mayotte, Mexico, MicronesiaFederatedStates, MoldovaRepublic, Monaco, Mongolia, Montenegro, Montserrat, Morocco, Mozambique, Myanmar, Namibia, Nauru, Nepal, Netherlands, NewCaledonia, NewZealand, Nicaragua, Niger, Nigeria, Niue, NorfolkIsland, NorthernMarianaIslands, Norway, Oman, Pakistan, Palau, PalestineState, Panama, PapuaNewGuinea, Paraguay, Peru, Philippines, Pitcairn, Poland, Portugal, PuertoRico, Qatar, Reunion, Romania, RussianFederation, Rwanda, SaintBarthelemy, SaintHelenaAscensionAndTristandaCunha, SaintKittsAndNevis, SaintLucia, SaintMartinFrenchpart, SaintPierreAndMiquelon, SaintVincentAndTheGrenadines, Samoa, SanMarino, SaoTomeAndPrincipe, SaudiArabia, Senegal, Serbia, Seychelles, SierraLeone, Singapore, SintMaartenDutchpart, Slovakia, Slovenia, SolomonIslands, Somalia, SouthAfrica, SouthGeorgiaAndTheSouthSandwichIslands, SouthSudan, Spain, SriLanka, Sudan, Suriname, SvalbardAndJanMayen, Swaziland, Sweden, Switzerland, SyrianArabRepublic, TaiwanProvinceOfChina, Tajikistan, TanzaniaUnitedRepublic, Thailand, TimorLeste, Togo, Tokelau, Tonga, TrinidadAndTobago, Tunisia, Turkey, Turkmenistan, TurksAndCaicosIslands, Tuvalu, Uganda, Ukraine, UnitedArabEmirates, UnitedKingdomOfGreatBritainAndNorthernIreland, UnitedStatesOfAmerica, UnitedStatesMinorOutlyingIslands, Uruguay, Uzbekistan, Vanuatu, VenezuelaBolivarianRepublic, Vietnam, VirginIslandsBritish, VirginIslandsUS, WallisAndFutuna, WesternSahara, Yemen, Zambia, Zimbabwe"}
- business_label = { type = "udf"}
- metadata = {type = "udf"}
- pay_later = {type = "enum", values = "Affirm, Alma, AfterpayClearpay, Klarna, PayBright, Atome, Walley"}
- gift_card = {type = "enum", values = "Givex, PaySafeCard"}
- wallet = {type = "enum", values = "AmazonPay, ApplePay, GooglePay, Paypal, AliPay, AliPayHk, Dana, MbWay, MobilePay, SamsungPay, Twint, Vipps, TouchNGo, Swish, WeChatPay, GoPay, Gcash, Momo, KakaoPay, Cashapp, Mifinity, Paze"}
- upi = {type = "enum", values = "UpiCollect, UpiIntent"}
- voucher = {type = "enum", values = "Boleto, Efecty, PagoEfectivo, RedCompra, RedPagos, Indomaret, Alfamart, Oxxo, SevenEleven, Lawson, MiniStop, FamilyMart, Seicomart, PayEasy"}
- bank_transfer = {type = "enum", values = "Ach, SepaBankTransfer, Bacs, Multibanco, Pix, Pse, PermataBankTransfer, BcaBankTransfer, BniVa, BriVa, CimbVa, DanamonVa, MandiriVa, LocalBankTransfer, InstantBankTransfer"}
- bank_redirect = {type = "enum", values = "Giropay, Ideal, Sofort, Eft, Eps, BancontactCard, Blik, LocalBankRedirect, OnlineBankingThailand, OnlineBankingCzechRepublic, OnlineBankingFinland, OnlineBankingFpx, OnlineBankingPoland, OnlineBankingSlovakia, Przelewy24, Trustly, Bizum, Interac, OpenBankingUk, OpenBankingPIS"}
- bank_debit = {type = "enum", values = "Ach, Sepa, Bacs, Becs"}
- crypto = {type = "enum", values = "CryptoCurrency"}
- reward = {type = "enum", values = "Evoucher, ClassicReward"}
- card_redirect = {type = "enum", values = "Knet, Benefit, MomoAtm, CardRedirect"}
- real_time_payment = {type = "enum", values = "Fps, DuitNow, PromptPay, VietQr"}
- open_banking = {type = "enum", values = "OpenBankingPIS"}
- mobile_payment = {type = "enum", values = "DirectCarrierBilling"}
- payment_method = {type = "enum", values = "card, card_redirect, pay_later, wallet, bank_redirect, bank_transfer, crypto, bank_debit, reward, real_time_payment, upi, voucher, gift_card, open_banking, mobile_payment"}
- payment_card_bin = {type = "udf"}
- payment_card_type = {type = "enum", values = "CREDIT, DEBIT"}
- mandate_acceptance_type = {type = "enum", values= "Online, Offline"}
- card_network = {type = "enum", values = "Visa, Mastercard, AmericanExpress, JCB, DinersClub, Discover, CartesBancaires, UnionPay, Interac, RuPay, Maestro, Star, Pulse, Accel, Nyce"}
- mandate_type = {type = "enum", values= "SingleUse, MultiUse"}
- payment_type = {type = "enum", values = "normal, new_mandate, setup_mandate, recurring_mandate, non_mandate"}
- payment_method_type = {type = "enum", values = "ach, affirm, afterpay_clearpay, alfamart, ali_pay, ali_pay_hk, alma, amazon_pay, apple_pay, atome, bacs, bancontact_card, becs, benefit, bizum, blik, boleto, bca_bank_transfer, bni_va, bri_va, card, card_redirect, cimb_va, classic_reward, credit, crypto_currency, cashapp, dana, danamon_va, debit, duit_now, efecty, eft, eps, fps, evoucher, giropay, givex, google_pay, go_pay, gcash, ideal, interac, indomaret, klarna, kakao_pay, local_bank_redirect, mandiri_va, knet, mb_way, mobile_pay, momo, momo_atm, multibanco, online_banking_thailand, online_banking_czech_republic, online_banking_finland, online_banking_fpx, online_banking_poland, online_banking_slovakia, oxxo, pago_efectivo, permata_bank_transfer, open_banking_uk, pay_bright, paypal, paze, pix, pay_safe_card, przelewy24, prompt_pay, pse, red_compra, red_pagos, samsung_pay, sepa, sepa_bank_transfer, sofort, swish, touch_n_go, trustly, twint, upi_collect, upi_intent, vipps, viet_qr, venmo, walley, we_chat_pay, seven_eleven, lawson, mini_stop, family_mart, seicomart, pay_easy, local_bank_transfer, mifinity, open_banking_pis, direct_carrier_billing, instant_bank_transfer"}
- authentication_type = {type = "enum", values = "three_ds, no_three_ds"}
- capture_methods = {type = "enum", values = "automatic, manual, manual_multiple, scheduled, sequential_automatic"}
- setup_future_usage = {type = "enum", values = "on_session, off_session"}
- payment_card_network = {type = "enum", values = "visa, mastercard, american_express, jcb, diners_club, discover, cartes_bancaires, union_pay, interac, rupay, maestro"}
- amount = {type = "integer"}
- login_date = {type = "str"}
- currency = {type = "enum", values = "AED, AFN, ALL, AMD, ANG, AOA, ARS, AUD, AWG, AZN, BAM, BBD, BDT, BGN, BHD, BIF, BMD, BND, BOB, BRL, BSD, BTN, BWP, BYN, BZD, CAD, CDF, CHF, CLF, CLP, CNY, COP, CRC, CUC, CUP, CVE, CZK, DJF, DKK, DOP, DZD, EGP, ERN, ETB, EUR, FJD, FKP, GBP, GEL, GHS, GIP, GMD, GNF, GTQ, GYD, HKD, HNL, HRK, HTG, HUF, IDR, ILS, INR, IQD, IRR, ISK, JMD, JOD, JPY, KES, KGS, KHR, KMF, KPW, KRW, KWD, KYD, KZT, LAK, LBP, LKR, LRD, LSL, LYD, MAD, MDL, MGA, MKD, MMK, MNT, MOP, MRU, MUR, MVR, MWK, MXN, MYR, MZN, NAD, NGN, NIO, NOK, NPR, NZD, OMR, PAB, PEN, PGK, PHP, PKR, PLN, PYG, QAR, RON, RSD, RUB, RWF, SAR, SBD, SCR, SDG, SEK, SGD, SHP, SLE, SLL, SOS, SRD, SSP, STD, STN, SVC, SYP, SZL, THB, TJS, TMT, TND, TOP, TRY, TTD, TWD, TZS, UAH, UGX, USD, UYU, UZS, VES, VND, VUV, WST, XAF, XCD, XOF, XPF, YER, ZAR, ZMW, ZWL"}
- payment_card_issuer_country = { type = "enum", values = "AF, AX, AL, DZ, AS, AD, AO, AI, AQ, AG, AR, AM, AW, AU, AT, AZ, BS, BH, BD, BB, BY, BE, BZ, BJ, BM, BT, BO, BQ, BA, BW, BV, BR, IO, BN, BG, BF, BI, KH, CM, CA, CV, KY, CF, TD, CL, CN, CX, CC, CO, KM, CG, CD, CK, CR, CI, HR, CU, CW, CY, CZ, DK, DJ, DM, DO, EC, EG, SV, GQ, ER, EE, ET, FK, FO, FJ, FI, FR, GF, PF, TF, GA, GM, GE, DE, GH, GI, GR, GL, GD, GP, GU, GT, GG, GN, GW, GY, HT, HM, VA, HN, HK, HU, IS, IN, ID, IR, IQ, IE, IM, IL, IT, JM, JP, JE, JO, KZ, KE, KI, KP, KR, KW, KG, LA, LV, LB, LS, LR, LY, LI, LT, LU, MO, MK, MG, MW, MY, MV, ML, MT, MH, MQ, MR, MU, YT, MX, FM, MD, MC, MN, ME, MS, MA, MZ, MM, NA, NR, NP, NL, NC, NZ, NI, NE, NG, NU, NF, MP, NO, OM, PK, PW, PS, PA, PG, PY, PE, PH, PN, PL, PT, PR, QA, RE, RO, RU, RW, BL, SH, KN, LC, MF, PM, VC, WS, SM, ST, SA, SN, RS, SC, SL, SG, SX, SK, SI, SB, SO, ZA, GS, SS, ES, LK, SD, SR, SJ, SZ, SE, CH, SY, TW, TJ, TZ, TH, TL, TG, TK, TO, TT, TN, TR, TM, TC, TV, UG, UA, AE, GB, UM, UY, UZ, VU, VE, VN, VG, VI, WF, EH, YE, ZM, ZW, US"}
- card_bin = {type = "str"}
- capture_method = {type = "enum", values = "automatic, manual"}
- new_customer = {type = "udf"}
-
-
- udf1 = {type = "str"}
- order_udf1 = {type = "global_ref"}
- payment_payment_method = {type = "enum", values = "NB_HDFC, NB_ICICI, NB_SBI"}
- payment_payment_source = {type = "enum", values = "net.one97.paytm, @paytm"}
- txn_is_emi = {type = "enum", values = "true, false"}
-
- [routing_config.default]
- output = ["stripe", "adyen"]
-
- [[routing_config.constraint_graph.nodes]]
- preds = []
- succs = [0]
-
- [routing_config.constraint_graph.nodes.kind]
- kind = "value"
-
- [routing_config.constraint_graph.nodes.kind.data]
- kind = "value"
-
- [routing_config.constraint_graph.nodes.kind.data.data]
- key = "payment_method"
- comparison = "equal"
-
- [routing_config.constraint_graph.nodes.kind.data.data.value]
- type = "enum_variant"
- value = "card"
-
- [[routing_config.constraint_graph.nodes]]
- preds = []
- succs = [1]
-
- [routing_config.constraint_graph.nodes.kind]
- kind = "value"
-
- [routing_config.constraint_graph.nodes.kind.data]
- kind = "value"
-
- [routing_config.constraint_graph.nodes.kind.data.data]
- key = "payment_method"
- comparison = "equal"
-
- [routing_config.constraint_graph.nodes.kind.data.data.value]
- type = "enum_variant"
- value = "bank_debit"
-
- [[routing_config.constraint_graph.nodes]]
- preds = [0]
- succs = []
-
- [routing_config.constraint_graph.nodes.kind]
- kind = "value"
-
- [routing_config.constraint_graph.nodes.kind.data]
- kind = "value"
-
- [routing_config.constraint_graph.nodes.kind.data.data]
- key = "output"
- comparison = "equal"
-
- [routing_config.constraint_graph.nodes.kind.data.data.value]
- type = "enum_variant"
- value = "stripe"
-
- [[routing_config.constraint_graph.nodes]]
- preds = [1]
- succs = []
-
- [routing_config.constraint_graph.nodes.kind]
- kind = "value"
-
- [routing_config.constraint_graph.nodes.kind.data]
- kind = "value"
-
- [routing_config.constraint_graph.nodes.kind.data.data]
- key = "output"
- comparison = "equal"
-
- [routing_config.constraint_graph.nodes.kind.data.data.value]
- type = "enum_variant"
- value = "adyen"
-
- [[routing_config.constraint_graph.edges]]
- strength = "strong"
- relation = "positive"
- pred = 0
- succ = 2
-
- [[routing_config.constraint_graph.edges]]
- strength = "strong"
- relation = "positive"
- pred = 1
- succ = 3
-
- [debit_routing_config]
- fraud_check_fee = 0.01
-
- [debit_routing_config.network_fee]
- visa = { percentage = 0.1375, fixed_amount = 0.020 }
- mastercard = { percentage = 0.15, fixed_amount = 0.40 }
- accel = { percentage = 0.0, fixed_amount = 0.040 }
- nyce = { percentage = 0.10, fixed_amount = 0.015 }
- pulse = { percentage = 0.10, fixed_amount = 0.03 }
- star = { percentage = 0.10, fixed_amount = 0.015 }
-
- [debit_routing_config.interchange_fee]
- regulated = { percentage = 0.05, fixed_amount = 0.21 }
-
- [debit_routing_config.interchange_fee.non_regulated]
- merchant_category_code_0001.visa = { percentage = 1.65, fixed_amount = 0.15 }
- merchant_category_code_0001.mastercard = { percentage = 1.65, fixed_amount = 0.15 }
- merchant_category_code_0001.accel = { percentage = 1.55, fixed_amount = 0.04 }
- merchant_category_code_0001.nyce = { percentage = 1.30, fixed_amount = 0.213125 }
- merchant_category_code_0001.pulse = { percentage = 1.60, fixed_amount = 0.15 }
- merchant_category_code_0001.star = { percentage = 1.63, fixed_amount = 0.15 }
+ {{ .Files.Get "config/development.toml" | nindent 4 }}
\ No newline at end of file
diff --git a/helm-charts/templates/deployment.yaml b/helm-charts/templates/deployment.yaml
index e579c6a2..c5dbea8f 100644
--- a/helm-charts/templates/deployment.yaml
+++ b/helm-charts/templates/deployment.yaml
@@ -28,25 +28,31 @@ spec:
serviceAccountName: {{ include "decision-engine.serviceAccountName" . }}
securityContext:
{{- toYaml .Values.podSecurityContext | nindent 8 }}
+ {{- if .Values.initContainers.enabled }}
initContainers:
{{- if .Values.decisionEngine.usePostgreSQL }}
- name: wait-for-postgresql
- image: busybox:1.28
+ image: "{{ .Values.initContainers.busybox.repository }}:{{ .Values.initContainers.busybox.tag }}"
+ imagePullPolicy: {{ .Values.initContainers.busybox.pullPolicy }}
command: ['sh', '-c', 'until nc -z {{ include "decision-engine.postgresqlHost" . }} 5432; do echo waiting for postgresql; sleep 2; done;']
{{- end }}
{{- if .Values.decisionEngine.useRedis }}
- name: wait-for-redis
- image: busybox:1.28
+ image: "{{ .Values.initContainers.busybox.repository }}:{{ .Values.initContainers.busybox.tag }}"
+ imagePullPolicy: {{ .Values.initContainers.busybox.pullPolicy }}
command: ['sh', '-c', 'until nc -z {{ include "decision-engine.redisHost" . }} 6379; do echo waiting for redis; sleep 2; done;']
{{- end }}
- name: wait-for-groovy-runner
- image: busybox:1.28
+ image: "{{ .Values.initContainers.busybox.repository }}:{{ .Values.initContainers.busybox.tag }}"
+ imagePullPolicy: {{ .Values.initContainers.busybox.pullPolicy }}
command: ['sh', '-c', 'until nc -z {{ include "decision-engine.groovyRunnerName" . }} {{ .Values.groovyRunner.service.port }}; do echo waiting for groovy-runner; sleep 2; done;']
{{- if .Values.decisionEngine.useMySQL }}
- name: wait-for-mysql
- image: busybox:1.28
+ image: "{{ .Values.initContainers.busybox.repository }}:{{ .Values.initContainers.busybox.tag }}"
+ imagePullPolicy: {{ .Values.initContainers.busybox.pullPolicy }}
command: ['sh', '-c', 'until nc -z {{ include "decision-engine.mysqlHost" . }} 3306; do echo waiting for mysql; sleep 2; done;']
{{- end }}
+ {{- end }}
containers:
- name: {{ .Chart.Name }}
securityContext:
@@ -54,15 +60,24 @@ spec:
image: "{{ .Values.image.repository }}:{{ .Values.image.version | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- - name: http
- containerPort: {{ .Values.decisionEngine.server.port }}
- protocol: TCP
- - name: metrics
- containerPort: {{ .Values.decisionEngine.metrics.port }}
- protocol: TCP
+ {{- range .Values.service.ports }}
+ - name: {{ .name }}
+ containerPort: {{ .targetPort }}
+ protocol: {{ .protocol | default "TCP" }}
+ {{- end }}
env:
- name: GROOVY_RUNNER_HOST
value: "{{ include "decision-engine.groovyRunnerName" . }}:{{ .Values.groovyRunner.service.port }}"
+ {{- range $name, $value := .Values.extraEnvVars }}
+ - name: {{ $name }}
+ {{- if and (kindIs "map" $value) $value.valueFrom }}
+ valueFrom:
+ {{- toYaml $value.valueFrom | nindent 16 }}
+ {{- else }}
+ value: {{ $value | quote }}
+ {{- end }}
+ {{- end }}
+
livenessProbe:
httpGet:
path: /health
diff --git a/helm-charts/templates/istio-destinationrule.yaml b/helm-charts/templates/istio-destinationrule.yaml
new file mode 100644
index 00000000..a5ab60f8
--- /dev/null
+++ b/helm-charts/templates/istio-destinationrule.yaml
@@ -0,0 +1,16 @@
+{{- if and .Values.istio.enabled .Values.istio.destinationRule.enabled }}
+apiVersion: networking.istio.io/v1
+kind: DestinationRule
+metadata:
+ name: {{ include "decision-engine.fullname" . }}-dr
+ namespace: {{ .Release.Namespace }}
+ labels:
+ {{- include "decision-engine.labels" . | nindent 4 }}
+ app.kubernetes.io/component: istio-destination-rule
+spec:
+ host: {{ include "decision-engine.fullname" . }}
+ {{- if .Values.istio.destinationRule.trafficPolicy }}
+ trafficPolicy:
+ {{- toYaml .Values.istio.destinationRule.trafficPolicy | nindent 4 }}
+ {{- end }}
+{{- end }}
\ No newline at end of file
diff --git a/helm-charts/templates/istio-virtualservice.yaml b/helm-charts/templates/istio-virtualservice.yaml
new file mode 100644
index 00000000..9d2994f5
--- /dev/null
+++ b/helm-charts/templates/istio-virtualservice.yaml
@@ -0,0 +1,52 @@
+{{- if and .Values.istio.enabled .Values.istio.virtualService.enabled }}
+apiVersion: networking.istio.io/v1beta1
+kind: VirtualService
+metadata:
+ name: {{ include "decision-engine.fullname" . }}-vs
+ namespace: {{ .Release.Namespace }}
+ labels:
+ {{- include "decision-engine.labels" . | nindent 4 }}
+ app.kubernetes.io/component: istio-virtual-service
+spec:
+ {{- with .Values.istio.virtualService.hosts }}
+ hosts:
+ {{- toYaml . | nindent 4 }}
+ {{- end }}
+ {{- with .Values.istio.virtualService.gateways }}
+ gateways:
+ {{- toYaml . | nindent 4 }}
+ {{- end }}
+ {{- if .Values.istio.virtualService.http }}
+ http:
+ {{- range .Values.istio.virtualService.http }}
+ - {{- if .name }}
+ name: {{ .name | quote }}
+ {{- end }}
+ {{- if .match }}
+ match:
+ {{- toYaml .match | nindent 6 }}
+ {{- end }}
+ {{- if .rewrite }}
+ rewrite:
+ {{- toYaml .rewrite | nindent 6 }}
+ {{- end }}
+ {{- if .timeout }}
+ timeout: {{ .timeout }}
+ {{- end }}
+ {{- if .retries }}
+ retries:
+ {{- toYaml .retries | nindent 6 }}
+ {{- end }}
+ route:
+ - destination:
+ host: {{ include "decision-engine.fullname" $ }}
+ port:
+ number: 80
+ {{- if .weight }}
+ weight: {{ .weight }}
+ {{- else }}
+ weight: 100
+ {{- end }}
+ {{- end }}
+ {{- end }}
+{{- end }}
\ No newline at end of file
diff --git a/helm-charts/templates/mysql-migration-job.yaml b/helm-charts/templates/mysql-migration-job.yaml
index 97c412e3..85d52d5a 100644
--- a/helm-charts/templates/mysql-migration-job.yaml
+++ b/helm-charts/templates/mysql-migration-job.yaml
@@ -26,10 +26,13 @@ spec:
serviceAccountName: {{ include "decision-engine.serviceAccountName" . }}
securityContext:
{{- toYaml .Values.podSecurityContext | nindent 8 }}
+ {{- if .Values.initContainers.enabled }}
initContainers:
- name: wait-for-mysql
- image: busybox:1.28
+ image: "{{ .Values.initContainers.busybox.repository }}:{{ .Values.initContainers.busybox.tag }}"
+ imagePullPolicy: {{ .Values.initContainers.busybox.pullPolicy }}
command: ['sh', '-c', 'until nc -z {{ include "decision-engine.mysqlHost" . }} 3306; do echo waiting for mysql; sleep 2; done;']
+ {{- end }}
containers:
- name: migration
image: "debian:stable-slim"
diff --git a/helm-charts/templates/postgresql-migration-job.yaml b/helm-charts/templates/postgresql-migration-job.yaml
index ae561780..28d6488d 100644
--- a/helm-charts/templates/postgresql-migration-job.yaml
+++ b/helm-charts/templates/postgresql-migration-job.yaml
@@ -36,10 +36,13 @@ spec:
serviceAccountName: {{ include "decision-engine.serviceAccountName" . }}
securityContext:
{{- toYaml .Values.podSecurityContext | nindent 8 }}
+ {{- if .Values.initContainers.enabled }}
initContainers:
- name: wait-for-postgresql
- image: busybox:1.28
+ image: "{{ .Values.initContainers.busybox.repository }}:{{ .Values.initContainers.busybox.tag }}"
+ imagePullPolicy: {{ .Values.initContainers.busybox.pullPolicy }}
command: ['sh', '-c', 'until nc -z {{ include "decision-engine.postgresqlHost" . }} 5432; do echo waiting for postgresql; sleep 2; done;']
+ {{- end }}
containers:
- name: migration
image: rust:latest
diff --git a/helm-charts/templates/routing-config-job.yaml b/helm-charts/templates/routing-config-job.yaml
index 1a6becb4..467d4e24 100644
--- a/helm-charts/templates/routing-config-job.yaml
+++ b/helm-charts/templates/routing-config-job.yaml
@@ -26,17 +26,21 @@ spec:
serviceAccountName: {{ include "decision-engine.serviceAccountName" . }}
securityContext:
{{- toYaml .Values.podSecurityContext | nindent 8 }}
+ {{- if .Values.initContainers.enabled }}
initContainers:
{{- if .Values.decisionEngine.usePostgreSQL }}
- name: wait-for-postgresql
- image: busybox:1.28
+ image: "{{ .Values.initContainers.busybox.repository }}:{{ .Values.initContainers.busybox.tag }}"
+ imagePullPolicy: {{ .Values.initContainers.busybox.pullPolicy }}
command: ['sh', '-c', 'until nc -z {{ include "decision-engine.postgresqlHost" . }} 5432; do echo waiting for postgresql; sleep 2; done;']
{{- end }}
{{- if .Values.decisionEngine.useMySQL }}
- name: wait-for-mysql
- image: busybox:1.28
+ image: "{{ .Values.initContainers.busybox.repository }}:{{ .Values.initContainers.busybox.tag }}"
+ imagePullPolicy: {{ .Values.initContainers.busybox.pullPolicy }}
command: ['sh', '-c', 'until nc -z {{ include "decision-engine.mysqlHost" . }} 3306; do echo waiting for mysql; sleep 2; done;']
{{- end }}
+ {{- end }}
containers:
- name: routing-config
image: "{{ .Values.routingConfig.image.repository }}:{{ .Values.routingConfig.image.tag }}"
diff --git a/helm-charts/templates/service.yaml b/helm-charts/templates/service.yaml
index c0e9a419..b97106ec 100644
--- a/helm-charts/templates/service.yaml
+++ b/helm-charts/templates/service.yaml
@@ -8,10 +8,12 @@ metadata:
spec:
type: {{ .Values.service.type }}
ports:
- - port: {{ .Values.service.port }}
- targetPort: http
- protocol: TCP
- name: http
+ {{- range .Values.service.ports }}
+ - name: {{ .name }}
+ port: {{ .port }}
+ targetPort: {{ .targetPort }}
+ protocol: {{ .protocol | default "TCP" }}
+ {{- end }}
selector:
{{- include "decision-engine.selectorLabels" . | nindent 4 }}
app.kubernetes.io/component: {{ .Values.decisionEngine.metadata.labels.component }}
diff --git a/helm-charts/values.yaml b/helm-charts/values.yaml
index 2fc07263..98999855 100644
--- a/helm-charts/values.yaml
+++ b/helm-charts/values.yaml
@@ -5,10 +5,10 @@ image:
# Updated to include the registry URL
repository: ghcr.io/juspay/decision-engine/postgres
pullPolicy: Always
- version: "v1.2.0"
+ version: "v1.4"
# Configure these if your images are in a private registry
-imagePullSecrets:
+imagePullSecrets:
# - name: regcred
nameOverride: ""
fullnameOverride: ""
@@ -27,6 +27,14 @@ podAnnotations: {}
podSecurityContext: {}
# fsGroup: 2000
+initContainers:
+ # Set to false to disable all init containers
+ enabled: true
+ busybox:
+ repository: public.ecr.aws/docker/library/busybox
+ tag: "1.28"
+ pullPolicy: IfNotPresent
+
securityContext: {}
# capabilities:
# drop:
@@ -37,7 +45,15 @@ securityContext: {}
service:
type: ClusterIP
- port: 8080
+ ports:
+ - name: http
+ port: 80
+ targetPort: 8080
+ protocol: TCP
+ - name: metrics
+ port: 9090
+ targetPort: 9090
+ protocol: TCP
ingress:
enabled: false
@@ -156,7 +172,7 @@ groovyRunner:
enabled: true
image:
repository: "ghcr.io/juspay/decision-engine/groovy-runner"
- version: "v1.0.0"
+ version: "v1.4"
pullPolicy: "Always"
service:
port: 8085
@@ -206,3 +222,55 @@ routingConfig:
enabled: true
# Path to mount routing config files
mountPath: "/app"
+
+# Additional environment variables to inject into the main container (map format for proper merging)
+# Supports both simple values and valueFrom references for secrets/configmaps
+extraEnvVars: {}
+ # Simple value example:
+ # MY_VAR: "my-value"
+ # Secret reference example:
+ # DB_PASSWORD:
+ # valueFrom:
+ # secretKeyRef:
+ # name: decision-engine-secrets
+ # key: LOCKER__PG_DATABASE__PG_PASSWORD
+ # ConfigMap reference example:
+ # APP_CONFIG:
+ # valueFrom:
+ # configMapKeyRef:
+ # name: app-config
+ # key: config.json
+
+# Istio configuration (optional)
+istio:
+ enabled: false
+ virtualService:
+ enabled: false
+ hosts: []
+ gateways: []
+ # HTTP routing rules - route destination will be automatically set to control center service
+ http: []
+ # Example configuration:
+ # http:
+ # - name: "control-center-routes"
+ # match:
+ # - uri:
+ # prefix: /
+ # rewrite:
+ # uri: "/dashboard"
+ # weight: 100
+ # timeout: 30s
+ # retries:
+ # attempts: 3
+ # perTryTimeout: 10s
+ destinationRule:
+ enabled: false
+ trafficPolicy: {}
+ # Example traffic policy:
+ # trafficPolicy:
+ # loadBalancer:
+ # simple: ROUND_ROBIN
+ # connectionPool:
+ # tcp:
+ # maxConnections: 50
+ # connectTimeout: 30s
\ No newline at end of file
diff --git a/migrations/2026-04-14-analytics_events/down.sql b/migrations/2026-04-14-analytics_events/down.sql
new file mode 100644
index 00000000..611d9b5b
--- /dev/null
+++ b/migrations/2026-04-14-analytics_events/down.sql
@@ -0,0 +1,2 @@
+-- This file should undo anything in `up.sql`
+DROP TABLE IF EXISTS analytics_event;
diff --git a/migrations/2026-04-14-analytics_events/up.sql b/migrations/2026-04-14-analytics_events/up.sql
new file mode 100644
index 00000000..442f8c11
--- /dev/null
+++ b/migrations/2026-04-14-analytics_events/up.sql
@@ -0,0 +1,26 @@
+-- Your SQL goes here
+CREATE TABLE analytics_event (
+ id SERIAL PRIMARY KEY,
+ event_type VARCHAR(64) NOT NULL,
+ merchant_id VARCHAR(255),
+ payment_method_type VARCHAR(255),
+ payment_method VARCHAR(255),
+ gateway VARCHAR(255),
+ routing_approach VARCHAR(128),
+ rule_name VARCHAR(255),
+ status VARCHAR(64),
+ error_code VARCHAR(64),
+ error_message TEXT,
+ score_value DOUBLE,
+ sigma_factor DOUBLE,
+ average_latency DOUBLE,
+ tp99_latency DOUBLE,
+ transaction_count BIGINT,
+ route VARCHAR(128),
+ details TEXT,
+ created_at_ms BIGINT NOT NULL
+);
+
+CREATE INDEX idx_analytics_event_created_at_ms ON analytics_event (created_at_ms);
+CREATE INDEX idx_analytics_event_merchant_id ON analytics_event (merchant_id);
+CREATE INDEX idx_analytics_event_type ON analytics_event (event_type);
diff --git a/migrations/2026-04-15-000001_payment_audit_fields/down.sql b/migrations/2026-04-15-000001_payment_audit_fields/down.sql
new file mode 100644
index 00000000..2b515b7b
--- /dev/null
+++ b/migrations/2026-04-15-000001_payment_audit_fields/down.sql
@@ -0,0 +1,8 @@
+DROP INDEX idx_analytics_event_stage ON analytics_event;
+DROP INDEX idx_analytics_event_request_id ON analytics_event;
+DROP INDEX idx_analytics_event_payment_id ON analytics_event;
+
+ALTER TABLE analytics_event
+ DROP COLUMN event_stage,
+ DROP COLUMN request_id,
+ DROP COLUMN payment_id;
diff --git a/migrations/2026-04-15-000001_payment_audit_fields/up.sql b/migrations/2026-04-15-000001_payment_audit_fields/up.sql
new file mode 100644
index 00000000..b1bfd884
--- /dev/null
+++ b/migrations/2026-04-15-000001_payment_audit_fields/up.sql
@@ -0,0 +1,8 @@
+ALTER TABLE analytics_event
+ ADD COLUMN payment_id VARCHAR(255) NULL,
+ ADD COLUMN request_id VARCHAR(255) NULL,
+ ADD COLUMN event_stage VARCHAR(128) NULL;
+
+CREATE INDEX idx_analytics_event_payment_id ON analytics_event (payment_id);
+CREATE INDEX idx_analytics_event_request_id ON analytics_event (request_id);
+CREATE INDEX idx_analytics_event_stage ON analytics_event (event_stage);
diff --git a/migrations/2026-04-16-000001_analytics_sr_dimensions/down.sql b/migrations/2026-04-16-000001_analytics_sr_dimensions/down.sql
new file mode 100644
index 00000000..9f253e4b
--- /dev/null
+++ b/migrations/2026-04-16-000001_analytics_sr_dimensions/down.sql
@@ -0,0 +1,6 @@
+ALTER TABLE analytics_event
+ DROP COLUMN auth_type,
+ DROP COLUMN country,
+ DROP COLUMN currency,
+ DROP COLUMN card_is_in,
+ DROP COLUMN card_network;
diff --git a/migrations/2026-04-16-000001_analytics_sr_dimensions/up.sql b/migrations/2026-04-16-000001_analytics_sr_dimensions/up.sql
new file mode 100644
index 00000000..32608d64
--- /dev/null
+++ b/migrations/2026-04-16-000001_analytics_sr_dimensions/up.sql
@@ -0,0 +1,6 @@
+ALTER TABLE analytics_event
+ ADD COLUMN card_network VARCHAR(255),
+ ADD COLUMN card_is_in VARCHAR(255),
+ ADD COLUMN currency VARCHAR(64),
+ ADD COLUMN country VARCHAR(64),
+ ADD COLUMN auth_type VARCHAR(64);
diff --git a/migrations_pg/2026-04-14-analytics_events/down.sql b/migrations_pg/2026-04-14-analytics_events/down.sql
new file mode 100644
index 00000000..6ca66a8b
--- /dev/null
+++ b/migrations_pg/2026-04-14-analytics_events/down.sql
@@ -0,0 +1 @@
+DROP TABLE analytics_event;
diff --git a/migrations_pg/2026-04-14-analytics_events/up.sql b/migrations_pg/2026-04-14-analytics_events/up.sql
new file mode 100644
index 00000000..25774a8a
--- /dev/null
+++ b/migrations_pg/2026-04-14-analytics_events/up.sql
@@ -0,0 +1,25 @@
+CREATE TABLE analytics_event (
+ id SERIAL PRIMARY KEY,
+ event_type VARCHAR(64) NOT NULL,
+ merchant_id VARCHAR(255),
+ payment_method_type VARCHAR(255),
+ payment_method VARCHAR(255),
+ gateway VARCHAR(255),
+ routing_approach VARCHAR(128),
+ rule_name VARCHAR(255),
+ status VARCHAR(64),
+ error_code VARCHAR(64),
+ error_message TEXT,
+ score_value DOUBLE PRECISION,
+ sigma_factor DOUBLE PRECISION,
+ average_latency DOUBLE PRECISION,
+ tp99_latency DOUBLE PRECISION,
+ transaction_count BIGINT,
+ route VARCHAR(128),
+ details TEXT,
+ created_at_ms BIGINT NOT NULL
+);
+
+CREATE INDEX idx_analytics_event_created_at_ms ON analytics_event (created_at_ms);
+CREATE INDEX idx_analytics_event_merchant_id ON analytics_event (merchant_id);
+CREATE INDEX idx_analytics_event_type ON analytics_event (event_type);
diff --git a/migrations_pg/2026-04-15-000001_payment_audit_fields/down.sql b/migrations_pg/2026-04-15-000001_payment_audit_fields/down.sql
new file mode 100644
index 00000000..49ea4f44
--- /dev/null
+++ b/migrations_pg/2026-04-15-000001_payment_audit_fields/down.sql
@@ -0,0 +1,8 @@
+DROP INDEX IF EXISTS idx_analytics_event_stage;
+DROP INDEX IF EXISTS idx_analytics_event_request_id;
+DROP INDEX IF EXISTS idx_analytics_event_payment_id;
+
+ALTER TABLE analytics_event
+ DROP COLUMN IF EXISTS event_stage,
+ DROP COLUMN IF EXISTS request_id,
+ DROP COLUMN IF EXISTS payment_id;
diff --git a/migrations_pg/2026-04-15-000001_payment_audit_fields/up.sql b/migrations_pg/2026-04-15-000001_payment_audit_fields/up.sql
new file mode 100644
index 00000000..503624cf
--- /dev/null
+++ b/migrations_pg/2026-04-15-000001_payment_audit_fields/up.sql
@@ -0,0 +1,8 @@
+ALTER TABLE analytics_event
+ ADD COLUMN payment_id VARCHAR(255),
+ ADD COLUMN request_id VARCHAR(255),
+ ADD COLUMN event_stage VARCHAR(128);
+
+CREATE INDEX idx_analytics_event_payment_id ON analytics_event (payment_id);
+CREATE INDEX idx_analytics_event_request_id ON analytics_event (request_id);
+CREATE INDEX idx_analytics_event_stage ON analytics_event (event_stage);
diff --git a/migrations_pg/2026-04-16-000001_analytics_sr_dimensions/down.sql b/migrations_pg/2026-04-16-000001_analytics_sr_dimensions/down.sql
new file mode 100644
index 00000000..e1c4a75b
--- /dev/null
+++ b/migrations_pg/2026-04-16-000001_analytics_sr_dimensions/down.sql
@@ -0,0 +1,6 @@
+ALTER TABLE analytics_event
+ DROP COLUMN IF EXISTS auth_type,
+ DROP COLUMN IF EXISTS country,
+ DROP COLUMN IF EXISTS currency,
+ DROP COLUMN IF EXISTS card_is_in,
+ DROP COLUMN IF EXISTS card_network;
diff --git a/migrations_pg/2026-04-16-000001_analytics_sr_dimensions/up.sql b/migrations_pg/2026-04-16-000001_analytics_sr_dimensions/up.sql
new file mode 100644
index 00000000..32608d64
--- /dev/null
+++ b/migrations_pg/2026-04-16-000001_analytics_sr_dimensions/up.sql
@@ -0,0 +1,6 @@
+ALTER TABLE analytics_event
+ ADD COLUMN card_network VARCHAR(255),
+ ADD COLUMN card_is_in VARCHAR(255),
+ ADD COLUMN currency VARCHAR(64),
+ ADD COLUMN country VARCHAR(64),
+ ADD COLUMN auth_type VARCHAR(64);
diff --git a/nginx/nginx.conf b/nginx/nginx.conf
new file mode 100644
index 00000000..e46aa9a7
--- /dev/null
+++ b/nginx/nginx.conf
@@ -0,0 +1,54 @@
+events {}
+
+http {
+ include /etc/nginx/mime.types;
+ default_type application/octet-stream;
+
+ upstream decision_engine {
+ server decision-engine-api:8080;
+ }
+
+ upstream mintlify_docs {
+ server mintlify-docs:3000;
+ }
+
+ server {
+ listen 80;
+
+ # Mintlify Next.js static assets — must be proxied to the docs server
+ location /_next/ {
+ proxy_pass http://mintlify_docs;
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ }
+
+ # Mintlify internal routes
+ location ~* ^/(api-reference|introduction|favicon|logo) {
+ proxy_pass http://mintlify_docs;
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_http_version 1.1;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection "upgrade";
+ }
+
+ # Redirect /dashboard → /dashboard/
+ location = /dashboard {
+ return 301 /dashboard/;
+ }
+
+ # Dashboard SPA (React app served from static files)
+ location /dashboard/ {
+ root /usr/share/nginx/html;
+ try_files $uri $uri/ /dashboard/index.html;
+ }
+
+ # Decision Engine API
+ location / {
+ proxy_pass http://decision_engine;
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ }
+ }
+}
diff --git a/oneclick.sh b/oneclick.sh
new file mode 100755
index 00000000..55f90e67
--- /dev/null
+++ b/oneclick.sh
@@ -0,0 +1,206 @@
+#!/bin/bash
+
+set -e
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+cd "$SCRIPT_DIR"
+
+OPENAPI_PATH="$SCRIPT_DIR/docs/openapi.json"
+DOCS_PORT="${DOCS_PORT:-3000}"
+DOCS_URL="http://localhost:${DOCS_PORT}"
+DOCS_HOME_URL="${DOCS_URL}/introduction"
+API_REF_URL="${DOCS_URL}/api-reference"
+API_EXAMPLES_URL="${DOCS_URL}/api-reference1"
+DOCS_LOG_PATH="${SCRIPT_DIR}/.mintlify-dev.log"
+
+PORTS=(8080 5173 "$DOCS_PORT")
+
+check_and_kill_ports() {
+ local pids_to_kill=()
+ local ports_in_use=()
+
+ echo "Checking for processes on ports ${PORTS[*]}..."
+ echo ""
+
+ for port in "${PORTS[@]}"; do
+ local pids
+ pids=$(lsof -t -iTCP:$port -sTCP:LISTEN 2>/dev/null || true)
+ if [ -n "$pids" ]; then
+ ports_in_use+=("$port")
+ while IFS= read -r pid; do
+ [ -z "$pid" ] && continue
+ local cmd
+ cmd=$(ps -p "$pid" -o command= 2>/dev/null || echo "unknown process")
+ pids_to_kill+=("$pid")
+ echo " [!] Port $port is in use by PID $pid"
+ echo " Command: $cmd"
+ done <<< "$pids"
+ fi
+ done
+
+ if [ ${#pids_to_kill[@]} -gt 0 ]; then
+ echo ""
+ echo "=========================================="
+ echo " WARNING: Found processes on ports ${ports_in_use[*]}"
+ echo " These processes will be killed to proceed."
+ echo "=========================================="
+ echo ""
+ echo "Press Enter to continue and kill these processes, or Ctrl+C to abort..."
+ read -r
+
+ echo ""
+ echo "Killing processes..."
+ for pid in "${pids_to_kill[@]}"; do
+ kill $pid 2>/dev/null || true
+ echo " Killed PID $pid"
+ done
+
+ sleep 1
+
+ for port in "${PORTS[@]}"; do
+ local pid
+ pid=$(lsof -t -iTCP:$port -sTCP:LISTEN 2>/dev/null || true)
+ if [ -n "$pid" ]; then
+ kill -9 $pid 2>/dev/null || true
+ echo " Force killed PID $pid on port $port"
+ fi
+ done
+
+ echo "Done. All ports cleared."
+ echo ""
+ else
+ echo "No processes found on ports ${PORTS[*]}."
+ echo ""
+ fi
+}
+
+cleanup() {
+ local exit_code="${1:-0}"
+ echo ""
+ echo "Stopping services..."
+ if [ -n "$SERVER_PID" ]; then
+ kill $SERVER_PID 2>/dev/null || true
+ fi
+ if [ -n "$DASHBOARD_PID" ]; then
+ kill $DASHBOARD_PID 2>/dev/null || true
+ fi
+ if [ -n "$DOCS_PID" ]; then
+ kill $DOCS_PID 2>/dev/null || true
+ fi
+ exit "$exit_code"
+}
+
+trap cleanup SIGINT SIGTERM
+
+wait_for_backend() {
+ local attempts=0
+ local max_attempts=90
+
+ echo "Waiting for Decision Engine API on http://localhost:8080/health..."
+
+ while [ $attempts -lt $max_attempts ]; do
+ if curl -fsS http://localhost:8080/health >/dev/null 2>&1; then
+ echo "Decision Engine API is healthy."
+ echo ""
+ return 0
+ fi
+
+ if ! kill -0 "$SERVER_PID" 2>/dev/null; then
+ echo "Decision Engine server exited before becoming healthy."
+ return 1
+ fi
+
+ attempts=$((attempts + 1))
+ sleep 1
+ done
+
+ echo "Decision Engine API did not become healthy within ${max_attempts}s."
+ return 1
+}
+
+wait_for_docs() {
+ local attempts=0
+ local max_attempts=120
+
+ echo "Waiting for docs preview on ${DOCS_HOME_URL}..."
+
+ while [ $attempts -lt $max_attempts ]; do
+ if curl -fsS "${DOCS_HOME_URL}" >/dev/null 2>&1; then
+ echo "Docs preview is healthy."
+ echo ""
+ return 0
+ fi
+
+ if ! kill -0 "$DOCS_PID" 2>/dev/null; then
+ echo "Docs preview exited before becoming healthy."
+ echo "Check ${DOCS_LOG_PATH} for details."
+ return 1
+ fi
+
+ attempts=$((attempts + 1))
+ sleep 1
+ done
+
+ echo "Docs preview did not become healthy within ${max_attempts}s."
+ echo "Check ${DOCS_LOG_PATH} for details."
+ return 1
+}
+
+check_and_kill_ports
+
+echo "Running Postgres migrations..."
+just migrate-pg
+
+echo "Starting Decision Engine server..."
+cargo run --no-default-features --features postgres &
+SERVER_PID=$!
+
+if ! wait_for_backend; then
+ cleanup 1
+fi
+
+echo "Installing dashboard dependencies..."
+cd "$SCRIPT_DIR/website"
+npm install --silent
+
+echo "Starting docs preview..."
+cd "$SCRIPT_DIR/docs"
+rm -f "$DOCS_LOG_PATH"
+if [ "${DOCS_PORT}" != "3000" ]; then
+ echo "Mint preview uses port 3000 in this environment; overriding DOCS_PORT=${DOCS_PORT} to 3000."
+ DOCS_PORT="3000"
+ DOCS_URL="http://localhost:${DOCS_PORT}"
+ DOCS_HOME_URL="${DOCS_URL}/introduction"
+ API_REF_URL="${DOCS_URL}/api-reference"
+ API_EXAMPLES_URL="${DOCS_URL}/api-reference1"
+fi
+PORT="$DOCS_PORT" mint dev --no-open >"$DOCS_LOG_PATH" 2>&1 &
+DOCS_PID=$!
+
+if ! wait_for_docs; then
+ cleanup 1
+fi
+
+cd "$SCRIPT_DIR/website"
+echo "Starting dashboard..."
+npm run dev &
+DASHBOARD_PID=$!
+
+cd "$SCRIPT_DIR"
+
+echo ""
+echo "=========================================="
+echo " Decision Engine is starting up!"
+echo "=========================================="
+echo ""
+echo " Server: http://localhost:8080"
+echo " Dashboard: http://localhost:5173/dashboard/"
+echo " Docs: $DOCS_HOME_URL"
+echo " API Ref: $API_REF_URL"
+echo " API Examples:$API_EXAMPLES_URL"
+echo " OpenAPI: $OPENAPI_PATH"
+echo ""
+echo "=========================================="
+echo ""
+
+wait $SERVER_PID $DASHBOARD_PID
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 00000000..e8dcadc4
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,3152 @@
+{
+ "name": "decision-engine-cypress-tests",
+ "version": "1.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "decision-engine-cypress-tests",
+ "version": "1.0.0",
+ "dependencies": {
+ "uuid": "^9.0.1"
+ },
+ "devDependencies": {
+ "@cypress/grep": "^4.0.1",
+ "cypress": "^13.6.0"
+ }
+ },
+ "node_modules/@ampproject/remapping": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
+ "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "peer": true,
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/code-frame": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz",
+ "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/helper-validator-identifier": "^7.27.1",
+ "js-tokens": "^4.0.0",
+ "picocolors": "^1.1.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/compat-data": {
+ "version": "7.28.0",
+ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.0.tgz",
+ "integrity": "sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/core": {
+ "version": "7.28.0",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.0.tgz",
+ "integrity": "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@ampproject/remapping": "^2.2.0",
+ "@babel/code-frame": "^7.27.1",
+ "@babel/generator": "^7.28.0",
+ "@babel/helper-compilation-targets": "^7.27.2",
+ "@babel/helper-module-transforms": "^7.27.3",
+ "@babel/helpers": "^7.27.6",
+ "@babel/parser": "^7.28.0",
+ "@babel/template": "^7.27.2",
+ "@babel/traverse": "^7.28.0",
+ "@babel/types": "^7.28.0",
+ "convert-source-map": "^2.0.0",
+ "debug": "^4.1.0",
+ "gensync": "^1.0.0-beta.2",
+ "json5": "^2.2.3",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/babel"
+ }
+ },
+ "node_modules/@babel/core/node_modules/semver": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "dev": true,
+ "license": "ISC",
+ "peer": true,
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/@babel/generator": {
+ "version": "7.28.0",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.0.tgz",
+ "integrity": "sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/parser": "^7.28.0",
+ "@babel/types": "^7.28.0",
+ "@jridgewell/gen-mapping": "^0.3.12",
+ "@jridgewell/trace-mapping": "^0.3.28",
+ "jsesc": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-compilation-targets": {
+ "version": "7.27.2",
+ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz",
+ "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/compat-data": "^7.27.2",
+ "@babel/helper-validator-option": "^7.27.1",
+ "browserslist": "^4.24.0",
+ "lru-cache": "^5.1.1",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-compilation-targets/node_modules/semver": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "dev": true,
+ "license": "ISC",
+ "peer": true,
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/@babel/helper-globals": {
+ "version": "7.28.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz",
+ "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-imports": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz",
+ "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/traverse": "^7.27.1",
+ "@babel/types": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-transforms": {
+ "version": "7.27.3",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.3.tgz",
+ "integrity": "sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/helper-module-imports": "^7.27.1",
+ "@babel/helper-validator-identifier": "^7.27.1",
+ "@babel/traverse": "^7.27.3"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/helper-plugin-utils": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz",
+ "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-string-parser": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
+ "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-identifier": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz",
+ "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-option": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz",
+ "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helpers": {
+ "version": "7.28.2",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.2.tgz",
+ "integrity": "sha512-/V9771t+EgXz62aCcyofnQhGM8DQACbRhvzKFsXKC9QM+5MadF8ZmIm0crDMaz3+o0h0zXfJnd4EhbYbxsrcFw==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/template": "^7.27.2",
+ "@babel/types": "^7.28.2"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/parser": {
+ "version": "7.28.0",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.0.tgz",
+ "integrity": "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.28.0"
+ },
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-jsx": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz",
+ "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/template": {
+ "version": "7.27.2",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz",
+ "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.27.1",
+ "@babel/parser": "^7.27.2",
+ "@babel/types": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/traverse": {
+ "version": "7.28.0",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.0.tgz",
+ "integrity": "sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.27.1",
+ "@babel/generator": "^7.28.0",
+ "@babel/helper-globals": "^7.28.0",
+ "@babel/parser": "^7.28.0",
+ "@babel/template": "^7.27.2",
+ "@babel/types": "^7.28.0",
+ "debug": "^4.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/types": {
+ "version": "7.28.2",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.2.tgz",
+ "integrity": "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-string-parser": "^7.27.1",
+ "@babel/helper-validator-identifier": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@colors/colors": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz",
+ "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">=0.1.90"
+ }
+ },
+ "node_modules/@cypress/grep": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/@cypress/grep/-/grep-4.1.0.tgz",
+ "integrity": "sha512-yUscMiUgM28VDPrNxL19/BhgHZOVrAPrzVsuEcy6mqPqDYt8H8fIaHeeGQPW4CbMu/ry9sehjH561WDDBIXOIg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.3.4",
+ "find-test-names": "^1.28.18",
+ "globby": "^11.0.4"
+ },
+ "peerDependencies": {
+ "cypress": ">=10"
+ }
+ },
+ "node_modules/@cypress/request": {
+ "version": "3.0.9",
+ "resolved": "https://registry.npmjs.org/@cypress/request/-/request-3.0.9.tgz",
+ "integrity": "sha512-I3l7FdGRXluAS44/0NguwWlO83J18p0vlr2FYHrJkWdNYhgVoiYo61IXPqaOsL+vNxU1ZqMACzItGK3/KKDsdw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "aws-sign2": "~0.7.0",
+ "aws4": "^1.8.0",
+ "caseless": "~0.12.0",
+ "combined-stream": "~1.0.6",
+ "extend": "~3.0.2",
+ "forever-agent": "~0.6.1",
+ "form-data": "~4.0.4",
+ "http-signature": "~1.4.0",
+ "is-typedarray": "~1.0.0",
+ "isstream": "~0.1.2",
+ "json-stringify-safe": "~5.0.1",
+ "mime-types": "~2.1.19",
+ "performance-now": "^2.1.0",
+ "qs": "6.14.0",
+ "safe-buffer": "^5.1.2",
+ "tough-cookie": "^5.0.0",
+ "tunnel-agent": "^0.6.0",
+ "uuid": "^8.3.2"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/@cypress/request/node_modules/uuid": {
+ "version": "8.3.2",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
+ "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "uuid": "dist/bin/uuid"
+ }
+ },
+ "node_modules/@cypress/xvfb": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@cypress/xvfb/-/xvfb-1.2.4.tgz",
+ "integrity": "sha512-skbBzPggOVYCbnGgV+0dmBdW/s77ZkAOXIC1knS8NagwDjBrNC1LuXtQJeiN6l+m7lzmHtaoUw/ctJKdqkG57Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^3.1.0",
+ "lodash.once": "^4.1.1"
+ }
+ },
+ "node_modules/@cypress/xvfb/node_modules/debug": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+ "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.1"
+ }
+ },
+ "node_modules/@jridgewell/gen-mapping": {
+ "version": "0.3.12",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz",
+ "integrity": "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.5.0",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ }
+ },
+ "node_modules/@jridgewell/resolve-uri": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+ "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.5.4",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz",
+ "integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.29",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz",
+ "integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.1.0",
+ "@jridgewell/sourcemap-codec": "^1.4.14"
+ }
+ },
+ "node_modules/@nodelib/fs.scandir": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+ "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.stat": "2.0.5",
+ "run-parallel": "^1.1.9"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.stat": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+ "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.walk": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+ "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.scandir": "2.1.5",
+ "fastq": "^1.6.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@types/node": {
+ "version": "24.1.0",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-24.1.0.tgz",
+ "integrity": "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "undici-types": "~7.8.0"
+ }
+ },
+ "node_modules/@types/sinonjs__fake-timers": {
+ "version": "8.1.1",
+ "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.1.tgz",
+ "integrity": "sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/sizzle": {
+ "version": "2.3.9",
+ "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.9.tgz",
+ "integrity": "sha512-xzLEyKB50yqCUPUJkIsrVvoWNfFUbIZI+RspLWt8u+tIW/BetMBZtgV2LY/2o+tYH8dRvQ+eoPf3NdhQCcLE2w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/yauzl": {
+ "version": "2.10.3",
+ "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz",
+ "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/acorn": {
+ "version": "8.15.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
+ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/acorn-walk": {
+ "version": "8.3.4",
+ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz",
+ "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "acorn": "^8.11.0"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/aggregate-error": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz",
+ "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "clean-stack": "^2.0.0",
+ "indent-string": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/ansi-colors": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz",
+ "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/ansi-escapes": {
+ "version": "4.3.2",
+ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
+ "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "type-fest": "^0.21.3"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/arch": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz",
+ "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/array-union": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
+ "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/asn1": {
+ "version": "0.2.6",
+ "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz",
+ "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "safer-buffer": "~2.1.0"
+ }
+ },
+ "node_modules/assert-plus": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+ "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/astral-regex": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
+ "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/async": {
+ "version": "3.2.6",
+ "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz",
+ "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/asynckit": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/at-least-node": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
+ "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">= 4.0.0"
+ }
+ },
+ "node_modules/aws-sign2": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
+ "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/aws4": {
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.2.tgz",
+ "integrity": "sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/base64-js": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/bcrypt-pbkdf": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
+ "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "tweetnacl": "^0.14.3"
+ }
+ },
+ "node_modules/blob-util": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/blob-util/-/blob-util-2.0.2.tgz",
+ "integrity": "sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==",
+ "dev": true,
+ "license": "Apache-2.0"
+ },
+ "node_modules/bluebird": {
+ "version": "3.7.2",
+ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
+ "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/braces": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fill-range": "^7.1.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/browserslist": {
+ "version": "4.25.1",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.1.tgz",
+ "integrity": "sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "caniuse-lite": "^1.0.30001726",
+ "electron-to-chromium": "^1.5.173",
+ "node-releases": "^2.0.19",
+ "update-browserslist-db": "^1.1.3"
+ },
+ "bin": {
+ "browserslist": "cli.js"
+ },
+ "engines": {
+ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+ }
+ },
+ "node_modules/buffer": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
+ "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.1.13"
+ }
+ },
+ "node_modules/buffer-crc32": {
+ "version": "0.2.13",
+ "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
+ "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/cachedir": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.4.0.tgz",
+ "integrity": "sha512-9EtFOZR8g22CL7BWjJ9BUx1+A/djkofnyW3aOXZORNW2kxoUpx2h+uN2cOqwPmFhnpVmxg+KW2OjOSgChTEvsQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/call-bind-apply-helpers": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
+ "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/call-bound": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
+ "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "get-intrinsic": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/caniuse-lite": {
+ "version": "1.0.30001731",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001731.tgz",
+ "integrity": "sha512-lDdp2/wrOmTRWuoB5DpfNkC0rJDU8DqRa6nYL6HK6sytw70QMopt/NIc/9SM7ylItlBWfACXk0tEn37UWM/+mg==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "CC-BY-4.0",
+ "peer": true
+ },
+ "node_modules/caseless": {
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
+ "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==",
+ "dev": true,
+ "license": "Apache-2.0"
+ },
+ "node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/chalk/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/check-more-types": {
+ "version": "2.24.0",
+ "resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz",
+ "integrity": "sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/ci-info": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.0.tgz",
+ "integrity": "sha512-l+2bNRMiQgcfILUi33labAZYIWlH1kWDp+ecNo5iisRKrbm0xcRyCww71/YU0Fkw0mAFpz9bJayXPjey6vkmaQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/sibiraj-s"
+ }
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/clean-stack": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
+ "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/cli-cursor": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
+ "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "restore-cursor": "^3.1.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/cli-table3": {
+ "version": "0.6.5",
+ "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.5.tgz",
+ "integrity": "sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "string-width": "^4.2.0"
+ },
+ "engines": {
+ "node": "10.* || >= 12.*"
+ },
+ "optionalDependencies": {
+ "@colors/colors": "1.5.0"
+ }
+ },
+ "node_modules/cli-truncate": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz",
+ "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "slice-ansi": "^3.0.0",
+ "string-width": "^4.2.0"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/colorette": {
+ "version": "2.0.20",
+ "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz",
+ "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/combined-stream": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "delayed-stream": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/commander": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz",
+ "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/common-tags": {
+ "version": "1.8.2",
+ "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz",
+ "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/convert-source-map": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
+ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/core-util-is": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+ "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/cross-spawn": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+ "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/cypress": {
+ "version": "13.17.0",
+ "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.17.0.tgz",
+ "integrity": "sha512-5xWkaPurwkIljojFidhw8lFScyxhtiFHl/i/3zov+1Z5CmY4t9tjIdvSXfu82Y3w7wt0uR9KkucbhkVvJZLQSA==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "dependencies": {
+ "@cypress/request": "^3.0.6",
+ "@cypress/xvfb": "^1.2.4",
+ "@types/sinonjs__fake-timers": "8.1.1",
+ "@types/sizzle": "^2.3.2",
+ "arch": "^2.2.0",
+ "blob-util": "^2.0.2",
+ "bluebird": "^3.7.2",
+ "buffer": "^5.7.1",
+ "cachedir": "^2.3.0",
+ "chalk": "^4.1.0",
+ "check-more-types": "^2.24.0",
+ "ci-info": "^4.0.0",
+ "cli-cursor": "^3.1.0",
+ "cli-table3": "~0.6.1",
+ "commander": "^6.2.1",
+ "common-tags": "^1.8.0",
+ "dayjs": "^1.10.4",
+ "debug": "^4.3.4",
+ "enquirer": "^2.3.6",
+ "eventemitter2": "6.4.7",
+ "execa": "4.1.0",
+ "executable": "^4.1.1",
+ "extract-zip": "2.0.1",
+ "figures": "^3.2.0",
+ "fs-extra": "^9.1.0",
+ "getos": "^3.2.1",
+ "is-installed-globally": "~0.4.0",
+ "lazy-ass": "^1.6.0",
+ "listr2": "^3.8.3",
+ "lodash": "^4.17.21",
+ "log-symbols": "^4.0.0",
+ "minimist": "^1.2.8",
+ "ospath": "^1.2.2",
+ "pretty-bytes": "^5.6.0",
+ "process": "^0.11.10",
+ "proxy-from-env": "1.0.0",
+ "request-progress": "^3.0.0",
+ "semver": "^7.5.3",
+ "supports-color": "^8.1.1",
+ "tmp": "~0.2.3",
+ "tree-kill": "1.2.2",
+ "untildify": "^4.0.0",
+ "yauzl": "^2.10.0"
+ },
+ "bin": {
+ "cypress": "bin/cypress"
+ },
+ "engines": {
+ "node": "^16.0.0 || ^18.0.0 || >=20.0.0"
+ }
+ },
+ "node_modules/dashdash": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
+ "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "assert-plus": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/dayjs": {
+ "version": "1.11.13",
+ "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz",
+ "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/debug": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
+ "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/delayed-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+ "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/dir-glob": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
+ "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "path-type": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/dunder-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
+ "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "gopd": "^1.2.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/ecc-jsbn": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
+ "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "jsbn": "~0.1.0",
+ "safer-buffer": "^2.1.0"
+ }
+ },
+ "node_modules/electron-to-chromium": {
+ "version": "1.5.192",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.192.tgz",
+ "integrity": "sha512-rP8Ez0w7UNw/9j5eSXCe10o1g/8B1P5SM90PCCMVkIRQn2R0LEHWz4Eh9RnxkniuDe1W0cTSOB3MLlkTGDcuCg==",
+ "dev": true,
+ "license": "ISC",
+ "peer": true
+ },
+ "node_modules/emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/end-of-stream": {
+ "version": "1.4.5",
+ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz",
+ "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "once": "^1.4.0"
+ }
+ },
+ "node_modules/enquirer": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz",
+ "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-colors": "^4.1.1",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8.6"
+ }
+ },
+ "node_modules/es-define-property": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
+ "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-errors": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+ "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-object-atoms": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
+ "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-set-tostringtag": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
+ "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.6",
+ "has-tostringtag": "^1.0.2",
+ "hasown": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/escalade": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+ "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/eventemitter2": {
+ "version": "6.4.7",
+ "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.7.tgz",
+ "integrity": "sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/execa": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz",
+ "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "cross-spawn": "^7.0.0",
+ "get-stream": "^5.0.0",
+ "human-signals": "^1.1.1",
+ "is-stream": "^2.0.0",
+ "merge-stream": "^2.0.0",
+ "npm-run-path": "^4.0.0",
+ "onetime": "^5.1.0",
+ "signal-exit": "^3.0.2",
+ "strip-final-newline": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sindresorhus/execa?sponsor=1"
+ }
+ },
+ "node_modules/executable": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/executable/-/executable-4.1.1.tgz",
+ "integrity": "sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "pify": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/extend": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/extract-zip": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz",
+ "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "debug": "^4.1.1",
+ "get-stream": "^5.1.0",
+ "yauzl": "^2.10.0"
+ },
+ "bin": {
+ "extract-zip": "cli.js"
+ },
+ "engines": {
+ "node": ">= 10.17.0"
+ },
+ "optionalDependencies": {
+ "@types/yauzl": "^2.9.1"
+ }
+ },
+ "node_modules/extsprintf": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
+ "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==",
+ "dev": true,
+ "engines": [
+ "node >=0.6.0"
+ ],
+ "license": "MIT"
+ },
+ "node_modules/fast-glob": {
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
+ "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.stat": "^2.0.2",
+ "@nodelib/fs.walk": "^1.2.3",
+ "glob-parent": "^5.1.2",
+ "merge2": "^1.3.0",
+ "micromatch": "^4.0.8"
+ },
+ "engines": {
+ "node": ">=8.6.0"
+ }
+ },
+ "node_modules/fastq": {
+ "version": "1.19.1",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz",
+ "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "reusify": "^1.0.4"
+ }
+ },
+ "node_modules/fd-slicer": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
+ "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "pend": "~1.2.0"
+ }
+ },
+ "node_modules/figures": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
+ "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "escape-string-regexp": "^1.0.5"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/fill-range": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/find-test-names": {
+ "version": "1.29.17",
+ "resolved": "https://registry.npmjs.org/find-test-names/-/find-test-names-1.29.17.tgz",
+ "integrity": "sha512-JyZJ1EqH6+3/eXtViY7A79BTggAmcKu0rmXu89oJPobwbk8MmFhVz06sF1L2r6TLT7477iVtCmftBQ0pl2K/kg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.27.2",
+ "@babel/plugin-syntax-jsx": "^7.27.1",
+ "acorn-walk": "^8.2.0",
+ "debug": "^4.3.3",
+ "globby": "^11.0.4",
+ "simple-bin-help": "^1.8.0"
+ },
+ "bin": {
+ "find-test-names": "bin/find-test-names.js",
+ "print-tests": "bin/print-tests.js",
+ "update-test-count": "bin/update-test-count.js"
+ }
+ },
+ "node_modules/forever-agent": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
+ "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/form-data": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
+ "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.8",
+ "es-set-tostringtag": "^2.1.0",
+ "hasown": "^2.0.2",
+ "mime-types": "^2.1.12"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/fs-extra": {
+ "version": "9.1.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
+ "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "at-least-node": "^1.0.0",
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^6.0.1",
+ "universalify": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/gensync": {
+ "version": "1.0.0-beta.2",
+ "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
+ "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/get-intrinsic": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
+ "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "es-define-property": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.1.1",
+ "function-bind": "^1.1.2",
+ "get-proto": "^1.0.1",
+ "gopd": "^1.2.0",
+ "has-symbols": "^1.1.0",
+ "hasown": "^2.0.2",
+ "math-intrinsics": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
+ "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "dunder-proto": "^1.0.1",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/get-stream": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
+ "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "pump": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/getos": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/getos/-/getos-3.2.1.tgz",
+ "integrity": "sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "async": "^3.2.0"
+ }
+ },
+ "node_modules/getpass": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
+ "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "assert-plus": "^1.0.0"
+ }
+ },
+ "node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/global-dirs": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz",
+ "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ini": "2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/globby": {
+ "version": "11.1.0",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
+ "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "array-union": "^2.1.0",
+ "dir-glob": "^3.0.1",
+ "fast-glob": "^3.2.9",
+ "ignore": "^5.2.0",
+ "merge2": "^1.4.1",
+ "slash": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/gopd": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
+ "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/graceful-fs": {
+ "version": "4.2.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/has-symbols": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
+ "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-tostringtag": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
+ "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-symbols": "^1.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/hasown": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+ "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/http-signature": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.4.0.tgz",
+ "integrity": "sha512-G5akfn7eKbpDN+8nPS/cb57YeA1jLTVxjpCj7tmm3QKPdyDy7T+qSC40e9ptydSWvkwjSXw1VbkpyEm39ukeAg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "assert-plus": "^1.0.0",
+ "jsprim": "^2.0.2",
+ "sshpk": "^1.18.0"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/human-signals": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz",
+ "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=8.12.0"
+ }
+ },
+ "node_modules/ieee754": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+ "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/ignore": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
+ "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/indent-string": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
+ "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/ini": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz",
+ "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-installed-globally": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz",
+ "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "global-dirs": "^3.0.0",
+ "is-path-inside": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/is-path-inside": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
+ "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-stream": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
+ "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-typedarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+ "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/is-unicode-supported": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
+ "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/isstream": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
+ "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/jsbn": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
+ "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/jsesc": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
+ "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "bin": {
+ "jsesc": "bin/jsesc"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/json-schema": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz",
+ "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==",
+ "dev": true,
+ "license": "(AFL-2.1 OR BSD-3-Clause)"
+ },
+ "node_modules/json-stringify-safe": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
+ "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/json5": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "bin": {
+ "json5": "lib/cli.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/jsonfile": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
+ "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "universalify": "^2.0.0"
+ },
+ "optionalDependencies": {
+ "graceful-fs": "^4.1.6"
+ }
+ },
+ "node_modules/jsprim": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz",
+ "integrity": "sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==",
+ "dev": true,
+ "engines": [
+ "node >=0.6.0"
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "assert-plus": "1.0.0",
+ "extsprintf": "1.3.0",
+ "json-schema": "0.4.0",
+ "verror": "1.10.0"
+ }
+ },
+ "node_modules/lazy-ass": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz",
+ "integrity": "sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "> 0.8"
+ }
+ },
+ "node_modules/listr2": {
+ "version": "3.14.0",
+ "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.14.0.tgz",
+ "integrity": "sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "cli-truncate": "^2.1.0",
+ "colorette": "^2.0.16",
+ "log-update": "^4.0.0",
+ "p-map": "^4.0.0",
+ "rfdc": "^1.3.0",
+ "rxjs": "^7.5.1",
+ "through": "^2.3.8",
+ "wrap-ansi": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ },
+ "peerDependencies": {
+ "enquirer": ">= 2.3.0 < 3"
+ },
+ "peerDependenciesMeta": {
+ "enquirer": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/lodash": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/lodash.once": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
+ "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/log-symbols": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
+ "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "chalk": "^4.1.0",
+ "is-unicode-supported": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/log-update": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz",
+ "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-escapes": "^4.3.0",
+ "cli-cursor": "^3.1.0",
+ "slice-ansi": "^4.0.0",
+ "wrap-ansi": "^6.2.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/log-update/node_modules/slice-ansi": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz",
+ "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "astral-regex": "^2.0.0",
+ "is-fullwidth-code-point": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/slice-ansi?sponsor=1"
+ }
+ },
+ "node_modules/log-update/node_modules/wrap-ansi": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
+ "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/lru-cache": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
+ "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
+ "dev": true,
+ "license": "ISC",
+ "peer": true,
+ "dependencies": {
+ "yallist": "^3.0.2"
+ }
+ },
+ "node_modules/math-intrinsics": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
+ "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/merge-stream": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
+ "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/merge2": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+ "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/micromatch": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
+ "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "braces": "^3.0.3",
+ "picomatch": "^2.3.1"
+ },
+ "engines": {
+ "node": ">=8.6"
+ }
+ },
+ "node_modules/mime-db": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "2.1.35",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "mime-db": "1.52.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mimic-fn": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
+ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/minimist": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+ "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/node-releases": {
+ "version": "2.0.19",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz",
+ "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/npm-run-path": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
+ "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "path-key": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/object-inspect": {
+ "version": "1.13.4",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
+ "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "node_modules/onetime": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
+ "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "mimic-fn": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/ospath": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/ospath/-/ospath-1.2.2.tgz",
+ "integrity": "sha512-o6E5qJV5zkAbIDNhGSIlyOhScKXgQrSRMilfph0clDfM0nEnBOlKlH4sWDmG95BW/CvwNz0vmm7dJVtU2KlMiA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/p-map": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz",
+ "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "aggregate-error": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-type": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/pend": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
+ "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/performance-now": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
+ "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/picocolors": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+ "dev": true,
+ "license": "ISC",
+ "peer": true
+ },
+ "node_modules/picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/pretty-bytes": {
+ "version": "5.6.0",
+ "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz",
+ "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/process": {
+ "version": "0.11.10",
+ "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
+ "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6.0"
+ }
+ },
+ "node_modules/proxy-from-env": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz",
+ "integrity": "sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/pump": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz",
+ "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "end-of-stream": "^1.1.0",
+ "once": "^1.3.1"
+ }
+ },
+ "node_modules/qs": {
+ "version": "6.14.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz",
+ "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "side-channel": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=0.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/queue-microtask": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/request-progress": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-3.0.0.tgz",
+ "integrity": "sha512-MnWzEHHaxHO2iWiQuHrUPBi/1WeBf5PkxQqNyNvLl9VAYSdXkP8tQ3pBSeCPD+yw0v0Aq1zosWLz0BdeXpWwZg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "throttleit": "^1.0.0"
+ }
+ },
+ "node_modules/restore-cursor": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz",
+ "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "onetime": "^5.1.0",
+ "signal-exit": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/reusify": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
+ "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "iojs": ">=1.0.0",
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rfdc": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz",
+ "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/run-parallel": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+ "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "queue-microtask": "^1.2.2"
+ }
+ },
+ "node_modules/rxjs": {
+ "version": "7.8.2",
+ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
+ "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "tslib": "^2.1.0"
+ }
+ },
+ "node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/semver": {
+ "version": "7.7.2",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
+ "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/shebang-command": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "shebang-regex": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/shebang-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/side-channel": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
+ "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "object-inspect": "^1.13.3",
+ "side-channel-list": "^1.0.0",
+ "side-channel-map": "^1.0.1",
+ "side-channel-weakmap": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-list": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
+ "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "object-inspect": "^1.13.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-map": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
+ "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.5",
+ "object-inspect": "^1.13.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-weakmap": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
+ "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.5",
+ "object-inspect": "^1.13.3",
+ "side-channel-map": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/signal-exit": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
+ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/simple-bin-help": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/simple-bin-help/-/simple-bin-help-1.8.0.tgz",
+ "integrity": "sha512-0LxHn+P1lF5r2WwVB/za3hLRIsYoLaNq1CXqjbrs3ZvLuvlWnRKrUjEWzV7umZL7hpQ7xULiQMV+0iXdRa5iFg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.16"
+ }
+ },
+ "node_modules/slash": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/slice-ansi": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz",
+ "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "astral-regex": "^2.0.0",
+ "is-fullwidth-code-point": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/sshpk": {
+ "version": "1.18.0",
+ "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz",
+ "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "asn1": "~0.2.3",
+ "assert-plus": "^1.0.0",
+ "bcrypt-pbkdf": "^1.0.0",
+ "dashdash": "^1.12.0",
+ "ecc-jsbn": "~0.1.1",
+ "getpass": "^0.1.1",
+ "jsbn": "~0.1.0",
+ "safer-buffer": "^2.0.2",
+ "tweetnacl": "~0.14.0"
+ },
+ "bin": {
+ "sshpk-conv": "bin/sshpk-conv",
+ "sshpk-sign": "bin/sshpk-sign",
+ "sshpk-verify": "bin/sshpk-verify"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/string-width": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-final-newline": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
+ "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/supports-color": {
+ "version": "8.1.1",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+ "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/supports-color?sponsor=1"
+ }
+ },
+ "node_modules/throttleit": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.1.tgz",
+ "integrity": "sha512-vDZpf9Chs9mAdfY046mcPt8fg5QSZr37hEH4TXYBnDF+izxgrbRGUAAaBvIk/fJm9aOFCGFd1EsNg5AZCbnQCQ==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/through": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+ "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/tldts": {
+ "version": "6.1.86",
+ "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.86.tgz",
+ "integrity": "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "tldts-core": "^6.1.86"
+ },
+ "bin": {
+ "tldts": "bin/cli.js"
+ }
+ },
+ "node_modules/tldts-core": {
+ "version": "6.1.86",
+ "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.86.tgz",
+ "integrity": "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/tmp": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz",
+ "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.14"
+ }
+ },
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/tough-cookie": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.2.tgz",
+ "integrity": "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "tldts": "^6.1.32"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/tree-kill": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz",
+ "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "tree-kill": "cli.js"
+ }
+ },
+ "node_modules/tslib": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+ "dev": true,
+ "license": "0BSD"
+ },
+ "node_modules/tunnel-agent": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+ "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "safe-buffer": "^5.0.1"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/tweetnacl": {
+ "version": "0.14.5",
+ "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
+ "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==",
+ "dev": true,
+ "license": "Unlicense"
+ },
+ "node_modules/type-fest": {
+ "version": "0.21.3",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz",
+ "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==",
+ "dev": true,
+ "license": "(MIT OR CC0-1.0)",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/undici-types": {
+ "version": "7.8.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz",
+ "integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true
+ },
+ "node_modules/universalify": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
+ "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 10.0.0"
+ }
+ },
+ "node_modules/untildify": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz",
+ "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/update-browserslist-db": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz",
+ "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "escalade": "^3.2.0",
+ "picocolors": "^1.1.1"
+ },
+ "bin": {
+ "update-browserslist-db": "cli.js"
+ },
+ "peerDependencies": {
+ "browserslist": ">= 4.21.0"
+ }
+ },
+ "node_modules/uuid": {
+ "version": "9.0.1",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
+ "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
+ "funding": [
+ "https://github.com/sponsors/broofa",
+ "https://github.com/sponsors/ctavan"
+ ],
+ "license": "MIT",
+ "bin": {
+ "uuid": "dist/bin/uuid"
+ }
+ },
+ "node_modules/verror": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
+ "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==",
+ "dev": true,
+ "engines": [
+ "node >=0.6.0"
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "assert-plus": "^1.0.0",
+ "core-util-is": "1.0.2",
+ "extsprintf": "^1.2.0"
+ }
+ },
+ "node_modules/which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "node-which": "bin/node-which"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/wrap-ansi": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/yallist": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
+ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
+ "dev": true,
+ "license": "ISC",
+ "peer": true
+ },
+ "node_modules/yauzl": {
+ "version": "2.10.0",
+ "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
+ "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "buffer-crc32": "~0.2.3",
+ "fd-slicer": "~1.1.0"
+ }
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 00000000..f31aa140
--- /dev/null
+++ b/package.json
@@ -0,0 +1,20 @@
+{
+ "name": "decision-engine-cypress-tests",
+ "version": "1.0.0",
+ "description": "Cypress tests for Decision Engine routing flows",
+ "scripts": {
+ "cypress:open": "cypress open",
+ "cypress:run": "cypress run",
+ "cypress:run:headless": "cypress run --headless",
+ "test:gateway-latency": "cypress run --spec 'cypress/e2e/routing-flows/gateway-latency-scoring.cy.js'",
+ "test:success-rate": "cypress run --spec 'cypress/e2e/routing-flows/success-rate-routing.cy.js'",
+ "test": "cypress run --spec 'cypress/e2e/routing-flows/*.cy.js'"
+ },
+ "devDependencies": {
+ "cypress": "^13.6.0",
+ "@cypress/grep": "^4.0.1"
+ },
+ "dependencies": {
+ "uuid": "^9.0.1"
+ }
+}
diff --git a/scripts/test_analytics.sh b/scripts/test_analytics.sh
new file mode 100755
index 00000000..69b3facb
--- /dev/null
+++ b/scripts/test_analytics.sh
@@ -0,0 +1,197 @@
+#!/bin/bash
+
+# Test script for Decision Engine Analytics
+set -e
+
+echo "🚀 Testing Decision Engine Analytics Setup"
+echo "=========================================="
+
+# Colors for output
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+YELLOW='\033[1;33m'
+NC='\033[0m' # No Color
+
+# Function to print colored output
+print_status() {
+ echo -e "${GREEN}✓${NC} $1"
+}
+
+print_warning() {
+ echo -e "${YELLOW}⚠${NC} $1"
+}
+
+print_error() {
+ echo -e "${RED}✗${NC} $1"
+}
+
+# Check if Docker is running
+if ! docker info > /dev/null 2>&1; then
+ print_error "Docker is not running. Please start Docker first."
+ exit 1
+fi
+
+print_status "Docker is running"
+
+# Check if docker-compose is available
+if ! command -v docker-compose &> /dev/null; then
+ print_error "docker-compose is not installed"
+ exit 1
+fi
+
+print_status "docker-compose is available"
+
+echo ""
+echo "🔧 Starting Analytics Infrastructure..."
+echo "======================================"
+
+# Clean up any existing containers to avoid conflicts
+print_status "Cleaning up existing containers..."
+docker-compose --profile analytics down --remove-orphans 2>/dev/null || true
+
+# Start analytics infrastructure
+print_status "Starting Zookeeper, Kafka, ClickHouse and Analytics Migrator..."
+docker-compose up -d kafka zookeeper clickhouse analytics-migrator
+
+# Wait for services to be ready
+echo ""
+echo "⏳ Waiting for services to be ready..."
+sleep 10
+
+# Check Kafka
+echo ""
+echo "🔍 Checking Kafka..."
+if docker exec open-router-kafka kafka-topics --bootstrap-server localhost:9092 --list > /dev/null 2>&1; then
+ print_status "Kafka is running"
+else
+ print_error "Kafka is not responding"
+ exit 1
+fi
+
+# Check ClickHouse
+echo ""
+echo "🔍 Checking ClickHouse..."
+if docker exec open-router-clickhouse clickhouse-client --query "SELECT 1" > /dev/null 2>&1; then
+ print_status "ClickHouse is running"
+else
+ print_error "ClickHouse is not responding"
+ exit 1
+fi
+
+# Check if analytics database exists
+echo ""
+echo "🔍 Checking Analytics Database..."
+if docker exec open-router-clickhouse clickhouse-client --query "SHOW DATABASES" | grep -q "decision_engine_analytics"; then
+ print_status "Analytics database exists"
+else
+ print_warning "Analytics database not found, running migrations..."
+
+ # Run migrations manually if needed
+ docker exec open-router-clickhouse clickhouse-client --multiquery < analytics/migrations/001_routing_events.sql
+
+ if docker exec open-router-clickhouse clickhouse-client --query "SHOW DATABASES" | grep -q "decision_engine_analytics"; then
+ print_status "Analytics database created successfully"
+ else
+ print_error "Failed to create analytics database"
+ exit 1
+ fi
+fi
+
+# Check analytics tables
+echo ""
+echo "🔍 Checking Analytics Tables..."
+TABLES=$(docker exec open-router-clickhouse clickhouse-client --query "SHOW TABLES FROM decision_engine_analytics")
+
+if echo "$TABLES" | grep -q "routing_events"; then
+ print_status "routing_events table exists"
+else
+ print_error "routing_events table not found"
+ exit 1
+fi
+
+if echo "$TABLES" | grep -q "routing_events_queue"; then
+ print_status "routing_events_queue table exists"
+else
+ print_error "routing_events_queue table not found"
+ exit 1
+fi
+
+# Test Kafka topic creation
+echo ""
+echo "🔍 Checking Kafka Topics..."
+if docker exec open-router-kafka kafka-topics --bootstrap-server localhost:9092 --list | grep -q "decision-engine-routing-events"; then
+ print_status "Routing events topic exists"
+else
+ print_warning "Creating routing events topic..."
+ docker exec open-router-kafka kafka-topics --bootstrap-server localhost:9092 --create --topic decision-engine-routing-events --partitions 3 --replication-factor 1
+ print_status "Routing events topic created"
+fi
+
+# Test sending a sample event to Kafka
+echo ""
+echo "🧪 Testing Event Publishing..."
+SAMPLE_EVENT='{"event_id":"test-event-1","merchant_id":"test-merchant","request_id":"test-req-1","endpoint":"/routing/evaluate","method":"POST","request_payload":"{}","response_payload":"{}","status_code":200,"processing_time_ms":100,"gateway_selected":"stripe","routing_algorithm_id":"algo-1","error_message":null,"user_agent":"test-agent","ip_address":"127.0.0.1","created_at":"2024-01-01T12:00:00Z","sign_flag":1}'
+
+echo "$SAMPLE_EVENT" | docker exec -i open-router-kafka kafka-console-producer --bootstrap-server localhost:9092 --topic decision-engine-routing-events
+
+print_status "Sample event sent to Kafka"
+
+# Wait a moment for processing
+sleep 5
+
+# Check if event was processed by ClickHouse
+echo ""
+echo "🔍 Checking Event Processing..."
+EVENT_COUNT=$(docker exec open-router-clickhouse clickhouse-client --query "SELECT count(*) FROM decision_engine_analytics.routing_events WHERE event_id = 'test-event-1'")
+
+if [ "$EVENT_COUNT" -gt 0 ]; then
+ print_status "Event successfully processed by ClickHouse"
+else
+ print_warning "Event not yet processed (this might be normal for new setups)"
+fi
+
+# Show sample queries
+echo ""
+echo "📊 Sample Analytics Queries"
+echo "=========================="
+
+echo ""
+echo "Total events in the last hour:"
+docker exec open-router-clickhouse clickhouse-client --query "
+SELECT count(*) as total_events
+FROM decision_engine_analytics.routing_events
+WHERE created_at >= now() - INTERVAL 1 HOUR
+"
+
+echo ""
+echo "Events by endpoint:"
+docker exec open-router-clickhouse clickhouse-client --query "
+SELECT
+ endpoint,
+ count(*) as event_count
+FROM decision_engine_analytics.routing_events
+GROUP BY endpoint
+ORDER BY event_count DESC
+"
+
+echo ""
+echo "🎉 Analytics Setup Test Complete!"
+echo "================================="
+print_status "All analytics components are running correctly"
+
+echo ""
+echo "📝 Next Steps:"
+echo "1. Enable analytics in your config: Set analytics.enabled = true"
+echo "2. Start the decision engine: docker-compose up open-router-local"
+echo "3. Send test requests to /routing/evaluate or /decide-gateway"
+echo "4. Query analytics data using the sample queries above"
+
+echo ""
+echo "🔗 Useful Commands:"
+echo "- View ClickHouse logs: docker logs open-router-clickhouse"
+echo "- View Kafka logs: docker logs open-router-kafka"
+echo "- Connect to ClickHouse: docker exec -it open-router-clickhouse clickhouse-client"
+echo "- List Kafka topics: docker exec open-router-kafka kafka-topics --bootstrap-server localhost:9092 --list"
+
+echo ""
+echo "📚 For more information, see analytics/README.md"
diff --git a/scripts/test_kafka_connection.sh b/scripts/test_kafka_connection.sh
new file mode 100755
index 00000000..23ca2ea7
--- /dev/null
+++ b/scripts/test_kafka_connection.sh
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+echo "Testing Kafka connection from application container..."
+
+# Test 1: Check if the application can reach Kafka
+echo "1. Testing network connectivity to Kafka..."
+docker exec open-router-kafka sh -c "nc -z kafka 29092 && echo 'Kafka is reachable' || echo 'Kafka is NOT reachable'"
+
+# Test 2: Send a test message to the topic using kafka tools from within the kafka container
+echo "2. Sending test message to decision-engine-routing-events topic..."
+docker exec open-router-kafka kafka-console-producer --bootstrap-server localhost:9092 --topic decision-engine-routing-events <>,
+ event_sender: Option>,
+}
+
+impl AnalyticsClient {
+ pub fn new(config: AnalyticsConfig) -> AnalyticsResult {
+ if !config.enabled {
+ info!("Analytics is disabled");
+ return Ok(Self {
+ config,
+ kafka_producer: None,
+ event_sender: None,
+ });
+ }
+
+ // Initialize Kafka producer
+ let kafka_producer = Arc::new(KafkaProducer::new(config.kafka.clone())?);
+
+ // Create event channel for batching
+ let (event_sender, event_receiver) = mpsc::channel::(1000);
+
+ // Start batch processor
+ let _batch_processor = kafka_producer.start_batch_processor(event_receiver);
+
+ info!("Analytics client initialized successfully");
+
+ Ok(Self {
+ config,
+ kafka_producer: Some(kafka_producer),
+ event_sender: Some(event_sender),
+ })
+ }
+
+ pub async fn track_routing_event(&self, event: RoutingEvent) -> AnalyticsResult<()> {
+ if !self.config.enabled {
+ return Ok(());
+ }
+
+ let event_data = event.to_event_data();
+
+ if let Some(sender) = &self.event_sender {
+ if let Err(e) = sender.try_send(event_data) {
+ match e {
+ mpsc::error::TrySendError::Full(_) => {
+ warn!("Analytics event queue is full, dropping event");
+ }
+ mpsc::error::TrySendError::Closed(_) => {
+ error!("Analytics event channel is closed");
+ return Err(AnalyticsError::Configuration(
+ "Event channel is closed".to_string(),
+ ));
+ }
+ }
+ }
+ }
+
+ Ok(())
+ }
+
+ pub async fn track_routing_event_sync(&self, event: RoutingEvent) -> AnalyticsResult<()> {
+ if !self.config.enabled {
+ return Ok(());
+ }
+
+ let event_data = event.to_event_data();
+
+ if let Some(producer) = &self.kafka_producer {
+ producer.send_event(&event_data).await?;
+ }
+
+ Ok(())
+ }
+
+ pub async fn flush_events(&self) -> AnalyticsResult<()> {
+ if !self.config.enabled {
+ return Ok(());
+ }
+
+ // Close the sender to trigger flush in batch processor
+ if let Some(sender) = &self.event_sender {
+ sender.closed().await;
+ }
+
+ Ok(())
+ }
+
+ pub fn is_enabled(&self) -> bool {
+ self.config.enabled
+ }
+
+ pub async fn health_check(&self) -> AnalyticsResult<()> {
+ if !self.config.enabled {
+ return Ok(());
+ }
+
+ // Test Kafka connectivity by sending a test event
+ if let Some(producer) = &self.kafka_producer {
+ let test_event = RoutingEventData {
+ event_id: "health-check".to_string(),
+ merchant_id: "health-check".to_string(),
+ request_id: "health-check".to_string(),
+ endpoint: "/health".to_string(),
+ method: "GET".to_string(),
+ request_payload: "{}".to_string(),
+ response_payload: r#"{"status": "ok"}"#.to_string(),
+ status_code: 200,
+ processing_time_ms: 1,
+ gateway_selected: None,
+ routing_algorithm_id: None,
+ error_message: None,
+ user_agent: Some("health-check".to_string()),
+ ip_address: Some("127.0.0.1".to_string()),
+ created_at: time::OffsetDateTime::now_utc(),
+ sign_flag: 1,
+ };
+
+ producer.send_event(&test_event).await?;
+ }
+
+ Ok(())
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::analytics::{ClickhouseConfig, KafkaConfig};
+
+ #[tokio::test]
+ async fn test_analytics_client_disabled() {
+ let config = AnalyticsConfig {
+ enabled: false,
+ kafka: KafkaConfig::default(),
+ clickhouse: ClickhouseConfig::default(),
+ };
+
+ let client = AnalyticsClient::new(config).unwrap();
+ assert!(!client.is_enabled());
+
+ let event = RoutingEvent::new(
+ "merchant-123".to_string(),
+ "req-456".to_string(),
+ "/routing/evaluate".to_string(),
+ "POST".to_string(),
+ );
+
+ // Should not error when disabled
+ let result = client.track_routing_event(event).await;
+ assert!(result.is_ok());
+ }
+
+ #[test]
+ fn test_analytics_config_default() {
+ let config = AnalyticsConfig::default();
+ assert!(!config.enabled);
+ assert_eq!(config.kafka.brokers, vec!["localhost:9092"]);
+ assert_eq!(config.kafka.topic_prefix, "decision-engine");
+ assert_eq!(config.clickhouse.host, "http://localhost:8123");
+ assert_eq!(config.clickhouse.username, "analytics_user");
+ }
+}
diff --git a/src/analytics/events.rs b/src/analytics/events.rs
new file mode 100644
index 00000000..46cd8a3b
--- /dev/null
+++ b/src/analytics/events.rs
@@ -0,0 +1,284 @@
+use crate::analytics::{AnalyticsResult, RoutingEventData};
+use axum::extract::Request;
+use serde_json::Value;
+use time::OffsetDateTime;
+use uuid::Uuid;
+
+#[derive(Clone)]
+pub struct RoutingEvent {
+ pub event_id: String,
+ pub merchant_id: String,
+ pub request_id: String,
+ pub endpoint: String,
+ pub method: String,
+ pub request_payload: String,
+ pub response_payload: String,
+ pub status_code: u16,
+ pub processing_time_ms: u32,
+ pub gateway_selected: Option,
+ pub routing_algorithm_id: Option,
+ pub error_message: Option,
+ pub user_agent: Option,
+ pub ip_address: Option,
+ pub created_at: OffsetDateTime,
+}
+
+impl RoutingEvent {
+ pub fn new(merchant_id: String, request_id: String, endpoint: String, method: String) -> Self {
+ Self {
+ event_id: Uuid::new_v4().to_string(),
+ merchant_id,
+ request_id,
+ endpoint,
+ method,
+ request_payload: String::new(),
+ response_payload: String::new(),
+ status_code: 0,
+ processing_time_ms: 0,
+ gateway_selected: None,
+ routing_algorithm_id: None,
+ error_message: None,
+ user_agent: None,
+ ip_address: None,
+ created_at: OffsetDateTime::now_utc(),
+ }
+ }
+
+ pub fn from_request(request: &Request, merchant_id: String) -> Self {
+ let request_id = extract_request_id(request);
+ let endpoint = request.uri().path().to_string();
+ let method = request.method().to_string();
+ let user_agent = extract_user_agent(request);
+ let ip_address = extract_ip_address(request);
+
+ Self {
+ event_id: Uuid::new_v4().to_string(),
+ merchant_id,
+ request_id,
+ endpoint,
+ method,
+ request_payload: String::new(),
+ response_payload: String::new(),
+ status_code: 0,
+ processing_time_ms: 0,
+ gateway_selected: None,
+ routing_algorithm_id: None,
+ error_message: None,
+ user_agent,
+ ip_address,
+ created_at: OffsetDateTime::now_utc(),
+ }
+ }
+
+ pub fn with_request_payload(mut self, payload: &str) -> Self {
+ self.request_payload = payload.to_string();
+ self
+ }
+
+ pub fn with_response_payload(mut self, payload: &str) -> Self {
+ self.response_payload = payload.to_string();
+ self
+ }
+
+ pub fn with_status_code(mut self, status_code: u16) -> Self {
+ self.status_code = status_code;
+ self
+ }
+
+ pub fn with_processing_time(mut self, processing_time_ms: u32) -> Self {
+ self.processing_time_ms = processing_time_ms;
+ self
+ }
+
+ pub fn with_gateway_selected(mut self, gateway: Option) -> Self {
+ self.gateway_selected = gateway;
+ self
+ }
+
+ pub fn with_routing_algorithm_id(mut self, algorithm_id: Option) -> Self {
+ self.routing_algorithm_id = algorithm_id;
+ self
+ }
+
+ pub fn with_error_message(mut self, error: Option) -> Self {
+ self.error_message = error;
+ self
+ }
+
+ pub fn to_event_data(&self) -> RoutingEventData {
+ RoutingEventData {
+ event_id: self.event_id.clone(),
+ merchant_id: self.merchant_id.clone(),
+ request_id: self.request_id.clone(),
+ endpoint: self.endpoint.clone(),
+ method: self.method.clone(),
+ request_payload: self.request_payload.clone(),
+ response_payload: self.response_payload.clone(),
+ status_code: self.status_code,
+ processing_time_ms: self.processing_time_ms,
+ gateway_selected: self.gateway_selected.clone(),
+ routing_algorithm_id: self.routing_algorithm_id.clone(),
+ error_message: self.error_message.clone(),
+ user_agent: self.user_agent.clone(),
+ ip_address: self.ip_address.clone(),
+ created_at: self.created_at,
+ sign_flag: 1, // Always 1 for new events
+ }
+ }
+
+ /// Extract gateway information from response payload
+ pub fn extract_gateway_from_response(&mut self) -> AnalyticsResult<()> {
+ if !self.response_payload.is_empty() {
+ if let Ok(response_json) = serde_json::from_str::(&self.response_payload) {
+ // Try to extract gateway from various possible response structures
+ if let Some(gateway) = response_json
+ .get("gateway")
+ .or_else(|| response_json.get("selected_gateway"))
+ .or_else(|| response_json.get("connector"))
+ .and_then(|v| v.as_str())
+ {
+ self.gateway_selected = Some(gateway.to_string());
+ }
+
+ // Try to extract routing algorithm ID
+ if let Some(algo_id) = response_json
+ .get("routing_algorithm_id")
+ .or_else(|| response_json.get("algorithm_id"))
+ .and_then(|v| v.as_str())
+ {
+ self.routing_algorithm_id = Some(algo_id.to_string());
+ }
+ }
+ }
+ Ok(())
+ }
+
+ /// Extract error information from response payload
+ pub fn extract_error_from_response(&mut self) -> AnalyticsResult<()> {
+ if self.status_code >= 400 && !self.response_payload.is_empty() {
+ if let Ok(response_json) = serde_json::from_str::(&self.response_payload) {
+ if let Some(error) = response_json
+ .get("error")
+ .or_else(|| response_json.get("message"))
+ .or_else(|| response_json.get("error_message"))
+ .and_then(|v| v.as_str())
+ {
+ self.error_message = Some(error.to_string());
+ }
+ }
+ }
+ Ok(())
+ }
+}
+
+fn extract_request_id(request: &Request) -> String {
+ request
+ .headers()
+ .get("x-request-id")
+ .or_else(|| request.headers().get("request-id"))
+ .and_then(|v| v.to_str().ok())
+ .map(|s| s.to_string())
+ .unwrap_or_else(|| Uuid::new_v4().to_string())
+}
+
+fn extract_user_agent(request: &Request) -> Option {
+ request
+ .headers()
+ .get("user-agent")
+ .and_then(|v| v.to_str().ok())
+ .map(|s| s.to_string())
+}
+
+fn extract_ip_address(request: &Request) -> Option {
+ // Try various headers for IP address
+ request
+ .headers()
+ .get("x-forwarded-for")
+ .or_else(|| request.headers().get("x-real-ip"))
+ .or_else(|| request.headers().get("cf-connecting-ip"))
+ .and_then(|v| v.to_str().ok())
+ .map(|s| {
+ // Take the first IP if there are multiple (comma-separated)
+ s.split(',')
+ .next()
+ .map(|ip| ip.trim().to_string())
+ .unwrap_or_else(String::new)
+ })
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_routing_event_creation() {
+ let event = RoutingEvent::new(
+ "merchant-123".to_string(),
+ "req-456".to_string(),
+ "/routing/evaluate".to_string(),
+ "POST".to_string(),
+ );
+
+ assert_eq!(event.merchant_id, "merchant-123");
+ assert_eq!(event.request_id, "req-456");
+ assert_eq!(event.endpoint, "/routing/evaluate");
+ assert_eq!(event.method, "POST");
+ assert!(!event.event_id.is_empty());
+ }
+
+ #[test]
+ fn test_event_builder_pattern() {
+ let event = RoutingEvent::new(
+ "merchant-123".to_string(),
+ "req-456".to_string(),
+ "/routing/evaluate".to_string(),
+ "POST".to_string(),
+ )
+ .with_request_payload(r#"{"test": "data"}"#)
+ .with_response_payload(r#"{"gateway": "stripe"}"#)
+ .with_status_code(200)
+ .with_processing_time(150)
+ .with_gateway_selected(Some("stripe".to_string()));
+
+ assert_eq!(event.request_payload, r#"{"test": "data"}"#);
+ assert_eq!(event.response_payload, r#"{"gateway": "stripe"}"#);
+ assert_eq!(event.status_code, 200);
+ assert_eq!(event.processing_time_ms, 150);
+ assert_eq!(event.gateway_selected, Some("stripe".to_string()));
+ }
+
+ #[test]
+ fn test_extract_gateway_from_response() {
+ let mut event = RoutingEvent::new(
+ "merchant-123".to_string(),
+ "req-456".to_string(),
+ "/routing/evaluate".to_string(),
+ "POST".to_string(),
+ )
+ .with_response_payload(r#"{"gateway": "stripe", "routing_algorithm_id": "algo-123"}"#);
+
+ event.extract_gateway_from_response().unwrap();
+
+ assert_eq!(event.gateway_selected, Some("stripe".to_string()));
+ assert_eq!(event.routing_algorithm_id, Some("algo-123".to_string()));
+ }
+
+ #[test]
+ fn test_extract_error_from_response() {
+ let mut event = RoutingEvent::new(
+ "merchant-123".to_string(),
+ "req-456".to_string(),
+ "/routing/evaluate".to_string(),
+ "POST".to_string(),
+ )
+ .with_response_payload(r#"{"error": "Gateway not available"}"#)
+ .with_status_code(500);
+
+ event.extract_error_from_response().unwrap();
+
+ assert_eq!(
+ event.error_message,
+ Some("Gateway not available".to_string())
+ );
+ }
+}
diff --git a/src/analytics/kafka_producer.rs b/src/analytics/kafka_producer.rs
new file mode 100644
index 00000000..17014660
--- /dev/null
+++ b/src/analytics/kafka_producer.rs
@@ -0,0 +1,248 @@
+use crate::analytics::{AnalyticsError, AnalyticsResult, KafkaConfig, RoutingEventData};
+use kafka::producer::{Producer, Record, RequiredAcks};
+use std::time::Duration;
+use tokio::sync::mpsc;
+use tracing::{debug, error, info, warn};
+
+#[derive(Clone)]
+pub struct KafkaProducer {
+ config: KafkaConfig,
+ topic: String,
+}
+
+impl KafkaProducer {
+ pub fn new(config: KafkaConfig) -> AnalyticsResult {
+ let topic = format!("{}-routing-events", config.topic_prefix);
+
+ // Validate broker configuration
+ if config.brokers.is_empty() {
+ return Err(AnalyticsError::Configuration(
+ "No Kafka brokers configured".to_string(),
+ ));
+ }
+
+ debug!(
+ "Initializing Kafka producer with brokers: {:?}",
+ config.brokers
+ );
+
+ Ok(Self { config, topic })
+ }
+
+ /// Test Kafka connectivity
+ pub async fn test_connection(&self) -> AnalyticsResult<()> {
+ debug!(
+ "Testing Kafka connection to brokers: {:?}",
+ self.config.brokers
+ );
+
+ Producer::from_hosts(self.config.brokers.clone())
+ .with_ack_timeout(Duration::from_secs(5))
+ .with_required_acks(RequiredAcks::One)
+ .create()
+ .map_err(|e| {
+ error!(
+ "Failed to create Kafka producer for connection test: {:?}",
+ e
+ );
+ AnalyticsError::Kafka(e)
+ })?;
+
+ info!("Kafka connection test successful");
+ Ok(())
+ }
+
+ pub async fn send_event(&self, event: &RoutingEventData) -> AnalyticsResult<()> {
+ let json_data = serde_json::to_string(event)?;
+
+ // Create producer with configuration
+ let mut producer = Producer::from_hosts(self.config.brokers.clone())
+ .with_ack_timeout(Duration::from_secs(1))
+ .with_required_acks(RequiredAcks::One)
+ .create()
+ .map_err(AnalyticsError::Kafka)?;
+
+ // Send the record
+ let record =
+ Record::from_key_value(&self.topic, event.event_id.as_bytes(), json_data.as_bytes());
+
+ producer.send(&record).map_err(AnalyticsError::Kafka)?;
+
+ Ok(())
+ }
+
+ pub async fn send_events_batch(&self, events: &[RoutingEventData]) -> AnalyticsResult<()> {
+ if events.is_empty() {
+ return Ok(());
+ }
+
+ let mut producer = Producer::from_hosts(self.config.brokers.clone())
+ .with_ack_timeout(Duration::from_secs(5))
+ .with_required_acks(RequiredAcks::One)
+ .create()
+ .map_err(|e| {
+ error!("Failed to create Kafka producer for batch send: {:?}", e);
+ warn!("Kafka brokers configured: {:?}", self.config.brokers);
+ AnalyticsError::Kafka(e)
+ })?;
+
+ for (index, event) in events.iter().enumerate() {
+ let json_data = serde_json::to_string(event)?;
+ let record = Record::from_key_value(
+ &self.topic,
+ event.event_id.as_bytes(),
+ json_data.as_bytes(),
+ );
+
+ if let Err(e) = producer.send(&record) {
+ error!(
+ "Failed to send event {} of {} to Kafka: {:?}",
+ index + 1,
+ events.len(),
+ e
+ );
+ return Err(AnalyticsError::Kafka(e));
+ }
+ }
+
+ info!(
+ "Successfully sent {} events to Kafka topic: {}",
+ events.len(),
+ self.topic
+ );
+ Ok(())
+ }
+
+ /// Send events batch with graceful error handling
+ pub async fn send_events_batch_graceful(&self, events: &[RoutingEventData]) -> bool {
+ match self.send_events_batch(events).await {
+ Ok(()) => true,
+ Err(e) => {
+ warn!(
+ "Failed to send events batch to Kafka, continuing without analytics: {:?}",
+ e
+ );
+ false
+ }
+ }
+ }
+
+ pub fn start_batch_processor(
+ &self,
+ mut receiver: mpsc::Receiver,
+ ) -> tokio::task::JoinHandle<()> {
+ let producer = self.clone();
+ let batch_size = self.config.batch_size;
+ let batch_timeout = Duration::from_millis(self.config.batch_timeout_ms);
+ let max_consecutive_failures = self.config.max_consecutive_failures;
+
+ tokio::spawn(async move {
+ let mut batch = Vec::with_capacity(batch_size);
+ let mut last_flush = tokio::time::Instant::now();
+ let mut consecutive_failures = 0;
+ info!("Starting Kafka batch processor with batch_size: {}, timeout: {}ms, max_consecutive_failures: {}",
+ batch_size, batch_timeout.as_millis(), max_consecutive_failures);
+
+ loop {
+ tokio::select! {
+ // Receive new events
+ event = receiver.recv() => {
+ match event {
+ Some(event) => {
+ batch.push(event);
+
+ // Flush if batch is full
+ if batch.len() >= batch_size {
+ let success = producer.send_events_batch_graceful(&batch).await;
+ if success {
+ consecutive_failures = 0;
+ } else {
+ consecutive_failures += 1;
+ if consecutive_failures >= max_consecutive_failures {
+ warn!("Too many consecutive Kafka failures ({}), continuing to collect events but not sending",
+ consecutive_failures);
+ }
+ }
+ batch.clear();
+ last_flush = tokio::time::Instant::now();
+ }
+ }
+ None => {
+ // Channel closed, flush remaining events and exit
+ if !batch.is_empty() {
+ info!("Channel closed, sending final batch of {} events", batch.len());
+ producer.send_events_batch_graceful(&batch).await;
+ }
+ info!("Kafka batch processor shutting down");
+ break;
+ }
+ }
+ }
+
+ // Timeout-based flush
+ _ = tokio::time::sleep_until(last_flush + batch_timeout) => {
+ if !batch.is_empty() {
+ let success = producer.send_events_batch_graceful(&batch).await;
+ if success {
+ consecutive_failures = 0;
+ } else {
+ consecutive_failures += 1;
+ if consecutive_failures >= max_consecutive_failures {
+ warn!("Too many consecutive Kafka failures ({}), continuing to collect events but not sending",
+ consecutive_failures);
+ }
+ }
+ batch.clear();
+ last_flush = tokio::time::Instant::now();
+ }
+ }
+ }
+ }
+ })
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use time::OffsetDateTime;
+
+ #[tokio::test]
+ async fn test_kafka_producer_creation() {
+ let config = KafkaConfig {
+ brokers: vec!["localhost:9092".to_string()],
+ topic_prefix: "test".to_string(),
+ batch_size: 10,
+ batch_timeout_ms: 1000,
+ max_consecutive_failures: 5,
+ };
+
+ let producer = KafkaProducer::new(config);
+ assert!(producer.is_ok());
+ }
+
+ #[test]
+ fn test_event_serialization() {
+ let event = RoutingEventData {
+ event_id: "test-event-1".to_string(),
+ merchant_id: "merchant-123".to_string(),
+ request_id: "req-456".to_string(),
+ endpoint: "/routing/evaluate".to_string(),
+ method: "POST".to_string(),
+ request_payload: r#"{"test": "data"}"#.to_string(),
+ response_payload: r#"{"result": "success"}"#.to_string(),
+ status_code: 200,
+ processing_time_ms: 150,
+ gateway_selected: Some("stripe".to_string()),
+ routing_algorithm_id: Some("algo-789".to_string()),
+ error_message: None,
+ user_agent: Some("test-agent".to_string()),
+ ip_address: Some("127.0.0.1".to_string()),
+ created_at: OffsetDateTime::now_utc(),
+ sign_flag: 1,
+ };
+
+ let json = serde_json::to_string(&event);
+ assert!(json.is_ok());
+ }
+}
diff --git a/src/analytics/middleware.rs b/src/analytics/middleware.rs
new file mode 100644
index 00000000..43323336
--- /dev/null
+++ b/src/analytics/middleware.rs
@@ -0,0 +1,159 @@
+use crate::analytics::RoutingEvent;
+use crate::tenant::GlobalAppState;
+use axum::{
+ body::Body,
+ extract::{Request, State},
+ middleware::Next,
+ response::Response,
+};
+use bytes::Bytes;
+use http_body_util::BodyExt;
+use std::{sync::Arc, time::Instant};
+use tracing::{error, warn};
+
+/// Analytics middleware to track routing events for specific endpoints
+pub async fn analytics_middleware(
+ State(global_app_state): State>,
+ request: Request,
+ next: Next,
+) -> Response {
+ // Only track analytics for routing endpoints
+ let path = request.uri().path();
+ if !global_app_state.global_config.analytics.enabled || !should_track_endpoint(path) {
+ return next.run(request).await;
+ }
+
+ let start_time = Instant::now();
+
+ // Extract merchant ID from request headers or body (simplified for now)
+ let merchant_id = extract_merchant_id(&request).unwrap_or("public".to_string());
+
+ // Get the tenant app state to access analytics client
+ let tenant_app_state = match global_app_state.get_app_state_of_tenant(&merchant_id).await {
+ Ok(state) => state,
+ Err(_) => {
+ // If tenant not found, try with default "public" tenant
+ match global_app_state.get_app_state_of_tenant("public").await {
+ Ok(state) => state,
+ Err(_) => {
+ // If analytics client is not available, just proceed without analytics
+ return next.run(request).await;
+ }
+ }
+ }
+ };
+
+ // Create routing event
+ let mut routing_event = RoutingEvent::from_request(&request, merchant_id.clone());
+
+ // Extract request body for logging
+ let (request_parts, body) = request.into_parts();
+ let body_bytes = match body.collect().await {
+ Ok(collected) => collected.to_bytes(),
+ Err(_) => Bytes::new(),
+ };
+
+ let request_payload = String::from_utf8_lossy(&body_bytes).to_string();
+ routing_event = routing_event.with_request_payload(&request_payload);
+
+ // Reconstruct request with body
+ let request = Request::from_parts(request_parts, Body::from(body_bytes));
+
+ // Process the request
+ let response = next.run(request).await;
+
+ // Calculate processing time
+ let processing_time = start_time.elapsed().as_millis() as u32;
+
+ // Extract response information
+ let status_code = response.status().as_u16();
+
+ // Extract response body for logging. Note: This operation can lead to high memory usage
+ let (response_parts, body) = response.into_parts();
+ let body_bytes = match body.collect().await {
+ Ok(collected) => collected.to_bytes(),
+ Err(_) => Bytes::new(),
+ };
+
+ let response_payload = String::from_utf8_lossy(&body_bytes).to_string();
+
+ // Complete the routing event
+ routing_event = routing_event
+ .with_response_payload(&response_payload)
+ .with_status_code(status_code)
+ .with_processing_time(processing_time);
+
+ // Extract gateway information from response
+ if let Err(e) = routing_event.extract_gateway_from_response() {
+ warn!("Failed to extract gateway from response: {:?}", e);
+ }
+
+ // Extract error information if status indicates failure
+ if let Err(e) = routing_event.extract_error_from_response() {
+ warn!("Failed to extract error from response: {:?}", e);
+ }
+
+ // Send event to analytics (async, non-blocking)
+ if let Err(e) = tenant_app_state
+ .analytics_client
+ .track_routing_event(routing_event)
+ .await
+ {
+ error!("Failed to track routing event: {:?}", e);
+ }
+
+ // Reconstruct response
+ Response::from_parts(response_parts, Body::from(body_bytes))
+}
+
+/// Determine if an endpoint should be tracked for analytics
+fn should_track_endpoint(path: &str) -> bool {
+ matches!(path, "/routing/evaluate" | "/decide-gateway")
+}
+
+/// Extract merchant ID from request (simplified implementation)
+fn extract_merchant_id(request: &Request) -> Option {
+ // Try to extract from headers first
+ if let Some(merchant_id) = request.headers().get("x-merchant-id") {
+ if let Ok(merchant_id_str) = merchant_id.to_str() {
+ return Some(merchant_id_str.to_string());
+ }
+ }
+
+ // Try x-tenant-id header as fallback
+ if let Some(tenant_id) = request.headers().get("x-tenant-id") {
+ if let Ok(tenant_id_str) = tenant_id.to_str() {
+ return Some(tenant_id_str.to_string());
+ }
+ }
+
+ // Default to "public" tenant
+ Some("public".to_string())
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_should_track_endpoint() {
+ assert!(should_track_endpoint("/routing/evaluate"));
+ assert!(should_track_endpoint("/decide-gateway"));
+ assert!(!should_track_endpoint("/health"));
+ assert!(!should_track_endpoint("/rule/create"));
+ }
+
+ #[test]
+ fn test_extract_merchant_id_from_header() {
+ let request = Request::builder()
+ .uri("/routing/evaluate")
+ .header("x-merchant-id", "merchant-123")
+ .body(Body::empty())
+ .unwrap();
+
+ assert_eq!(
+ extract_merchant_id(&request).as_deref(),
+ Some("merchant-123")
+ );
+ }
+}
diff --git a/src/analytics/mod.rs b/src/analytics/mod.rs
new file mode 100644
index 00000000..427265d0
--- /dev/null
+++ b/src/analytics/mod.rs
@@ -0,0 +1,15 @@
+pub mod client;
+pub mod events;
+pub mod kafka_producer;
+pub mod middleware;
+pub mod models;
+pub mod service;
+pub mod types;
+
+pub use client::AnalyticsClient;
+pub use events::RoutingEvent;
+pub use kafka_producer::KafkaProducer;
+pub use middleware::analytics_middleware;
+pub use models::*;
+pub use service::*;
+pub use types::*;
diff --git a/src/analytics/models.rs b/src/analytics/models.rs
new file mode 100644
index 00000000..f979648b
--- /dev/null
+++ b/src/analytics/models.rs
@@ -0,0 +1,317 @@
+use serde::{Deserialize, Serialize};
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct AnalyticsQuery {
+ pub merchant_id: Option,
+ pub scope: AnalyticsScope,
+ pub range: AnalyticsRange,
+ pub start_ms: Option,
+ pub end_ms: Option,
+ pub page: usize,
+ pub page_size: usize,
+ pub payment_method_type: Option,
+ pub payment_method: Option,
+ pub card_network: Option,
+ pub card_is_in: Option,
+ pub currency: Option,
+ pub country: Option,
+ pub auth_type: Option,
+ pub gateways: Vec,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
+#[serde(rename_all = "snake_case")]
+pub enum AnalyticsScope {
+ Current,
+ All,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
+#[serde(rename_all = "snake_case")]
+pub enum AnalyticsRange {
+ M15,
+ H1,
+ H24,
+}
+
+impl AnalyticsRange {
+ pub fn from_query(value: Option<&str>) -> Self {
+ match value {
+ Some("15m") => Self::M15,
+ Some("24h") => Self::H24,
+ _ => Self::H1,
+ }
+ }
+
+ pub fn window_ms(&self) -> i64 {
+ match self {
+ Self::M15 => 15 * 60 * 1000,
+ Self::H1 => 60 * 60 * 1000,
+ Self::H24 => 24 * 60 * 60 * 1000,
+ }
+ }
+
+ pub fn bucket_ms(&self) -> i64 {
+ match self {
+ Self::M15 => 60 * 1000,
+ Self::H1 => 5 * 60 * 1000,
+ Self::H24 => 15 * 60 * 1000,
+ }
+ }
+}
+
+impl AnalyticsScope {
+ pub fn from_query(value: Option<&str>) -> Self {
+ match value {
+ Some("all") => Self::All,
+ _ => Self::Current,
+ }
+ }
+
+ pub fn as_str(&self) -> &'static str {
+ match self {
+ Self::Current => "current",
+ Self::All => "all",
+ }
+ }
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct AnalyticsKpi {
+ pub label: String,
+ pub value: String,
+ pub subtitle: Option,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct AnalyticsOverviewResponse {
+ pub generated_at_ms: i64,
+ pub scope: String,
+ pub merchant_id: Option,
+ pub kpis: Vec,
+ pub route_hits: Vec,
+ pub top_scores: Vec,
+ pub top_errors: Vec,
+ pub top_rules: Vec,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct AnalyticsRouteHit {
+ pub route: String,
+ pub count: i64,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct GatewayScoreSnapshot {
+ pub merchant_id: String,
+ pub payment_method_type: String,
+ pub payment_method: String,
+ pub gateway: String,
+ pub score_value: f64,
+ pub sigma_factor: f64,
+ pub average_latency: f64,
+ pub tp99_latency: f64,
+ pub transaction_count: i64,
+ pub last_updated_ms: i64,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct GatewayScoreSeriesPoint {
+ pub bucket_ms: i64,
+ pub merchant_id: String,
+ pub payment_method_type: String,
+ pub payment_method: String,
+ pub gateway: String,
+ pub score_value: f64,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct AnalyticsGatewayScoresResponse {
+ pub generated_at_ms: i64,
+ pub scope: String,
+ pub merchant_id: Option,
+ pub range: String,
+ pub snapshots: Vec,
+ pub series: Vec,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct AnalyticsDecisionPoint {
+ pub bucket_ms: i64,
+ pub routing_approach: String,
+ pub count: i64,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct AnalyticsDecisionResponse {
+ pub generated_at_ms: i64,
+ pub scope: String,
+ pub merchant_id: Option,
+ pub range: String,
+ pub tiles: Vec,
+ pub series: Vec,
+ pub approaches: Vec,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct AnalyticsGatewaySharePoint {
+ pub bucket_ms: i64,
+ pub gateway: String,
+ pub count: i64,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct AnalyticsRoutingStatsResponse {
+ pub generated_at_ms: i64,
+ pub scope: String,
+ pub merchant_id: Option,
+ pub range: String,
+ pub gateway_share: Vec,
+ pub top_rules: Vec,
+ pub sr_trend: Vec,
+ pub available_filters: RoutingFilterOptions,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct RoutingFilterOptions {
+ pub dimensions: Vec,
+ pub missing_dimensions: Vec,
+ pub gateways: Vec,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct RoutingFilterDimension {
+ pub key: String,
+ pub label: String,
+ pub values: Vec,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct RoutingFilterDimensionHint {
+ pub key: String,
+ pub label: String,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct AnalyticsErrorSummary {
+ pub route: String,
+ pub error_code: String,
+ pub error_message: String,
+ pub count: i64,
+ pub last_seen_ms: i64,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct AnalyticsLogSample {
+ pub route: String,
+ pub merchant_id: Option,
+ pub payment_id: Option,
+ pub request_id: Option,
+ pub gateway: Option,
+ pub routing_approach: Option,
+ pub status: Option,
+ pub error_code: Option,
+ pub error_message: Option,
+ pub event_type: Option,
+ pub created_at_ms: i64,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct AnalyticsLogSummariesResponse {
+ pub generated_at_ms: i64,
+ pub scope: String,
+ pub merchant_id: Option,
+ pub range: String,
+ pub total_errors: i64,
+ pub errors: Vec,
+ pub samples: Vec,
+ pub page: usize,
+ pub page_size: usize,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct AnalyticsRuleHit {
+ pub rule_name: String,
+ pub count: i64,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct PaymentAuditQuery {
+ pub merchant_id: Option,
+ pub scope: AnalyticsScope,
+ pub range: AnalyticsRange,
+ pub start_ms: Option,
+ pub end_ms: Option,
+ pub page: usize,
+ pub page_size: usize,
+ pub payment_id: Option,
+ pub request_id: Option,
+ pub gateway: Option,
+ pub route: Option,
+ pub status: Option,
+ pub event_type: Option,
+ pub error_code: Option,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct PaymentAuditSummary {
+ pub lookup_key: String,
+ pub payment_id: Option,
+ pub request_id: Option,
+ pub merchant_id: Option,
+ pub first_seen_ms: i64,
+ pub last_seen_ms: i64,
+ pub event_count: usize,
+ pub latest_status: Option,
+ pub latest_gateway: Option,
+ pub latest_stage: Option,
+ pub gateways: Vec,
+ pub routes: Vec,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct PaymentAuditEvent {
+ pub id: i32,
+ pub event_type: String,
+ pub event_stage: Option,
+ pub route: Option,
+ pub merchant_id: Option,
+ pub payment_id: Option,
+ pub request_id: Option,
+ pub payment_method_type: Option,
+ pub payment_method: Option,
+ pub gateway: Option,
+ pub routing_approach: Option,
+ pub rule_name: Option,
+ pub status: Option,
+ pub error_code: Option,
+ pub error_message: Option,
+ pub score_value: Option,
+ pub sigma_factor: Option,
+ pub average_latency: Option,
+ pub tp99_latency: Option,
+ pub transaction_count: Option,
+ pub details: Option,
+ pub details_json: Option,
+ pub created_at_ms: i64,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct PaymentAuditResponse {
+ pub generated_at_ms: i64,
+ pub scope: String,
+ pub merchant_id: Option,
+ pub range: String,
+ pub payment_id: Option,
+ pub request_id: Option,
+ pub gateway: Option,
+ pub route: Option,
+ pub status: Option,
+ pub event_type: Option,
+ pub error_code: Option,
+ pub page: usize,
+ pub page_size: usize,
+ pub total_results: usize,
+ pub results: Vec,
+ pub timeline: Vec,
+}
diff --git a/src/analytics/service.rs b/src/analytics/service.rs
new file mode 100644
index 00000000..a96b49d4
--- /dev/null
+++ b/src/analytics/service.rs
@@ -0,0 +1,2025 @@
+use crate::analytics::models::*;
+use crate::error;
+use crate::metrics::{ANALYTICS_EVENT_COUNTER, ROUTING_DECISION_COUNTER, ROUTING_RULE_HIT_COUNTER};
+use async_bb8_diesel::AsyncRunQueryDsl;
+use diesel::prelude::*;
+use std::collections::{BTreeMap, BTreeSet, HashMap};
+use time::OffsetDateTime;
+
+#[cfg(feature = "mysql")]
+use crate::storage::schema;
+#[cfg(feature = "postgres")]
+use crate::storage::schema_pg;
+
+#[cfg(feature = "mysql")]
+use crate::storage::schema::analytics_event::dsl as analytics_dsl;
+#[cfg(feature = "postgres")]
+use crate::storage::schema_pg::analytics_event::dsl as analytics_dsl;
+
+#[derive(Debug, Clone, Insertable)]
+#[cfg_attr(feature = "mysql", diesel(table_name = schema::analytics_event))]
+#[cfg_attr(feature = "postgres", diesel(table_name = schema_pg::analytics_event))]
+pub struct NewAnalyticsEvent {
+ pub event_type: String,
+ pub merchant_id: Option,
+ pub payment_id: Option,
+ pub request_id: Option,
+ pub payment_method_type: Option,
+ pub payment_method: Option,
+ pub card_network: Option,
+ pub card_is_in: Option,
+ pub currency: Option,
+ pub country: Option,
+ pub auth_type: Option,
+ pub gateway: Option,
+ pub event_stage: Option,
+ pub routing_approach: Option,
+ pub rule_name: Option,
+ pub status: Option,
+ pub error_code: Option,
+ pub error_message: Option,
+ pub score_value: Option,
+ pub sigma_factor: Option,
+ pub average_latency: Option,
+ pub tp99_latency: Option,
+ pub transaction_count: Option,
+ pub route: Option,
+ pub details: Option,
+ pub created_at_ms: i64,
+}
+
+#[derive(Debug, Clone, Queryable, Selectable)]
+#[cfg_attr(feature = "mysql", diesel(table_name = schema::analytics_event))]
+#[cfg_attr(feature = "postgres", diesel(table_name = schema_pg::analytics_event))]
+pub struct AnalyticsEvent {
+ pub id: i32,
+ pub event_type: String,
+ pub merchant_id: Option,
+ pub payment_id: Option,
+ pub request_id: Option,
+ pub payment_method_type: Option,
+ pub payment_method: Option,
+ pub card_network: Option,
+ pub card_is_in: Option,
+ pub currency: Option,
+ pub country: Option,
+ pub auth_type: Option,
+ pub gateway: Option,
+ pub event_stage: Option,
+ pub routing_approach: Option,
+ pub rule_name: Option,
+ pub status: Option,
+ pub error_code: Option,
+ pub error_message: Option,
+ pub score_value: Option,
+ pub sigma_factor: Option,
+ pub average_latency: Option,
+ pub tp99_latency: Option,
+ pub transaction_count: Option,
+ pub route: Option,
+ pub details: Option,
+ pub created_at_ms: i64,
+}
+
+pub fn now_ms() -> i64 {
+ (OffsetDateTime::now_utc()
+ .unix_timestamp_nanos()
+ .div_euclid(1_000_000)) as i64
+}
+
+fn event_type_label(kind: &str) -> &'static str {
+ match kind {
+ "decision" => "decision",
+ "gateway_update" => "gateway_update",
+ "score_snapshot" => "score_snapshot",
+ "rule_hit" => "rule_hit",
+ "rule_evaluation_preview" => "rule_evaluation_preview",
+ "error" => "error",
+ "request_hit" => "request_hit",
+ _ => "other",
+ }
+}
+
+fn spawn_persist(event: NewAnalyticsEvent) {
+ let label = event_type_label(event.event_type.as_str());
+ ANALYTICS_EVENT_COUNTER.with_label_values(&[label]).inc();
+
+ tokio::spawn(async move {
+ if let Err(err) = persist_event(event).await {
+ crate::logger::debug!(error = %err, "Failed to persist analytics event");
+ }
+ });
+}
+
+pub fn record_decision_event(
+ merchant_id: Option,
+ routing_approach: Option,
+ gateway: Option,
+ status: Option,
+ route: &str,
+ rule_name: Option,
+ details: Option,
+ payment_id: Option,
+ request_id: Option,
+ event_stage: Option,
+ payment_method_type: Option,
+ payment_method: Option,
+) {
+ let approach = routing_approach
+ .clone()
+ .unwrap_or_else(|| "UNKNOWN".to_string());
+ let status_label = status.clone().unwrap_or_else(|| "success".to_string());
+ ROUTING_DECISION_COUNTER
+ .with_label_values(&[approach.as_str(), status_label.as_str()])
+ .inc();
+ spawn_persist(NewAnalyticsEvent {
+ event_type: "decision".to_string(),
+ merchant_id,
+ payment_id,
+ request_id,
+ payment_method_type,
+ payment_method,
+ card_network: None,
+ card_is_in: None,
+ currency: None,
+ country: None,
+ auth_type: None,
+ gateway,
+ event_stage,
+ routing_approach,
+ rule_name,
+ status,
+ error_code: None,
+ error_message: None,
+ score_value: None,
+ sigma_factor: None,
+ average_latency: None,
+ tp99_latency: None,
+ transaction_count: None,
+ route: Some(route.to_string()),
+ details,
+ created_at_ms: now_ms(),
+ });
+}
+
+pub fn record_score_snapshot_event(
+ merchant_id: Option,
+ payment_method_type: Option,
+ payment_method: Option,
+ card_network: Option,
+ card_is_in: Option,
+ currency: Option,
+ country: Option,
+ auth_type: Option,
+ gateway: Option,
+ score_value: Option,
+ sigma_factor: Option,
+ average_latency: Option,
+ tp99_latency: Option,
+ transaction_count: Option,
+ route: &str,
+ details: Option,
+ payment_id: Option,
+ request_id: Option,
+ event_stage: Option,
+) {
+ spawn_persist(NewAnalyticsEvent {
+ event_type: "score_snapshot".to_string(),
+ merchant_id,
+ payment_id,
+ request_id,
+ payment_method_type,
+ payment_method,
+ card_network,
+ card_is_in,
+ currency,
+ country,
+ auth_type,
+ gateway,
+ event_stage,
+ routing_approach: None,
+ rule_name: None,
+ status: Some("snapshot".to_string()),
+ error_code: None,
+ error_message: None,
+ score_value,
+ sigma_factor,
+ average_latency,
+ tp99_latency,
+ transaction_count,
+ route: Some(route.to_string()),
+ details,
+ created_at_ms: now_ms(),
+ });
+}
+
+pub fn record_gateway_update_event(
+ merchant_id: Option,
+ gateway: Option,
+ status: Option,
+ route: &str,
+ details: Option,
+ payment_id: Option,
+ request_id: Option,
+ event_stage: Option,
+) {
+ spawn_persist(NewAnalyticsEvent {
+ event_type: "gateway_update".to_string(),
+ merchant_id,
+ payment_id,
+ request_id,
+ payment_method_type: None,
+ payment_method: None,
+ card_network: None,
+ card_is_in: None,
+ currency: None,
+ country: None,
+ auth_type: None,
+ gateway,
+ event_stage,
+ routing_approach: None,
+ rule_name: None,
+ status,
+ error_code: None,
+ error_message: None,
+ score_value: None,
+ sigma_factor: None,
+ average_latency: None,
+ tp99_latency: None,
+ transaction_count: None,
+ route: Some(route.to_string()),
+ details,
+ created_at_ms: now_ms(),
+ });
+}
+
+pub fn record_rule_hit_event(
+ merchant_id: Option,
+ rule_name: String,
+ gateway: Option,
+ routing_approach: Option,
+ details: Option,
+ payment_id: Option,
+ request_id: Option,
+ event_stage: Option,
+) {
+ ROUTING_RULE_HIT_COUNTER
+ .with_label_values(&[rule_name.as_str()])
+ .inc();
+ spawn_persist(NewAnalyticsEvent {
+ event_type: "rule_hit".to_string(),
+ merchant_id,
+ payment_id,
+ request_id,
+ payment_method_type: None,
+ payment_method: None,
+ card_network: None,
+ card_is_in: None,
+ currency: None,
+ country: None,
+ auth_type: None,
+ gateway,
+ event_stage,
+ routing_approach,
+ rule_name: Some(rule_name),
+ status: Some("hit".to_string()),
+ error_code: None,
+ error_message: None,
+ score_value: None,
+ sigma_factor: None,
+ average_latency: None,
+ tp99_latency: None,
+ transaction_count: None,
+ route: Some("routing".to_string()),
+ details,
+ created_at_ms: now_ms(),
+ });
+}
+
+pub fn record_rule_evaluation_preview_event(
+ merchant_id: Option,
+ payment_id: Option,
+ gateway: Option,
+ rule_name: Option,
+ status: Option,
+ details: Option,
+) {
+ spawn_persist(NewAnalyticsEvent {
+ event_type: "rule_evaluation_preview".to_string(),
+ merchant_id,
+ payment_id,
+ request_id: None,
+ payment_method_type: None,
+ payment_method: None,
+ card_network: None,
+ card_is_in: None,
+ currency: None,
+ country: None,
+ auth_type: None,
+ gateway,
+ event_stage: Some("preview_evaluated".to_string()),
+ routing_approach: Some("RULE_EVALUATE_PREVIEW".to_string()),
+ rule_name,
+ status,
+ error_code: None,
+ error_message: None,
+ score_value: None,
+ sigma_factor: None,
+ average_latency: None,
+ tp99_latency: None,
+ transaction_count: None,
+ route: Some("routing_evaluate".to_string()),
+ details,
+ created_at_ms: now_ms(),
+ });
+}
+
+pub fn record_error_event(
+ route: &str,
+ merchant_id: Option,
+ payment_id: Option,
+ request_id: Option,
+ gateway: Option,
+ routing_approach: Option,
+ error_code: String,
+ error_message: String,
+ details: Option,
+ event_stage: Option,
+) {
+ spawn_persist(NewAnalyticsEvent {
+ event_type: "error".to_string(),
+ merchant_id,
+ payment_id,
+ request_id,
+ payment_method_type: None,
+ payment_method: None,
+ card_network: None,
+ card_is_in: None,
+ currency: None,
+ country: None,
+ auth_type: None,
+ gateway,
+ event_stage,
+ routing_approach,
+ rule_name: None,
+ status: Some("failure".to_string()),
+ error_code: Some(error_code),
+ error_message: Some(error_message),
+ score_value: None,
+ sigma_factor: None,
+ average_latency: None,
+ tp99_latency: None,
+ transaction_count: None,
+ route: Some(route.to_string()),
+ details,
+ created_at_ms: now_ms(),
+ });
+}
+
+pub fn record_request_hit_event(
+ route: &str,
+ merchant_id: Option,
+ payment_id: Option,
+ request_id: Option,
+) {
+ spawn_persist(NewAnalyticsEvent {
+ event_type: "request_hit".to_string(),
+ merchant_id,
+ payment_id,
+ request_id,
+ payment_method_type: None,
+ payment_method: None,
+ card_network: None,
+ card_is_in: None,
+ currency: None,
+ country: None,
+ auth_type: None,
+ gateway: None,
+ event_stage: Some("request_received".to_string()),
+ routing_approach: None,
+ rule_name: None,
+ status: Some("received".to_string()),
+ error_code: None,
+ error_message: None,
+ score_value: None,
+ sigma_factor: None,
+ average_latency: None,
+ tp99_latency: None,
+ transaction_count: None,
+ route: Some(route.to_string()),
+ details: None,
+ created_at_ms: now_ms(),
+ });
+}
+
+async fn persist_event(event: NewAnalyticsEvent) -> Result<(), error::ApiError> {
+ let state = crate::app::get_tenant_app_state().await;
+ let conn = &state
+ .db
+ .get_conn()
+ .await
+ .map_err(|_| error::ApiError::DatabaseError)?;
+
+ diesel::insert_into(analytics_dsl::analytics_event)
+ .values(event)
+ .execute_async(&**conn)
+ .await
+ .map_err(|_| error::ApiError::DatabaseError)?;
+
+ Ok(())
+}
+
+async fn load_events(
+ state: &crate::app::TenantAppState,
+ query: &AnalyticsQuery,
+ event_types: &[&str],
+) -> Result, error::ApiError> {
+ let conn = &state
+ .db
+ .get_conn()
+ .await
+ .map_err(|_| error::ApiError::DatabaseError)?;
+
+ let mut builder = analytics_dsl::analytics_event
+ .select(AnalyticsEvent::as_select())
+ .into_boxed();
+ let (start_ms, end_ms) = effective_window_bounds(query);
+ builder = builder
+ .filter(analytics_dsl::created_at_ms.ge(start_ms))
+ .filter(analytics_dsl::created_at_ms.le(end_ms));
+
+ if query.scope == AnalyticsScope::Current {
+ if let Some(merchant_id) = &query.merchant_id {
+ builder = builder.filter(analytics_dsl::merchant_id.eq(merchant_id.clone()));
+ }
+ }
+
+ let event_types: Vec = event_types
+ .iter()
+ .map(|event_type| (*event_type).to_string())
+ .collect();
+
+ if !event_types.is_empty() {
+ builder = builder.filter(analytics_dsl::event_type.eq_any(event_types));
+ }
+
+ builder
+ .order((analytics_dsl::created_at_ms.asc(), analytics_dsl::id.asc()))
+ .load_async::(&**conn)
+ .await
+ .map_err(|err| {
+ crate::logger::error!(
+ error = ?err,
+ merchant_id = ?query.merchant_id,
+ scope = query.scope.as_str(),
+ "Analytics read failed; returning empty analytics state"
+ );
+ err
+ })
+ .or_else(|_| Ok(Vec::new()))
+}
+
+async fn load_payment_audit_events(
+ state: &crate::app::TenantAppState,
+ query: &PaymentAuditQuery,
+) -> Result, error::ApiError> {
+ let conn = &state
+ .db
+ .get_conn()
+ .await
+ .map_err(|_| error::ApiError::DatabaseError)?;
+
+ let mut builder = analytics_dsl::analytics_event
+ .select(AnalyticsEvent::as_select())
+ .into_boxed();
+ let (start_ms, end_ms) = effective_payment_audit_window_bounds(query);
+ builder = builder
+ .filter(analytics_dsl::created_at_ms.ge(start_ms))
+ .filter(analytics_dsl::created_at_ms.le(end_ms));
+ builder = builder.filter(analytics_dsl::event_type.eq_any(vec![
+ "decision".to_string(),
+ "gateway_update".to_string(),
+ "rule_hit".to_string(),
+ "error".to_string(),
+ ]));
+
+ if query.scope == AnalyticsScope::Current {
+ if let Some(merchant_id) = &query.merchant_id {
+ builder = builder.filter(analytics_dsl::merchant_id.eq(merchant_id.clone()));
+ }
+ }
+
+ if let Some(payment_id) = &query.payment_id {
+ builder = builder.filter(analytics_dsl::payment_id.eq(payment_id.clone()));
+ }
+
+ if query.payment_id.is_none() {
+ if let Some(request_id) = &query.request_id {
+ builder = builder.filter(analytics_dsl::request_id.eq(request_id.clone()));
+ }
+ }
+
+ if let Some(gateway) = &query.gateway {
+ builder = builder.filter(analytics_dsl::gateway.eq(gateway.clone()));
+ }
+
+ if let Some(route) = &query.route {
+ builder = builder.filter(analytics_dsl::route.eq(route.clone()));
+ }
+
+ if let Some(status) = &query.status {
+ if status.eq_ignore_ascii_case("success") {
+ builder = builder.filter(
+ analytics_dsl::status
+ .eq("success".to_string())
+ .or(analytics_dsl::status
+ .eq("SUCCESS".to_string())
+ .or(analytics_dsl::status
+ .eq("CHARGED".to_string())
+ .or(analytics_dsl::status.eq("AUTHORIZED".to_string())))),
+ );
+ } else if status.eq_ignore_ascii_case("failure") || status.eq_ignore_ascii_case("FAILURE") {
+ builder = builder.filter(
+ analytics_dsl::status
+ .eq("FAILURE".to_string())
+ .or(analytics_dsl::status
+ .like("%FAILED%")
+ .or(analytics_dsl::status.like("%DECLINED%"))),
+ );
+ } else {
+ builder = builder.filter(analytics_dsl::status.eq(status.clone()));
+ }
+ }
+
+ if let Some(event_type) = &query.event_type {
+ builder = builder.filter(analytics_dsl::event_type.eq(event_type.clone()));
+ }
+
+ if let Some(error_code) = &query.error_code {
+ builder = builder.filter(analytics_dsl::error_code.eq(error_code.clone()));
+ }
+
+ builder
+ .order((
+ analytics_dsl::created_at_ms.desc(),
+ analytics_dsl::id.desc(),
+ ))
+ .load_async::(&**conn)
+ .await
+ .map_err(|err| {
+ crate::logger::error!(
+ error = ?err,
+ merchant_id = ?query.merchant_id,
+ payment_id = ?query.payment_id,
+ request_id = ?query.request_id,
+ "Payment audit read failed; returning empty audit state"
+ );
+ err
+ })
+ .or_else(|_| Ok(Vec::new()))
+}
+
+async fn load_preview_trace_events(
+ state: &crate::app::TenantAppState,
+ query: &PaymentAuditQuery,
+) -> Result, error::ApiError> {
+ let conn = &state
+ .db
+ .get_conn()
+ .await
+ .map_err(|_| error::ApiError::DatabaseError)?;
+
+ let mut builder = analytics_dsl::analytics_event
+ .select(AnalyticsEvent::as_select())
+ .into_boxed();
+ let (start_ms, end_ms) = effective_payment_audit_window_bounds(query);
+ builder = builder
+ .filter(analytics_dsl::created_at_ms.ge(start_ms))
+ .filter(analytics_dsl::created_at_ms.le(end_ms));
+ builder = builder.filter(analytics_dsl::route.eq("routing_evaluate".to_string()));
+ builder = builder.filter(analytics_dsl::event_type.eq_any(vec![
+ "rule_evaluation_preview".to_string(),
+ "error".to_string(),
+ ]));
+
+ if query.scope == AnalyticsScope::Current {
+ if let Some(merchant_id) = &query.merchant_id {
+ builder = builder.filter(analytics_dsl::merchant_id.eq(merchant_id.clone()));
+ }
+ }
+
+ if let Some(payment_id) = &query.payment_id {
+ builder = builder.filter(analytics_dsl::payment_id.eq(payment_id.clone()));
+ }
+
+ if query.payment_id.is_none() {
+ if let Some(request_id) = &query.request_id {
+ builder = builder.filter(analytics_dsl::request_id.eq(request_id.clone()));
+ }
+ }
+
+ if let Some(gateway) = &query.gateway {
+ builder = builder.filter(analytics_dsl::gateway.eq(gateway.clone()));
+ }
+
+ if let Some(status) = &query.status {
+ if status.eq_ignore_ascii_case("success") {
+ builder = builder.filter(
+ analytics_dsl::status
+ .eq("success".to_string())
+ .or(analytics_dsl::status.eq("default_selection".to_string())),
+ );
+ } else if status.eq_ignore_ascii_case("failure") || status.eq_ignore_ascii_case("FAILURE") {
+ builder = builder.filter(
+ analytics_dsl::status
+ .eq("FAILURE".to_string())
+ .or(analytics_dsl::status
+ .like("%FAILED%")
+ .or(analytics_dsl::status.like("%DECLINED%"))),
+ );
+ } else {
+ builder = builder.filter(analytics_dsl::status.eq(status.clone()));
+ }
+ }
+
+ if let Some(event_type) = &query.event_type {
+ builder = builder.filter(analytics_dsl::event_type.eq(event_type.clone()));
+ }
+
+ if let Some(error_code) = &query.error_code {
+ builder = builder.filter(analytics_dsl::error_code.eq(error_code.clone()));
+ }
+
+ builder
+ .order((
+ analytics_dsl::created_at_ms.desc(),
+ analytics_dsl::id.desc(),
+ ))
+ .load_async::(&**conn)
+ .await
+ .map_err(|err| {
+ crate::logger::error!(
+ error = ?err,
+ merchant_id = ?query.merchant_id,
+ payment_id = ?query.payment_id,
+ "Preview trace read failed; returning empty preview state"
+ );
+ err
+ })
+ .or_else(|_| Ok(Vec::new()))
+}
+
+fn parse_details_json(details: &Option) -> Option {
+ details
+ .as_ref()
+ .and_then(|value| serde_json::from_str::(value).ok())
+}
+
+fn transaction_status_from_details(event: &AnalyticsEvent) -> Option {
+ let details = parse_details_json(&event.details)?;
+ details
+ .get("request")
+ .and_then(|request| request.get("status"))
+ .and_then(|status| status.as_str())
+ .map(str::to_string)
+ .or_else(|| {
+ details
+ .get("selection_reason")
+ .and_then(|reason| reason.get("transaction_status"))
+ .and_then(|status| status.as_str())
+ .map(str::to_string)
+ })
+}
+
+fn effective_window_bounds(query: &AnalyticsQuery) -> (i64, i64) {
+ let now = now_ms();
+ let end_ms = query.end_ms.unwrap_or(now).min(now);
+ let start_ms = query
+ .start_ms
+ .filter(|start_ms| *start_ms >= 0 && *start_ms < end_ms)
+ .unwrap_or_else(|| end_ms.saturating_sub(query.range.window_ms()));
+
+ (start_ms, end_ms)
+}
+
+fn effective_payment_audit_window_bounds(query: &PaymentAuditQuery) -> (i64, i64) {
+ let now = now_ms();
+ let end_ms = query.end_ms.unwrap_or(now).min(now);
+ let start_ms = query
+ .start_ms
+ .filter(|start_ms| *start_ms >= 0 && *start_ms < end_ms)
+ .unwrap_or_else(|| end_ms.saturating_sub(query.range.window_ms()));
+
+ (start_ms, end_ms)
+}
+
+fn query_bucket_size_ms(query: &AnalyticsQuery) -> i64 {
+ let (start_ms, end_ms) = effective_window_bounds(query);
+ let window_ms = end_ms.saturating_sub(start_ms);
+
+ match window_ms {
+ 0..=900_000 => 60 * 1000,
+ 900_001..=3_600_000 => 5 * 60 * 1000,
+ 3_600_001..=86_400_000 => 15 * 60 * 1000,
+ 86_400_001..=259_200_000 => 60 * 60 * 1000,
+ _ => 3 * 60 * 60 * 1000,
+ }
+}
+
+fn bucket_ms(created_at_ms: i64, query: &AnalyticsQuery) -> i64 {
+ let bucket = query_bucket_size_ms(query).max(1);
+ created_at_ms - (created_at_ms.rem_euclid(bucket))
+}
+
+fn normalise_gateways(raw: Option) -> Vec {
+ raw.into_iter()
+ .flat_map(|value| value.split(',').map(str::to_owned).collect::>())
+ .map(|value| value.trim().to_string())
+ .filter(|value| !value.is_empty())
+ .collect()
+}
+
+fn normalise_payment_audit_route_filter(route: Option) -> Option {
+ route.and_then(|value| {
+ let trimmed = value.trim();
+ if trimmed.is_empty() {
+ return None;
+ }
+
+ Some(match trimmed {
+ "Decide Gateway" => "decide_gateway".to_string(),
+ "Update Gateway" => "update_gateway_score".to_string(),
+ "Rule Evaluate" => "routing_evaluate".to_string(),
+ other => other.to_string(),
+ })
+ })
+}
+
+fn normalise_payment_audit_status_filter(status: Option) -> Option {
+ status.and_then(|value| {
+ let trimmed = value.trim();
+ if trimmed.is_empty() {
+ return None;
+ }
+
+ Some(match trimmed.to_ascii_lowercase().as_str() {
+ "success" => "success".to_string(),
+ "failure" => "FAILURE".to_string(),
+ _ => trimmed.to_string(),
+ })
+ })
+}
+
+fn payment_audit_stage_label(event: &AnalyticsEvent) -> &'static str {
+ match event.event_type.as_str() {
+ "decision" => "Decide Gateway",
+ "gateway_update" => "Update Gateway",
+ "rule_hit" => "Rule Evaluate",
+ "rule_evaluation_preview" => "Preview Result",
+ "error" => "Errors",
+ _ => "Errors",
+ }
+}
+
+fn payment_audit_route_label(route: &str) -> String {
+ match route {
+ "decision_gateway" | "decide_gateway" => "Decide Gateway".to_string(),
+ "update_gateway_score" => "Update Gateway".to_string(),
+ "routing_evaluate" => "Rule Evaluate".to_string(),
+ other => other.to_string(),
+ }
+}
+
+fn payment_dimension_filters_enabled(query: &AnalyticsQuery) -> bool {
+ query.scope == AnalyticsScope::Current
+}
+
+struct RoutingDimensionSpec {
+ key: &'static str,
+ label: &'static str,
+}
+
+const ROUTING_DIMENSION_SPECS: [RoutingDimensionSpec; 7] = [
+ RoutingDimensionSpec {
+ key: "payment_method_type",
+ label: "Payment Method Type",
+ },
+ RoutingDimensionSpec {
+ key: "payment_method",
+ label: "Payment Method",
+ },
+ RoutingDimensionSpec {
+ key: "card_network",
+ label: "Card Network",
+ },
+ RoutingDimensionSpec {
+ key: "card_is_in",
+ label: "Card ISIN",
+ },
+ RoutingDimensionSpec {
+ key: "currency",
+ label: "Currency",
+ },
+ RoutingDimensionSpec {
+ key: "country",
+ label: "Country",
+ },
+ RoutingDimensionSpec {
+ key: "auth_type",
+ label: "Auth Type",
+ },
+];
+
+fn event_dimension_value<'a>(event: &'a AnalyticsEvent, key: &str) -> Option<&'a str> {
+ match key {
+ "payment_method_type" => event.payment_method_type.as_deref(),
+ "payment_method" => event.payment_method.as_deref(),
+ "card_network" => event.card_network.as_deref(),
+ "card_is_in" => event.card_is_in.as_deref(),
+ "currency" => event.currency.as_deref(),
+ "country" => event.country.as_deref(),
+ "auth_type" => event.auth_type.as_deref(),
+ _ => None,
+ }
+}
+
+fn query_dimension_value<'a>(query: &'a AnalyticsQuery, key: &str) -> Option<&'a str> {
+ match key {
+ "payment_method_type" => query.payment_method_type.as_deref(),
+ "payment_method" => query.payment_method.as_deref(),
+ "card_network" => query.card_network.as_deref(),
+ "card_is_in" => query.card_is_in.as_deref(),
+ "currency" => query.currency.as_deref(),
+ "country" => query.country.as_deref(),
+ "auth_type" => query.auth_type.as_deref(),
+ _ => None,
+ }
+}
+
+fn score_events_for_dimensions<'a>(events: &'a [AnalyticsEvent]) -> Vec<&'a AnalyticsEvent> {
+ events
+ .iter()
+ .filter(|event| event.event_type == "score_snapshot")
+ .collect()
+}
+
+fn active_routing_dimension_specs(
+ events: &[&AnalyticsEvent],
+) -> Vec<&'static RoutingDimensionSpec> {
+ ROUTING_DIMENSION_SPECS
+ .iter()
+ .filter(|spec| {
+ events.iter().any(|event| {
+ event_dimension_value(event, spec.key).is_some_and(|value| !value.is_empty())
+ })
+ })
+ .collect()
+}
+
+fn score_event_matches_dimension_filters(
+ event: &AnalyticsEvent,
+ query: &AnalyticsQuery,
+ ignored_key: Option<&str>,
+) -> bool {
+ if !payment_dimension_filters_enabled(query) {
+ return true;
+ }
+
+ for spec in ROUTING_DIMENSION_SPECS.iter() {
+ if ignored_key == Some(spec.key) {
+ continue;
+ }
+
+ let Some(selected_value) = query_dimension_value(query, spec.key) else {
+ continue;
+ };
+
+ if event_dimension_value(event, spec.key) != Some(selected_value) {
+ return false;
+ }
+ }
+
+ true
+}
+
+fn score_event_matches_filters(event: &AnalyticsEvent, query: &AnalyticsQuery) -> bool {
+ if !score_event_matches_dimension_filters(event, query, None) {
+ return false;
+ }
+
+ if !query.gateways.is_empty() {
+ let Some(gateway) = event.gateway.as_deref() else {
+ return false;
+ };
+ if !query.gateways.iter().any(|selected| selected == gateway) {
+ return false;
+ }
+ }
+
+ true
+}
+
+fn derive_routing_filter_options(
+ events: &[AnalyticsEvent],
+ query: &AnalyticsQuery,
+) -> RoutingFilterOptions {
+ let score_events = score_events_for_dimensions(events);
+ let active_dimensions = active_routing_dimension_specs(&score_events);
+ let missing_dimensions = ROUTING_DIMENSION_SPECS
+ .iter()
+ .filter(|spec| {
+ !active_dimensions
+ .iter()
+ .any(|active| active.key == spec.key)
+ })
+ .map(|spec| RoutingFilterDimensionHint {
+ key: spec.key.to_string(),
+ label: spec.label.to_string(),
+ })
+ .collect();
+
+ let dimensions = active_dimensions
+ .into_iter()
+ .map(|spec| {
+ let values = score_events
+ .iter()
+ .filter(|event| score_event_matches_dimension_filters(event, query, Some(spec.key)))
+ .filter_map(|event| event_dimension_value(event, spec.key).map(str::to_string))
+ .filter(|value| !value.is_empty())
+ .collect::>()
+ .into_iter()
+ .collect();
+
+ RoutingFilterDimension {
+ key: spec.key.to_string(),
+ label: spec.label.to_string(),
+ values,
+ }
+ })
+ .collect();
+
+ let gateways = score_events
+ .iter()
+ .filter(|event| score_event_matches_dimension_filters(event, query, None))
+ .filter_map(|event| event.gateway.clone())
+ .filter(|value| !value.is_empty())
+ .collect::>()
+ .into_iter()
+ .collect();
+
+ RoutingFilterOptions {
+ dimensions,
+ missing_dimensions,
+ gateways,
+ }
+}
+
+fn summarise_filtered_scores(
+ events: &[AnalyticsEvent],
+ query: &AnalyticsQuery,
+) -> Vec {
+ let mut by_bucket_gateway: BTreeMap<(i64, String), (f64, i64, String, String, String)> =
+ BTreeMap::new();
+
+ for event in events
+ .iter()
+ .filter(|event| event.event_type == "score_snapshot")
+ .filter(|event| score_event_matches_filters(event, query))
+ {
+ let gateway = event
+ .gateway
+ .clone()
+ .unwrap_or_else(|| "unknown".to_string());
+ let bucket = bucket_ms(event.created_at_ms, query);
+ let entry = by_bucket_gateway
+ .entry((bucket, gateway.clone()))
+ .or_insert((
+ 0.0,
+ 0,
+ event.merchant_id.clone().unwrap_or_default(),
+ event.payment_method_type.clone().unwrap_or_default(),
+ event.payment_method.clone().unwrap_or_default(),
+ ));
+ entry.0 += event.score_value.unwrap_or_default();
+ entry.1 += 1;
+ }
+
+ by_bucket_gateway
+ .into_iter()
+ .map(
+ |(
+ (bucket_ms, gateway),
+ (score_total, score_count, merchant_id, payment_method_type, payment_method),
+ )| {
+ GatewayScoreSeriesPoint {
+ bucket_ms,
+ merchant_id,
+ payment_method_type,
+ payment_method,
+ gateway,
+ score_value: if score_count > 0 {
+ score_total / score_count as f64
+ } else {
+ 0.0
+ },
+ }
+ },
+ )
+ .collect()
+}
+
+fn summarise_errors(events: &[AnalyticsEvent]) -> Vec {
+ let mut grouped: HashMap<(String, String, String), AnalyticsErrorSummary> = HashMap::new();
+
+ for event in events.iter().filter(|event| event.event_type == "error") {
+ let route = event.route.clone().unwrap_or_else(|| "unknown".to_string());
+ let error_code = event
+ .error_code
+ .clone()
+ .unwrap_or_else(|| "unknown".to_string());
+ let error_message = event
+ .error_message
+ .clone()
+ .unwrap_or_else(|| "unknown".to_string());
+ let key = (route.clone(), error_code.clone(), error_message.clone());
+ grouped
+ .entry(key)
+ .and_modify(|summary| {
+ summary.count += 1;
+ summary.last_seen_ms = summary.last_seen_ms.max(event.created_at_ms);
+ })
+ .or_insert_with(|| AnalyticsErrorSummary {
+ route,
+ error_code,
+ error_message,
+ count: 1,
+ last_seen_ms: event.created_at_ms,
+ });
+ }
+
+ let mut rows: Vec<_> = grouped.into_values().collect();
+ rows.sort_by(|left, right| {
+ right
+ .count
+ .cmp(&left.count)
+ .then_with(|| right.last_seen_ms.cmp(&left.last_seen_ms))
+ });
+ rows
+}
+
+fn summarise_rule_hits(events: &[AnalyticsEvent]) -> Vec {
+ let mut grouped: HashMap = HashMap::new();
+ for event in events.iter().filter(|event| event.event_type == "rule_hit") {
+ let rule_name = event
+ .rule_name
+ .clone()
+ .unwrap_or_else(|| "unknown".to_string());
+ *grouped.entry(rule_name).or_insert(0) += 1;
+ }
+
+ let mut rows: Vec<_> = grouped
+ .into_iter()
+ .map(|(rule_name, count)| AnalyticsRuleHit { rule_name, count })
+ .collect();
+ rows.sort_by(|left, right| {
+ right
+ .count
+ .cmp(&left.count)
+ .then_with(|| left.rule_name.cmp(&right.rule_name))
+ });
+ rows
+}
+
+fn summarise_scores(
+ events: &[AnalyticsEvent],
+) -> (Vec, Vec) {
+ let mut latest: HashMap<(String, String, String, String), AnalyticsEvent> = HashMap::new();
+ let mut series = Vec::new();
+
+ for event in events
+ .iter()
+ .filter(|event| event.event_type == "score_snapshot")
+ {
+ let merchant_id = event.merchant_id.clone().unwrap_or_default();
+ let payment_method_type = event.payment_method_type.clone().unwrap_or_default();
+ let payment_method = event.payment_method.clone().unwrap_or_default();
+ let gateway = event.gateway.clone().unwrap_or_default();
+ let key = (
+ merchant_id.clone(),
+ payment_method_type.clone(),
+ payment_method.clone(),
+ gateway.clone(),
+ );
+ series.push(GatewayScoreSeriesPoint {
+ bucket_ms: event.created_at_ms,
+ merchant_id: merchant_id.clone(),
+ payment_method_type: payment_method_type.clone(),
+ payment_method: payment_method.clone(),
+ gateway: gateway.clone(),
+ score_value: event.score_value.unwrap_or_default(),
+ });
+
+ latest
+ .entry(key)
+ .and_modify(|current| {
+ if event.created_at_ms >= current.created_at_ms {
+ *current = event.clone();
+ }
+ })
+ .or_insert_with(|| event.clone());
+ }
+
+ let mut snapshots: Vec = latest
+ .into_iter()
+ .map(
+ |((merchant_id, payment_method_type, payment_method, gateway), event)| {
+ GatewayScoreSnapshot {
+ merchant_id,
+ payment_method_type,
+ payment_method,
+ gateway,
+ score_value: event.score_value.unwrap_or_default(),
+ sigma_factor: event.sigma_factor.unwrap_or_default(),
+ average_latency: event.average_latency.unwrap_or_default(),
+ tp99_latency: event.tp99_latency.unwrap_or_default(),
+ transaction_count: event.transaction_count.unwrap_or_default(),
+ last_updated_ms: event.created_at_ms,
+ }
+ },
+ )
+ .collect();
+ snapshots.sort_by(|left, right| {
+ right
+ .score_value
+ .partial_cmp(&left.score_value)
+ .unwrap_or(std::cmp::Ordering::Equal)
+ .then_with(|| right.last_updated_ms.cmp(&left.last_updated_ms))
+ });
+
+ (snapshots, series)
+}
+
+fn summarise_decisions(
+ events: &[AnalyticsEvent],
+ query: &AnalyticsQuery,
+) -> (
+ Vec,
+ Vec,
+ Vec