diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cf05821..d766d7d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -48,9 +48,17 @@ jobs: - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 with: bun-version: 1.4.0 + # The Bridge workerd smoke uses Wrangler 4.137.0, which requires Node 22. + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: 22 - name: Install dependencies run: bun install --frozen-lockfile - name: Build run: bun run build - name: Consumer check run: bun run test:consumer + - name: Bridge packed Node and Worker consumers + run: bun run --filter @misofm/bridge test:consumer + - name: Bridge local workerd runtime + run: bun run --filter @misofm/bridge test:workerd diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index ca485d7..ad95a35 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -1,13 +1,12 @@ name: Publish to npm -# Publishes on a per-package version tag (effect-v0.1.0, musicos-v0.1.0, partyos-v0.1.0, -# platform-v0.25.0, streaming-v0.1.0, transcoding-v0.3.0, …), so a release is a deliberate act -# rather than a side effect of merging, and releasing one workspace package never -# implies another. Failed tag jobs -# can be re-run from Actions without permitting a branch to publish a package. +# Routes per-package version tags (effect-v0.1.0, bridge-v0.1.0, musicos-v0.1.0, +# partyos-v0.1.0, platform-v0.25.0, streaming-v0.1.0, transcoding-v0.3.0, …). +# Bridge tags run the validation and tarball checks but intentionally skip npm +# publication. Other package tags publish only their selected workspace. on: push: - tags: ["effect-v*", "musicos-v*", "partyos-v*", "platform-v*", "streaming-v*", "transcoding-v*"] + tags: ["effect-v*", "bridge-v*", "musicos-v*", "partyos-v*", "platform-v*", "streaming-v*", "transcoding-v*"] concurrency: group: publish-${{ github.ref }} @@ -57,6 +56,10 @@ jobs: DIR="packages/effect" VERSION="${TAG#effect-v}" ;; + bridge-v*) + DIR="packages/bridge" + VERSION="${TAG#bridge-v}" + ;; musicos-v*) DIR="packages/musicos" VERSION="${TAG#musicos-v}" @@ -78,7 +81,7 @@ jobs: VERSION="${TAG#transcoding-v}" ;; *) - echo "::error::Tag '$TAG' does not match effect-v*, musicos-v*, partyos-v*, platform-v*, streaming-v*, or transcoding-v*" + echo "::error::Tag '$TAG' does not match effect-v*, bridge-v*, musicos-v*, partyos-v*, platform-v*, streaming-v*, or transcoding-v*" exit 1 ;; esac @@ -142,5 +145,6 @@ jobs: # Trusted Publisher -> GitHub Actions, naming this repo and the workflow # file (publish.yml). - name: Publish + if: ${{ !startsWith(github.ref_name, 'bridge-v') }} working-directory: ${{ steps.pkg.outputs.dir }} run: npm publish --provenance --access public diff --git a/bun.lock b/bun.lock index a8ca58d..f07a785 100644 --- a/bun.lock +++ b/bun.lock @@ -11,6 +11,22 @@ "typescript": "^7.0.2", }, }, + "packages/bridge": { + "name": "@misofm/bridge", + "version": "0.1.0", + "devDependencies": { + "@effect/openapi-generator": "4.0.0-rc.112", + "@effect/platform-node": "4.0.0-rc.112", + "@types/bun": "^1.4.0", + "effect": "4.0.0-rc.112", + "typescript": "^7.0.2", + "wrangler": "4.137.0", + }, + "peerDependencies": { + "effect": "4.0.0-rc.112", + "typescript": "^5.7 || ^6 || ^7", + }, + }, "packages/effect": { "name": "@misofm/effect", "version": "0.2.0", @@ -144,12 +160,86 @@ "@babel/runtime": ["@babel/runtime@7.29.7", "", {}, "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw=="], + "@cloudflare/kv-asset-handler": ["@cloudflare/kv-asset-handler@0.5.0", "", {}, "sha512-jxQYkj8dSIzc0cD6cMMNdOc1UVjqSqu8BZdor5s8cGjW2I8BjODt/kWPVdY+u9zj3ms75Q5qaZgnxUad83+eAg=="], + + "@cloudflare/unenv-preset": ["@cloudflare/unenv-preset@2.16.2", "", { "peerDependencies": { "unenv": "2.0.0-rc.24", "workerd": ">1.20260305.0 <2.0.0-0" }, "optionalPeers": ["workerd"] }, "sha512-JBP1+Z7ZSNG/d4mRP+y8VC5dka3tZVMLEZRvS+rzQ4DGV1EoxRFQckcJTTkXbHSQiTj0DtNI01Zwb/V2fX0mvQ=="], + + "@cloudflare/workerd-darwin-64": ["@cloudflare/workerd-darwin-64@1.20260921.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-3iB2WnYOlZ29T+1zhCwbHFExCBp6E9bgmDUMryATYwrIGEQ1YbvR78m4ydm56XKN/d/yF3803ivMGfZMYDtiMg=="], + + "@cloudflare/workerd-darwin-arm64": ["@cloudflare/workerd-darwin-arm64@1.20260921.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-FpqVR7IQXVBmGtajyonEmhmb5UAsmV7dTaIkpemmHZXHEw7uYpkhkzKPjc4BOPhNQy8iwt2p+RZBPMY3Y7/bvQ=="], + + "@cloudflare/workerd-linux-64": ["@cloudflare/workerd-linux-64@1.20260921.1", "", { "os": "linux", "cpu": "x64" }, "sha512-riAJIohaVp5A8Sqy4yKlzHOaLPOICMf5oey+jC2rm45RVT+wK8+7UU0d31Dy/02Nc8YUkobAFwNVjX06P8WQ5g=="], + + "@cloudflare/workerd-linux-arm64": ["@cloudflare/workerd-linux-arm64@1.20260921.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-tnJu08tT7s0XWDqp3O0H/vCp0voy9OqVAzspb89biMo1dh8IiEpnyXnoPmdJ7H4qBnXCmXgy0kuEphuvpDPj9w=="], + + "@cloudflare/workerd-windows-64": ["@cloudflare/workerd-windows-64@1.20260921.1", "", { "os": "win32", "cpu": "x64" }, "sha512-VgNcRPstoZMb1G94JTrx+jU24GtkkazNfox0gnF/2fkuXpcfW/M0e0xvdMovYfwt8ZxG5AB2ZNvanD6ufBwiuQ=="], + + "@cspotcode/source-map-support": ["@cspotcode/source-map-support@0.8.1", "", { "dependencies": { "@jridgewell/trace-mapping": "0.3.9" } }, "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw=="], + "@effect/language-service": ["@effect/language-service@0.87.2", "", { "bin": { "effect-language-service": "cli.js" } }, "sha512-CfiSoaVQO8pZgaMZGw5VvMvRGybsJ2LaSDoLYaqiVGvo/YYPYVR2GzUKY0h1NtIweq/+SQ5XLrvtzPIttWQ0GQ=="], + "@effect/openapi-generator": ["@effect/openapi-generator@4.0.0-rc.112", "", { "dependencies": { "swagger2openapi": "^7.0.8" }, "peerDependencies": { "@effect/platform-node": "^4.0.0-rc.112", "effect": "^4.0.0-rc.112" }, "bin": { "openapigen": "./dist/bin.js" } }, "sha512-ZgAkEP2/8qPZKgnI5AqmBgqhrZsdMDKZXJoKn29xgElZUWCvHhdE6eSUfFtkQBRE5kQcATXOZajHl+S/Pg+8Dw=="], + "@effect/platform-node": ["@effect/platform-node@4.0.0-rc.112", "", { "dependencies": { "@effect/platform-node-shared": "^4.0.0-rc.112", "mime": "^4.1.0", "undici": "^8.10.0" }, "peerDependencies": { "effect": "^4.0.0-rc.112", "redis": ">=5.0.0 <7.0.0" } }, "sha512-/BMAcdNGQQskLmI0Zoa95KfTZkr9HV9N4NSxaSrusG6GeW6Ulp9KvZ+Rlaiw8lnOt43CXjFLdfll5/k5rxL4hQ=="], "@effect/platform-node-shared": ["@effect/platform-node-shared@4.0.0-rc.112", "", { "dependencies": { "@types/ws": "^8.18.1", "ws": "^8.21.3" }, "peerDependencies": { "effect": "^4.0.0-rc.112" } }, "sha512-ttjz0xKamFN7vL8pNDYVwddJLjZvqKePc05djlz2VcdaKbLsnYbtMnL1rbOfHgEnIUSHGh7FkjaN4DM1Ov81sQ=="], + "@emnapi/runtime": ["@emnapi/runtime@1.11.3", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA=="], + + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.28.1", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ=="], + + "@esbuild/android-arm": ["@esbuild/android-arm@0.28.1", "", { "os": "android", "cpu": "arm" }, "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ=="], + + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.28.1", "", { "os": "android", "cpu": "arm64" }, "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg=="], + + "@esbuild/android-x64": ["@esbuild/android-x64@0.28.1", "", { "os": "android", "cpu": "x64" }, "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng=="], + + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.28.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q=="], + + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.28.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ=="], + + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.28.1", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw=="], + + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.28.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ=="], + + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.28.1", "", { "os": "linux", "cpu": "arm" }, "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ=="], + + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.28.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g=="], + + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.28.1", "", { "os": "linux", "cpu": "ia32" }, "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w=="], + + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.28.1", "", { "os": "linux", "cpu": "none" }, "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg=="], + + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.28.1", "", { "os": "linux", "cpu": "none" }, "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ=="], + + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.28.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ=="], + + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.28.1", "", { "os": "linux", "cpu": "none" }, "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ=="], + + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.28.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag=="], + + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.28.1", "", { "os": "linux", "cpu": "x64" }, "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA=="], + + "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.28.1", "", { "os": "none", "cpu": "arm64" }, "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw=="], + + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.28.1", "", { "os": "none", "cpu": "x64" }, "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg=="], + + "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.28.1", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q=="], + + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.28.1", "", { "os": "openbsd", "cpu": "x64" }, "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw=="], + + "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.28.1", "", { "os": "none", "cpu": "arm64" }, "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg=="], + + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.28.1", "", { "os": "sunos", "cpu": "x64" }, "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ=="], + + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.28.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA=="], + + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.28.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg=="], + + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.28.1", "", { "os": "win32", "cpu": "x64" }, "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A=="], + + "@exodus/schemasafe": ["@exodus/schemasafe@1.3.0", "", {}, "sha512-5Aap/GaRupgNx/feGBwLLTVv8OQFfv3pq2lPRzPg9R+IOBnDgghTGW7l7EuVXOvg5cc/xSAlRW8rBrjIC3Nvqw=="], + "@gerrit0/mini-shiki": ["@gerrit0/mini-shiki@3.23.0", "", { "dependencies": { "@shikijs/engine-oniguruma": "^3.23.0", "@shikijs/langs": "^3.23.0", "@shikijs/themes": "^3.23.0", "@shikijs/types": "^3.23.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-bEMORlG0cqdjVyCEuU0cDQbORWX+kYCeo0kV1lbxF5bt4r7SID2l9bqsxJEM0zndaxpOUT7riCyIVEuqq/Ynxg=="], "@gql.tada/cli-utils": ["@gql.tada/cli-utils@1.9.3", "", { "dependencies": { "@0no-co/graphqlsp": "^1.17.3", "@gql.tada/internal": "1.2.2", "graphql": "^15.5.0 || ^16.0.0 || ^17.0.0" }, "peerDependencies": { "@gql.tada/svelte-support": "1.0.3", "@gql.tada/vue-support": "1.0.3", "typescript": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" }, "optionalPeers": ["@gql.tada/svelte-support", "@gql.tada/vue-support"] }, "sha512-P1TiXErpJwIi73sei5fzwGA/SOeCaIHFWFR4RdZPLwqxZzQN0T6MAUivzXBgKCORL67rvYnLaaPoWeqWq/61ug=="], @@ -158,6 +248,68 @@ "@graphql-typed-document-node/core": ["@graphql-typed-document-node/core@3.2.0", "", { "peerDependencies": { "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, "sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ=="], + "@img/colour": ["@img/colour@1.1.0", "", {}, "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ=="], + + "@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.35.4", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.3.3" }, "os": "darwin", "cpu": "arm64" }, "sha512-Uhfl4V4lhP2nbUVF9+hyH1+luj86f1gUFeo8ALYxFoULoU+G87D43BfeMP8XHsk9boxAnCY/bf2EHwhA7MuGsA=="], + + "@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.35.4", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.3.3" }, "os": "darwin", "cpu": "x64" }, "sha512-hWniXY3bG5qKpkKrAwPe4y+VTPmf086YQAnkxWh7uA1YrlRouWGa0M0Mxj3ZjnXFkv7/TD1bTy9lGUK26vRvWw=="], + + "@img/sharp-freebsd-wasm32": ["@img/sharp-freebsd-wasm32@0.35.4", "", { "dependencies": { "@img/sharp-wasm32": "0.35.4" }, "os": "freebsd" }, "sha512-lIsKw/BU+kjB4eZjxrYrZmwOJYi3Ajrv66iAlBmUPyKc3HpnloevB1g3wxGD9P/5BbQ1brBGl65VRRrCvQDEqA=="], + + "@img/sharp-libvips-darwin-arm64": ["@img/sharp-libvips-darwin-arm64@1.3.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-suTBPTDGrI9WodccaDdwZItTSaBYASlBk1NSfElSHrUfzu3szG6lvIF58+WiFvnfzuK8ZBFS5zE00PxqxnRiPg=="], + + "@img/sharp-libvips-darwin-x64": ["@img/sharp-libvips-darwin-x64@1.3.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-FVJZ5mITMobmXIz/hPDTw0EintTW5H3WfrxwLqEqjiIihlu+hVRyGrFQ60xl0Lxn7Bt3zdpevPaQi0HEzqz9fw=="], + + "@img/sharp-libvips-linux-arm": ["@img/sharp-libvips-linux-arm@1.3.3", "", { "os": "linux", "cpu": "arm" }, "sha512-3rbU4vqXXc3hY/OiXdl52xZvT0F1yEngWfvqudtPJg/KkyiaQw2DRsFrNzpmLvfavbwOq3qXn36GP8obHRULQA=="], + + "@img/sharp-libvips-linux-arm64": ["@img/sharp-libvips-linux-arm64@1.3.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-0DaL0A6Xu6sQSQFwe4iVCrKWU2cCTItnRsYsCdxAMm9NF6twAA9BKnoqy4hqz4+azQ0JHuA26qiUKsf1XJ/v5A=="], + + "@img/sharp-libvips-linux-ppc64": ["@img/sharp-libvips-linux-ppc64@1.3.3", "", { "os": "linux", "cpu": "ppc64" }, "sha512-cdn1OvUBwsXhbC0zSzJnNzf5MZ/mTrobawDvNXBTxe8VtqKAm0sRuEY2Evzovb/w9JMk4TvRxqt1mekSuJz64w=="], + + "@img/sharp-libvips-linux-riscv64": ["@img/sharp-libvips-linux-riscv64@1.3.3", "", { "os": "linux", "cpu": "none" }, "sha512-HjPVx7yKz+0lqdhDlTw1tt90wamBoxhiXpvl1XZpJLiHH4RCJ5yDTqH+VlYPv2fwFs89JFw4c1IexYOcQUi4IQ=="], + + "@img/sharp-libvips-linux-s390x": ["@img/sharp-libvips-linux-s390x@1.3.3", "", { "os": "linux", "cpu": "s390x" }, "sha512-neWLh+3yCNThxnfy3c4BbVBeGgt9aftno+XbT56iK28RgeDs3UOFWviLWlUu0bArYVYJaFDK+RRohbicUNCm8Q=="], + + "@img/sharp-libvips-linux-x64": ["@img/sharp-libvips-linux-x64@1.3.3", "", { "os": "linux", "cpu": "x64" }, "sha512-4vKmvAst9nrowcqquKFAyZJUDolUaIp8uRiN0mWFguJ1IplC9/pitXtlnnlU4aa/eJw3J7i67V+pwUL+wZGdsA=="], + + "@img/sharp-libvips-linuxmusl-arm64": ["@img/sharp-libvips-linuxmusl-arm64@1.3.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-Y9kQaLMuNoB0bPYOOdcZMaseNrFpPodIWWMrx+CZyydf2xn68j9WYc6sWWRrDwNkzCQjKYfc68L7jKjGlHMibw=="], + + "@img/sharp-libvips-linuxmusl-x64": ["@img/sharp-libvips-linuxmusl-x64@1.3.3", "", { "os": "linux", "cpu": "x64" }, "sha512-fj8Mv0HHfD1Rr+4I68+3agJynxDWtBFgicTbSOb9Bke6pIwzGcJ+RX/yHjmiEGFMCavY/dxvem7MyNaJF+wDiw=="], + + "@img/sharp-linux-arm": ["@img/sharp-linux-arm@0.35.4", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm": "1.3.3" }, "os": "linux", "cpu": "arm" }, "sha512-7OAS8gI0EReKGVN2HssHlM6umJgxF5VI3xN0p9FA91p/YO+ou5hiNghLdZ5BEHztwaaK5+bLKRf8x/o2L2nk9A=="], + + "@img/sharp-linux-arm64": ["@img/sharp-linux-arm64@0.35.4", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm64": "1.3.3" }, "os": "linux", "cpu": "arm64" }, "sha512-De4jpEnAU8Hd5oT0j1G3uL4ZvTuipVMn7YC6vPaJhy6/7EwEae0SVAoBrUMYQbkLGDm85taVWwuPc1a44LTzCQ=="], + + "@img/sharp-linux-ppc64": ["@img/sharp-linux-ppc64@0.35.4", "", { "optionalDependencies": { "@img/sharp-libvips-linux-ppc64": "1.3.3" }, "os": "linux", "cpu": "ppc64" }, "sha512-2oYZJeIl4kCcMGk4ouZVjnkCtFrpQFlNEtJ6GbxzhHQchwH0NH/qEb9ykmOl29dqwMq+JhFdZn+1ak2FKhI9fQ=="], + + "@img/sharp-linux-riscv64": ["@img/sharp-linux-riscv64@0.35.4", "", { "optionalDependencies": { "@img/sharp-libvips-linux-riscv64": "1.3.3" }, "os": "linux", "cpu": "none" }, "sha512-cPbNChoRURAWdebDIHSenxRpgEdy7JkPydSnUxRm9VvKD7m0/xVaR/8Fzlu81pk5nHEvHH87UZUA7cTtwnbJSA=="], + + "@img/sharp-linux-s390x": ["@img/sharp-linux-s390x@0.35.4", "", { "optionalDependencies": { "@img/sharp-libvips-linux-s390x": "1.3.3" }, "os": "linux", "cpu": "s390x" }, "sha512-RY0JFY8Fd6RonCBtHz+DvadaPkXDSI1AUn6yWL9TipqkZ1vY8w8evqdgyDFnkm4/K1ve1TvZiaePP5oSd4+WVQ=="], + + "@img/sharp-linux-x64": ["@img/sharp-linux-x64@0.35.4", "", { "optionalDependencies": { "@img/sharp-libvips-linux-x64": "1.3.3" }, "os": "linux", "cpu": "x64" }, "sha512-9qvvEAuk8k89TfWUoX2htWjbAMX8p+NxCppjpcg5k6xMsjhBQPTsoIh36h9Qde4WRuGpJeYnOjdosDn/cnv+OA=="], + + "@img/sharp-linuxmusl-arm64": ["@img/sharp-linuxmusl-arm64@0.35.4", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-arm64": "1.3.3" }, "os": "linux", "cpu": "arm64" }, "sha512-KB5jxpfWQTr0nc3xdHtWChdbifHrBGsd2SM62Eyxrl8afikm+f5qGBU75SJIZBT/S1MC8XyacdlXBMSWq6OURA=="], + + "@img/sharp-linuxmusl-x64": ["@img/sharp-linuxmusl-x64@0.35.4", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-x64": "1.3.3" }, "os": "linux", "cpu": "x64" }, "sha512-f+eZJZIQNEEd26RPSW+76chwOf1XtA2Y/O+5ocVyLliHkeih3e+jhLVBdNTd2rS3IbNXK8+ug93Vf5ZXtF5Lxg=="], + + "@img/sharp-wasm32": ["@img/sharp-wasm32@0.35.4", "", { "dependencies": { "@emnapi/runtime": "^1.11.3" } }, "sha512-zQnl4Kwp7Q6NHsENtU2T/00Zi+w3AQNwz3+UaTyVBy2FpXrzXzGjndpK61onhZjRtRpQXxCTeqw19bVyXOh7jA=="], + + "@img/sharp-webcontainers-wasm32": ["@img/sharp-webcontainers-wasm32@0.35.4", "", { "dependencies": { "@img/sharp-wasm32": "0.35.4" }, "cpu": "none" }, "sha512-ESfNkywmCfPNyaZjxooddJQiQ+l/nTpGEOGthxiLnIHXC/CmcBixnfwUleX9mCz9ovrUUvKMap/pm8RYbzfwaA=="], + + "@img/sharp-win32-arm64": ["@img/sharp-win32-arm64@0.35.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-iNdlBX9gLVvqe2I3uIJSIKTq6wckP/DYxZtcqxm09x5Gi24DnFBmPAWZmr60ZyYMG0xlzo6goG3670ar+RXvRw=="], + + "@img/sharp-win32-ia32": ["@img/sharp-win32-ia32@0.35.4", "", { "os": "win32", "cpu": "ia32" }, "sha512-kqRsbaa5CS6KHlpxnN7WhE6vAAugXyZButpRdvDWetlv6Qv4N9WTcrWzF7tXfB9T7MsoadqdI8hmwLq6UlLvtw=="], + + "@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.35.4", "", { "os": "win32", "cpu": "x64" }, "sha512-XtmnYhBcrORsJ4XJngyzr/EWP0hRZLAZRFaApdKuviyqF78+ylxh2y06ZmtULAMOnObJ3ucpN0AcwSWnMowTRg=="], + + "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], + + "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.6.0", "", {}, "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw=="], + + "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.9", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" } }, "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ=="], + + "@misofm/bridge": ["@misofm/bridge@workspace:packages/bridge"], + "@misofm/effect": ["@misofm/effect@workspace:packages/effect"], "@misofm/musicos": ["@misofm/musicos@workspace:packages/musicos"], @@ -196,6 +348,12 @@ "@noble/hashes": ["@noble/hashes@2.4.0", "", {}, "sha512-X5XaVWZIBCT7HHZGm5I7ZQXDwLG+bGXuSrMQAW+7Zvl87h1kmc1ZB1VSRJcpUfoUrGQp4Fkoxm5kZ+Ms+aW+eA=="], + "@poppinss/colors": ["@poppinss/colors@4.1.6", "", { "dependencies": { "kleur": "^4.1.5" } }, "sha512-H9xkIdFswbS8n1d6vmRd8+c10t2Qe+rZITbbDHHkQixH5+2x1FDGmi/0K+WgWiqQFKPSlIYB7jlH6Kpfn6Fleg=="], + + "@poppinss/dumper": ["@poppinss/dumper@0.6.5", "", { "dependencies": { "@poppinss/colors": "^4.1.5", "@sindresorhus/is": "^7.0.2", "supports-color": "^10.0.0" } }, "sha512-NBdYIb90J7LfOI32dOewKI1r7wnkiH6m920puQ3qHUeZkxNkQiFnXVWoE6YtFSv6QOiPPf7ys6i+HWWecDz7sw=="], + + "@poppinss/exception": ["@poppinss/exception@1.2.3", "", {}, "sha512-dCED+QRChTVatE9ibtoaxc+WkdzOSjYTKi/+uacHWIsfodVfpsueo3+DKpgU5Px8qXjgmXkSvhXvSCz3fnP9lw=="], + "@protobuf-ts/grpcweb-transport": ["@protobuf-ts/grpcweb-transport@2.11.1", "", { "dependencies": { "@protobuf-ts/runtime": "^2.11.1", "@protobuf-ts/runtime-rpc": "^2.11.1" } }, "sha512-1W4utDdvOB+RHMFQ0soL4JdnxjXV+ddeGIUg08DvZrA8Ms6k5NN6GBFU2oHZdTOcJVpPrDJ02RJlqtaoCMNBtw=="], "@protobuf-ts/runtime": ["@protobuf-ts/runtime@2.11.1", "", {}, "sha512-KuDaT1IfHkugM2pyz+FwiY80ejWrkH1pAtOBOZFuR6SXEFTsnb/jiQWQ1rCIrcKx2BtyxnxW6BWwsVSA/Ie+WQ=="], @@ -228,6 +386,10 @@ "@shikijs/vscode-textmate": ["@shikijs/vscode-textmate@10.0.2", "", {}, "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg=="], + "@sindresorhus/is": ["@sindresorhus/is@7.2.0", "", {}, "sha512-P1Cz1dWaFfR4IR+U13mqqiGsLFf1KbayybWwdd2vfctdV6hDpUkgCY0nKOLLTMSoRd/jJNjtbqzf13K8DCCXQw=="], + + "@speed-highlight/core": ["@speed-highlight/core@1.2.24", "", {}, "sha512-qeW2e1l78afw8VhRPfPQ1Gjj+KU5XFQ/OFV5ti6eTa9bruO7mJyZtA4vw0ofqmA3tKCkROE9xLk3VZoeRc98nw=="], + "@stricli/auto-complete": ["@stricli/auto-complete@1.3.0", "", { "dependencies": { "@stricli/core": "^1.3.0" }, "bin": { "auto-complete": "dist/bin/cli.js" } }, "sha512-egN+fdP2USbP08DkhSH+y9XsiXSrJMgbR1E5SuOD2kqI4AckufhOIKokDzmzmUT6yMa7j0jmWu29phT/jXwzqQ=="], "@stricli/core": ["@stricli/core@1.3.0", "", {}, "sha512-LnBe2HntygaLDU5trtjiC3J4C/YkmIZuM0XB52IF4qaLqJH09kgD1fnZiS2gaYUnt0nAN2a+1b4PSOBcfPrN4Q=="], @@ -290,16 +452,32 @@ "@videojs/vhs-utils": ["@videojs/vhs-utils@4.1.2", "", { "dependencies": { "@babel/runtime": "^7.12.5", "global": "^4.4.0" } }, "sha512-1Dsv5dtWOq0LP1G37O46FQFA2tKAZON5UMe6dFPxT7JvPhEx8QIXcFQxan8+hHI3fX6aomFRFrUBJNgRYQDSXA=="], + "ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], "balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], + "blake3-wasm": ["blake3-wasm@2.1.5", "", {}, "sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g=="], + "brace-expansion": ["brace-expansion@5.0.9", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg=="], "bun-types": ["bun-types@1.4.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-loKuVrAFZKfEv+JvWkHRS9GW5IqLuLRjVXN9p+vZvBN86O5hf/pBZQ5hSoyipsrMmWObZBDvWnlmKvjKTM0PdA=="], + "call-me-maybe": ["call-me-maybe@1.0.2", "", {}, "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ=="], + + "cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="], + "cluster-key-slot": ["cluster-key-slot@1.1.2", "", {}, "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA=="], + "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], + + "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], + + "cookie": ["cookie@1.1.1", "", {}, "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ=="], + "cosmiconfig": ["cosmiconfig@10.0.1", "", { "dependencies": { "env-paths": "^2.2.1", "js-yaml": "^5.4.1" } }, "sha512-/zvGoYn0y27QTBmK+0B+oPdEPC4fKGUmJsMTQbDjqph00TrkqfVFW/M+C6ya54sYCgHC6QCwK/mI6djt8cEGHQ=="], "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], @@ -310,13 +488,27 @@ "effect": ["effect@4.0.0-rc.112", "", { "dependencies": { "fast-check": "^4.9.0", "msgpackr": "^2.0.5" } }, "sha512-wXxwuh1Ywnv4cPRM3Wfa0vDwuOHnZ1TsTgHJkG9XgzND6inhBH9n1vBxhg3iIXOia/OrpmvVmd3lrD4vq6bF3A=="], + "emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + "entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="], "env-paths": ["env-paths@2.2.1", "", {}, "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A=="], + "error-stack-parser-es": ["error-stack-parser-es@1.0.5", "", {}, "sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA=="], + + "es6-promise": ["es6-promise@3.3.1", "", {}, "sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg=="], + + "esbuild": ["esbuild@0.28.1", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.28.1", "@esbuild/android-arm": "0.28.1", "@esbuild/android-arm64": "0.28.1", "@esbuild/android-x64": "0.28.1", "@esbuild/darwin-arm64": "0.28.1", "@esbuild/darwin-x64": "0.28.1", "@esbuild/freebsd-arm64": "0.28.1", "@esbuild/freebsd-x64": "0.28.1", "@esbuild/linux-arm": "0.28.1", "@esbuild/linux-arm64": "0.28.1", "@esbuild/linux-ia32": "0.28.1", "@esbuild/linux-loong64": "0.28.1", "@esbuild/linux-mips64el": "0.28.1", "@esbuild/linux-ppc64": "0.28.1", "@esbuild/linux-riscv64": "0.28.1", "@esbuild/linux-s390x": "0.28.1", "@esbuild/linux-x64": "0.28.1", "@esbuild/netbsd-arm64": "0.28.1", "@esbuild/netbsd-x64": "0.28.1", "@esbuild/openbsd-arm64": "0.28.1", "@esbuild/openbsd-x64": "0.28.1", "@esbuild/openharmony-arm64": "0.28.1", "@esbuild/sunos-x64": "0.28.1", "@esbuild/win32-arm64": "0.28.1", "@esbuild/win32-ia32": "0.28.1", "@esbuild/win32-x64": "0.28.1" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw=="], + + "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], + "fast-check": ["fast-check@4.9.0", "", { "dependencies": { "pure-rand": "^8.0.0" } }, "sha512-7ms6T7SybUev/PQITciI0yLM2pOSFy5zpG8Ty7tQofcVaQUvrMXp6CBwqF6fThLCLOrfBtuHAtwq6Yu4XPCllg=="], - "fsevents": ["fsevents@2.3.2", "", { "os": "darwin" }, "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA=="], + "fast-safe-stringify": ["fast-safe-stringify@2.1.1", "", {}, "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA=="], + + "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], + + "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], "global": ["global@4.4.0", "", { "dependencies": { "min-document": "^2.19.0", "process": "^0.11.10" } }, "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w=="], @@ -326,8 +518,14 @@ "hls.js": ["hls.js@1.6.13", "", {}, "sha512-hNEzjZNHf5bFrUNvdS4/1RjIanuJ6szpWNfTaX5I6WfGynWXGT7K/YQLYtemSvFExzeMdgdE4SsyVLJbd5PcZA=="], + "http2-client": ["http2-client@1.3.5", "", {}, "sha512-EC2utToWl4RKfs5zd36Mxq7nzHHBuomZboI0yYL6Y0RmBgT7Sgkq4rQ0ezFTYoIsSs7Tm9SJe+o2FcAg6GBhGA=="], + + "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], + "js-yaml": ["js-yaml@5.4.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.mjs" } }, "sha512-28R/k+NAjeuf7+CKlTxWZVExJGwVVLwY06DgEnOMz2gEpfNkDcD7QvyiVPT0xy0XXhU8vHsd4Ot42OOPdJG7dQ=="], + "kleur": ["kleur@4.1.5", "", {}, "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="], + "linkify-it": ["linkify-it@5.0.2", "", { "dependencies": { "uc.micro": "^2.0.0" } }, "sha512-ONTm2jCMAVZjgQa/Fy1kScXsuOoF5NPTsoFBdE1KVIZ2vAh/r9+Bqo+0jINCBYnavTPQZz38QzFTme79ENoN3Q=="], "lunr": ["lunr@2.3.9", "", {}, "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow=="], @@ -342,14 +540,36 @@ "min-document": ["min-document@2.19.2", "", { "dependencies": { "dom-walk": "^0.1.0" } }, "sha512-8S5I8db/uZN8r9HSLFVWPdJCvYOejMcEC82VIzNUc6Zkklf/d1gg2psfE79/vyhWOj4+J8MtwmoOz3TmvaGu5A=="], + "miniflare": ["miniflare@5.20260921.0-alpha", "", { "dependencies": { "@cspotcode/source-map-support": "0.8.1", "sharp": "0.35.4", "undici": "7.29.0", "workerd": "1.20260921.1", "ws": "8.21.0", "youch": "4.1.0-beta.10" } }, "sha512-vHH/unOYvV2jA1Q9SdkmzrQhhMoksdwg5jegu6ZeKaaRzgxZhVbt1NdTpQjHF2VTgiBjgP8SiUlUMfruB3N3SQ=="], + "minimatch": ["minimatch@10.2.6", "", { "dependencies": { "brace-expansion": "^5.0.8" } }, "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A=="], "msgpackr": ["msgpackr@2.1.0", "", { "optionalDependencies": { "msgpackr-extract": "^3.0.4" } }, "sha512-p/pBCVO63CsvvpkomUnNNag6+n38rULuDA6HHe70o2gtC8ODI52foF/4ko2qQcp6OiErJXTmrZeXmsGGHsIQNQ=="], "msgpackr-extract": ["msgpackr-extract@3.0.4", "", { "dependencies": { "node-gyp-build-optional-packages": "5.2.2" }, "optionalDependencies": { "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.4", "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.4", "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.4", "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.4", "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.4", "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.4" }, "bin": { "download-msgpackr-prebuilds": "bin/download-prebuilds.js" } }, "sha512-4kmO/MdyUIkLIvTPr8VHLil4AtoKIoniWPIEk5+CDy0xnWC84azhSFmuJ7PxZdsYtiP5kEeQsORAVIeMgxT+Hw=="], + "node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="], + + "node-fetch-h2": ["node-fetch-h2@2.3.0", "", { "dependencies": { "http2-client": "^1.2.5" } }, "sha512-ofRW94Ab0T4AOh5Fk8t0h8OBWrmjb0SSB20xh1H8YnPV9EJ+f5AMoYSUQ2zgJ4Iq2HAK0I2l5/Nequ8YzFS3Hg=="], + "node-gyp-build-optional-packages": ["node-gyp-build-optional-packages@5.2.2", "", { "dependencies": { "detect-libc": "^2.0.1" }, "bin": { "node-gyp-build-optional-packages": "bin.js", "node-gyp-build-optional-packages-optional": "optional.js", "node-gyp-build-optional-packages-test": "build-test.js" } }, "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw=="], + "node-readfiles": ["node-readfiles@0.2.0", "", { "dependencies": { "es6-promise": "^3.2.1" } }, "sha512-SU00ZarexNlE4Rjdm83vglt5Y9yiQ+XI1XpflWlb7q7UTN1JUItm69xMeiQCTxtTfnzt+83T8Cx+vI2ED++VDA=="], + + "oas-kit-common": ["oas-kit-common@1.0.8", "", { "dependencies": { "fast-safe-stringify": "^2.0.7" } }, "sha512-pJTS2+T0oGIwgjGpw7sIRU8RQMcUoKCDWFLdBqKB2BNmGpbBMH2sdqAaOXUg8OzonZHU0L7vfJu1mJFEiYDWOQ=="], + + "oas-linter": ["oas-linter@3.2.2", "", { "dependencies": { "@exodus/schemasafe": "^1.0.0-rc.2", "should": "^13.2.1", "yaml": "^1.10.0" } }, "sha512-KEGjPDVoU5K6swgo9hJVA/qYGlwfbFx+Kg2QB/kd7rzV5N8N5Mg6PlsoCMohVnQmo+pzJap/F610qTodKzecGQ=="], + + "oas-resolver": ["oas-resolver@2.5.6", "", { "dependencies": { "node-fetch-h2": "^2.3.0", "oas-kit-common": "^1.0.8", "reftools": "^1.1.9", "yaml": "^1.10.0", "yargs": "^17.0.1" }, "bin": { "resolve": "resolve.js" } }, "sha512-Yx5PWQNZomfEhPPOphFbZKi9W93CocQj18NlD2Pa4GWZzdZpSJvYwoiuurRI7m3SpcChrnO08hkuQDL3FGsVFQ=="], + + "oas-schema-walker": ["oas-schema-walker@1.1.5", "", {}, "sha512-2yucenq1a9YPmeNExoUa9Qwrt9RFkjqaMAA1X+U7sbb0AqBeTIdMHky9SQQ6iN94bO5NW0W4TRYXerG+BdAvAQ=="], + + "oas-validator": ["oas-validator@5.0.8", "", { "dependencies": { "call-me-maybe": "^1.0.1", "oas-kit-common": "^1.0.8", "oas-linter": "^3.2.2", "oas-resolver": "^2.5.6", "oas-schema-walker": "^1.1.5", "reftools": "^1.1.9", "should": "^13.2.1", "yaml": "^1.10.0" } }, "sha512-cu20/HE5N5HKqVygs3dt94eYJfBi0TsZvPVXDhbXQHiEityDN+RROTleefoKRKKJ9dFAF2JBkDHgvWj0sjKGmw=="], + + "path-to-regexp": ["path-to-regexp@6.3.0", "", {}, "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ=="], + + "pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], + "playwright": ["playwright@1.55.0", "", { "dependencies": { "playwright-core": "1.55.0" }, "optionalDependencies": { "fsevents": "2.3.2" }, "bin": { "playwright": "cli.js" } }, "sha512-sdCWStblvV1YU909Xqx0DhOjPZE4/5lJsIS84IfN9dAZfcl/CIZ5O8l3o0j7hPMjDvqoTF8ZUcc+i/GL5erstA=="], "playwright-core": ["playwright-core@1.55.0", "", { "bin": { "playwright-core": "cli.js" } }, "sha512-GvZs4vU3U5ro2nZpeiwyb0zuFaqb9sUiAJuyrWpcGouD8y9/HLgGbNRjIph7zU9D3hnPaisMl9zG9CgFi/biIg=="], @@ -366,8 +586,40 @@ "redis": ["redis@6.2.1", "", { "dependencies": { "@redis/bloom": "6.2.1", "@redis/client": "6.2.1", "@redis/json": "6.2.1", "@redis/search": "6.2.1", "@redis/time-series": "6.2.1" } }, "sha512-Z9VHtgYs48PiQC77X9O2Er8Hj4T+5BtFjT91/vi5Is1D04N72cA946ZslM1ImJw8ZctFBZWAVjM7S5wJNeHMpg=="], + "reftools": ["reftools@1.1.9", "", {}, "sha512-OVede/NQE13xBQ+ob5CKd5KyeJYU2YInb1bmV4nRoOfquZPkAkxuOXicSe1PvqIuZZ4kD13sPKBbR7UFDmli6w=="], + + "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="], + + "semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="], + + "sharp": ["sharp@0.35.4", "", { "dependencies": { "@img/colour": "^1.1.0", "detect-libc": "^2.1.2", "semver": "^7.8.5" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.35.4", "@img/sharp-darwin-x64": "0.35.4", "@img/sharp-freebsd-wasm32": "0.35.4", "@img/sharp-libvips-darwin-arm64": "1.3.3", "@img/sharp-libvips-darwin-x64": "1.3.3", "@img/sharp-libvips-linux-arm": "1.3.3", "@img/sharp-libvips-linux-arm64": "1.3.3", "@img/sharp-libvips-linux-ppc64": "1.3.3", "@img/sharp-libvips-linux-riscv64": "1.3.3", "@img/sharp-libvips-linux-s390x": "1.3.3", "@img/sharp-libvips-linux-x64": "1.3.3", "@img/sharp-libvips-linuxmusl-arm64": "1.3.3", "@img/sharp-libvips-linuxmusl-x64": "1.3.3", "@img/sharp-linux-arm": "0.35.4", "@img/sharp-linux-arm64": "0.35.4", "@img/sharp-linux-ppc64": "0.35.4", "@img/sharp-linux-riscv64": "0.35.4", "@img/sharp-linux-s390x": "0.35.4", "@img/sharp-linux-x64": "0.35.4", "@img/sharp-linuxmusl-arm64": "0.35.4", "@img/sharp-linuxmusl-x64": "0.35.4", "@img/sharp-webcontainers-wasm32": "0.35.4", "@img/sharp-win32-arm64": "0.35.4", "@img/sharp-win32-ia32": "0.35.4", "@img/sharp-win32-x64": "0.35.4" }, "peerDependencies": { "@types/node": "*" }, "optionalPeers": ["@types/node"] }, "sha512-n++8XWcj+jCOr2IOl7h8LbKnGBDY4aPbmprMONBNFdn0ImXqpGVv5zliDs0V9HbmbCQLpbuo2ej9rAoOQTvMDA=="], + + "should": ["should@13.2.3", "", { "dependencies": { "should-equal": "^2.0.0", "should-format": "^3.0.3", "should-type": "^1.4.0", "should-type-adaptors": "^1.0.1", "should-util": "^1.0.0" } }, "sha512-ggLesLtu2xp+ZxI+ysJTmNjh2U0TsC+rQ/pfED9bUZZ4DKefP27D+7YJVVTvKsmjLpIi9jAa7itwDGkDDmt1GQ=="], + + "should-equal": ["should-equal@2.0.0", "", { "dependencies": { "should-type": "^1.4.0" } }, "sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA=="], + + "should-format": ["should-format@3.0.3", "", { "dependencies": { "should-type": "^1.3.0", "should-type-adaptors": "^1.0.1" } }, "sha512-hZ58adtulAk0gKtua7QxevgUaXTTXxIi8t41L3zo9AHvjXO1/7sdLECuHeIN2SRtYXpNkmhoUP2pdeWgricQ+Q=="], + + "should-type": ["should-type@1.4.0", "", {}, "sha512-MdAsTu3n25yDbIe1NeN69G4n6mUnJGtSJHygX3+oN0ZbO3DTiATnf7XnYJdGT42JCXurTb1JI0qOBR65shvhPQ=="], + + "should-type-adaptors": ["should-type-adaptors@1.1.0", "", { "dependencies": { "should-type": "^1.3.0", "should-util": "^1.0.0" } }, "sha512-JA4hdoLnN+kebEp2Vs8eBe9g7uy0zbRo+RMcU0EsNy+R+k049Ki+N5tT5Jagst2g7EAja+euFuoXFCa8vIklfA=="], + + "should-util": ["should-util@1.0.1", "", {}, "sha512-oXF8tfxx5cDk8r2kYqlkUJzZpDBqVY/II2WhvU0n9Y3XYvAYRmeaf1PvvIvTgPnv4KJ+ES5M0PyDq5Jp+Ygy2g=="], + + "string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "supports-color": ["supports-color@10.2.2", "", {}, "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g=="], + + "swagger2openapi": ["swagger2openapi@7.0.8", "", { "dependencies": { "call-me-maybe": "^1.0.1", "node-fetch": "^2.6.1", "node-fetch-h2": "^2.3.0", "node-readfiles": "^0.2.0", "oas-kit-common": "^1.0.8", "oas-resolver": "^2.5.6", "oas-schema-walker": "^1.1.5", "oas-validator": "^5.0.8", "reftools": "^1.1.9", "yaml": "^1.10.0", "yargs": "^17.0.1" }, "bin": { "swagger2openapi": "swagger2openapi.js", "oas-validate": "oas-validate.js", "boast": "boast.js" } }, "sha512-upi/0ZGkYgEcLeGieoz8gT74oWHA0E7JivX7aN9mAf+Tc7BQoRBvnIGHoPDw+f9TXTW4s6kGYCZJtauP6OYp7g=="], + "toml": ["toml@5.0.0", "", {}, "sha512-bsqEd+g7fzlrw7LEynQ6W6aOK/lTOlepz5x1sJyIV9fTZVJS2Q76nuju6FK+gZhW5bUpvB7mCEqdR0u4WziMFw=="], + "tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="], + + "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + "typedoc": ["typedoc@0.28.20", "", { "dependencies": { "@gerrit0/mini-shiki": "^3.23.0", "lunr": "^2.3.9", "markdown-it": "^14.3.0", "minimatch": "^10.2.5", "yaml": "^2.9.0" }, "peerDependencies": { "typescript": "5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x || 5.8.x || 5.9.x || 6.0.x" }, "bin": { "typedoc": "bin/typedoc" } }, "sha512-uSKqkh8Cr48vllnEy+jdaAgOeR6Y+QCBW7usgUsKj7gJEfR7stw9U/fE49LBnj2tPRKPY0c0EBJSWe9Appmplg=="], "typedoc-plugin-markdown": ["typedoc-plugin-markdown@4.13.0", "", { "peerDependencies": { "typedoc": "0.28.x" } }, "sha512-OHaOLoMTS0wL2ud73WXvxv486mrUEtgXxW4iKiTOGJVipT/VBWY76rlVRMQGes7aVonoIf5roWRe1UvHbufLlQ=="], @@ -380,12 +632,34 @@ "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], + "unenv": ["unenv@2.0.0-rc.24", "", { "dependencies": { "pathe": "^2.0.3" } }, "sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw=="], + "valibot": ["valibot@1.4.2", "", { "peerDependencies": { "typescript": ">=5" }, "optionalPeers": ["typescript"] }, "sha512-gjdCvJ6d3RyHAneqxMYMW9QMCwYMb3jpOO0IyHZV1bnRHFBHrX3VkIILt5XYR0WhwHiH7Mty8ovuPZ/O3gamrg=="], + "webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="], + + "whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="], + + "workerd": ["workerd@1.20260921.1", "", { "optionalDependencies": { "@cloudflare/workerd-darwin-64": "1.20260921.1", "@cloudflare/workerd-darwin-arm64": "1.20260921.1", "@cloudflare/workerd-linux-64": "1.20260921.1", "@cloudflare/workerd-linux-arm64": "1.20260921.1", "@cloudflare/workerd-windows-64": "1.20260921.1" }, "bin": { "workerd": "bin/workerd" } }, "sha512-4HyG7G1W4ksa6tUZ8bV2jxDRWuL5PXnHm9+Z1sjFPb9OZNoYtXz4y7QQRh4ibi0BF/lOmlAVjbhkUqsAVZuUKA=="], + + "wrangler": ["wrangler@4.137.0", "", { "dependencies": { "@cloudflare/kv-asset-handler": "0.5.0", "@cloudflare/unenv-preset": "2.16.2", "blake3-wasm": "2.1.5", "esbuild": "0.28.1", "miniflare": "5.20260921.0-alpha", "path-to-regexp": "6.3.0", "unenv": "2.0.0-rc.24", "workerd": "1.20260921.1" }, "optionalDependencies": { "fsevents": "2.3.3" }, "peerDependencies": { "@cloudflare/workers-types": "^5.20260921.1" }, "optionalPeers": ["@cloudflare/workers-types"], "bin": { "wrangler": "bin/wrangler.js", "wrangler2": "bin/wrangler.js", "cf-wrangler": "bin/cf-wrangler.js" } }, "sha512-vq2JmxkvwOjnsMUejQwd89/EK6u1d20OMlGUVVmb55gVi2zSBKp2rvmxUiPqrSEntK8NwzpTF3DQ/S2I9/TLsg=="], + + "wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + "ws": ["ws@8.21.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw=="], + "y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="], + "yaml": ["yaml@2.9.0", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA=="], + "yargs": ["yargs@17.7.3", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g=="], + + "yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="], + + "youch": ["youch@4.1.0-beta.10", "", { "dependencies": { "@poppinss/colors": "^4.1.5", "@poppinss/dumper": "^0.6.4", "@speed-highlight/core": "^1.2.7", "cookie": "^1.0.2", "youch-core": "^0.3.3" } }, "sha512-rLfVLB4FgQneDr0dv1oddCVZmKjcJ6yX6mS4pU82Mq/Dt9a3cLZQ62pDBL4AUO+uVrCvtWz3ZFUL2HFAFJ/BXQ=="], + + "youch-core": ["youch-core@0.3.3", "", { "dependencies": { "@poppinss/exception": "^1.2.2", "error-stack-parser-es": "^1.0.5" } }, "sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA=="], + "zod": ["zod@4.5.4", "", {}, "sha512-sC95tT5iHHH9gtpj6A81kh+NEaRAUFN+qlUPDUbRfOMvNf5QCBqsb3WgvnpVtK5Y+4UfA6KqufotuTvMGiTlsA=="], "@misofm/transcoding/@types/bun": ["@types/bun@1.2.22", "", { "dependencies": { "bun-types": "1.2.22" } }, "sha512-5A/KrKos2ZcN0c6ljRSOa1fYIyCKhZfIVYeuyb4snnvomnpFqC0tTsEkdqNxbAgExV384OETQ//WAjl3XbYqQA=="], @@ -402,6 +676,20 @@ "bun-types/@types/node": ["@types/node@26.4.1", "", { "dependencies": { "undici-types": "~8.3.0" } }, "sha512-k97ENvZWtvA6yqz5/FS6a7duDgOPEeOQOc2iKS/nY6mX6qJUKtLnWzQS+Xj6tXweyj6ZcTAK2Qecetnvi9nCLA=="], + "miniflare/undici": ["undici@7.29.0", "", {}, "sha512-IDxfleLmmbSskfWSUATiN1nfn2rDuvnMOqb5CWR92iIfojA0Ud+ulOAAEQ57LPr9rWmsreUyf5lwyao+7GNNVw=="], + + "miniflare/ws": ["ws@8.21.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g=="], + + "oas-linter/yaml": ["yaml@1.10.3", "", {}, "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA=="], + + "oas-resolver/yaml": ["yaml@1.10.3", "", {}, "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA=="], + + "oas-validator/yaml": ["yaml@1.10.3", "", {}, "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA=="], + + "playwright/fsevents": ["fsevents@2.3.2", "", { "os": "darwin" }, "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA=="], + + "swagger2openapi/yaml": ["yaml@1.10.3", "", {}, "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA=="], + "@misofm/transcoding/@types/bun/bun-types": ["bun-types@1.2.22", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-hwaAu8tct/Zn6Zft4U9BsZcXkYomzpHJX28ofvx7k0Zz2HNz54n1n+tDgxoWFGB4PcFvJXJQloPhaV2eP3Q6EA=="], "@mysten/codegen/@types/node/undici-types": ["undici-types@8.3.0", "", {}, "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ=="], diff --git a/package.json b/package.json index 7ac6a9e..bee00cb 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "scripts": { "typecheck": "bun run --filter '*' typecheck", "test": "bun run --filter '*' test", - "build": "bun run --filter @misofm/streaming build && bun run --filter @misofm/effect build && bun run --filter @misofm/musicos build && bun run --filter @misofm/partyos build && bun run --filter @misofm/platform build && bun run --filter @misofm/transcoding build", + "build": "bun run --filter @misofm/streaming build && bun run --filter @misofm/effect build && bun run --filter @misofm/bridge build && bun run --filter @misofm/musicos build && bun run --filter @misofm/partyos build && bun run --filter @misofm/platform build && bun run --filter @misofm/transcoding build", "codegen": "bun scripts/codegen.ts", "codegen:check": "bun run codegen && git diff --exit-code -- packages/musicos/src/contracts packages/partyos/src/contracts packages/platform/src/contracts", "test:consumer": "bun scripts/check-consumer.ts" diff --git a/packages/bridge/AGENTS.md b/packages/bridge/AGENTS.md new file mode 100644 index 0000000..c4cc373 --- /dev/null +++ b/packages/bridge/AGENTS.md @@ -0,0 +1,23 @@ +# Bridge package contract + +- `openapi/bridge-2026-09-23.json` is the byte-pinned official Bridge OpenAPI + source. Its provenance and SHA-256 are recorded in `openapi/README.md`. +- `openapi/operation-manifest.json` is the stable mapping from upstream + `method + path` pairs to operation IDs and public group keys. Review contract + renames explicitly; do not regenerate this manifest as part of normal codegen. +- `openapi/normalization-overlay.json` contains the small, reasoned set of + upstream corrections applied before generation. Keep its rationale current. +- `src/generated/BridgeApi.ts` is generated only by + `bun run generate` / `bun run generate:check`. Never edit generated code. +- `bun run generate:check` reads only committed files and must be byte-for-byte + clean. It verifies the source hash, 134-operation manifest, warning baseline, + and generated output. +- The generated API uses Effect v4 `HttpApi` groups and endpoints. Runtime + client/service construction belongs in the package's handwritten modules; + those modules should consume the generated `BridgeApi` and its exported + schemas. +- Bridge wire field names and scalar encodings come from the pinned upstream + schemas. Do not globally loosen required fields or enum values to accommodate + conflicting examples; document each upstream discrepancy at its boundary. +- The package pins `effect@4.0.0-rc.112` exactly. The generator is development + tooling and is not a runtime package dependency. diff --git a/packages/bridge/LICENSE b/packages/bridge/LICENSE new file mode 100644 index 0000000..34ce76b --- /dev/null +++ b/packages/bridge/LICENSE @@ -0,0 +1,201 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2025 Miso Labs, Inc. (build@miso.network) + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/packages/bridge/README.md b/packages/bridge/README.md new file mode 100644 index 0000000..f56fbf1 --- /dev/null +++ b/packages/bridge/README.md @@ -0,0 +1,222 @@ +# `@misofm/bridge` + +An Effect v4 client for the Bridge API. It derives its operation and model +types from the pinned Bridge OpenAPI snapshot, adds a portable authenticated +client, and includes cursor pagination and webhook signature helpers. The +package does not start a runtime for you. + +## Install and make a request + +Install the SDK and the exact Effect version it was built and checked with: + +```sh +npm install @misofm/bridge effect@4.0.0-rc.112 +``` + +Provide the key as an Effect `Redacted` value. `Bridge.layerFetch` supplies the +standard Fetch transport; callers with their own transport can provide +`HttpClient.HttpClient` to `Bridge.layer` instead. + +```ts +import * as Effect from "effect/Effect" +import * as Redacted from "effect/Redacted" +import { Bridge, bridgeFetchLayer } from "@misofm/bridge" + +const listCustomers = Effect.gen(function*() { + const bridge = yield* Bridge + return yield* bridge.customers.getCustomers({ query: { limit: 25 } }) +}) + +const customers = await Effect.runPromise( + listCustomers.pipe(Effect.provide(bridgeFetchLayer({ + apiKey: Redacted.make(process.env.BRIDGE_API_KEY ?? ""), + environment: "sandbox" + }))) +) +``` + +The key is read by the application and wrapped before it reaches the client. +The SDK validates configuration without putting key or URL values in its +configuration errors. It defaults to production; select `sandbox` deliberately +for sandbox credentials. `baseUrl` can override either root for an approved +proxy or a controlled test. Fetch redirects are returned to the caller without +forwarding the `Api-Key` header. + +The complete 134-operation generated client is under the root `Bridge` service, +grouped by lower-camel-case API tag. The root module exports the client, +configuration, and client errors. Other public entry points are: + +| Import | Contents | +| --- | --- | +| `@misofm/bridge` | Client, configuration, safe client errors | +| `@misofm/bridge/bridge` | Client service and constructors | +| `@misofm/bridge/generated` | Generated `BridgeApi`, request/response schemas and model types | +| `@misofm/bridge/pagination` | Lazy cursor streams and pagination errors | +| `@misofm/bridge/webhooks` | Signature verification and event-envelope helpers | +| `@misofm/bridge/errors` | Safe client and configuration error classes | + +Every entry point is emitted as ESM JavaScript plus TypeScript declarations. + +## Miso Worker and other Fetch hosts + +The copyable [Cloudflare Worker example](examples/cloudflare-worker/README.md) +reads `env.BRIDGE_API_KEY` in the request handler, creates the Bridge layer for +that invocation, and passes `request.signal` to `Effect.runPromise`. This keeps +credentials invocation-scoped even when Cloudflare reuses an isolate. The +example's Worker secret binding is named in `wrangler.jsonc`; bind its value +with Wrangler outside source control. + +The handler maps client failures to a generic response and does not return +upstream bodies or log the key. For a different host, use the same pattern: +create the config from that invocation's secret, provide the layer, and run the +Effect only at the host boundary. + +## Errors, cancellation, and writes + +Each operation returns a lazy Effect. Its error channel contains that endpoint's +safe SDK errors: + +- `BridgeConfigurationError` for invalid configuration; +- `BridgeHttpError` for every non-2xx HTTP response, with only status, method, + and an optional request ID. The response body is drained for cleanup but is + never decoded or retained in the error, including when a method requests + `response-only` mode; +- `BridgeTransportError`, `BridgeSchemaError`, and `BridgeTimeoutError` for + sanitized transport, request/response schema, or configured timeout failures; + +Successful `response-only` calls return a response facade. Its deferred body +readers and stream sanitize later failures using the same public error types. +When the host runs the Effect, `Effect.runPromiseExit` preserves the full +`Exit`/interruption information. `Effect.runPromise` rejects on a failure. Do +not log raw causes or include upstream response bodies in public errors; the +SDK intentionally scrubs those values. A `timeoutMs` config applies a timeout +per request. Effect interruption is forwarded to Fetch using its `AbortSignal`; +interruption cannot undo work that Bridge has already accepted. + +For URL privacy, Bridge HTTP client spans and automatic trace header propagation +are suppressed while a Bridge operation runs. In particular, KYC links and +query strings are not recorded as HTTP span attributes or forwarded in +`traceparent` / `tracestate`. A caller's own surrounding span remains available, +but the outgoing Bridge request is not represented by an HTTP client span. + +The SDK does not retry writes. Supply an operation's `Idempotency-Key` header +only where that generated operation accepts it, and reuse the same key when the +upstream contract supports safe reconciliation. A timeout or transport failure +after a write can leave its remote outcome unknown; inspect or reconcile that +operation before retrying. Bridge explicitly disallows the header on API-key +creation. The pinned contract omits it for four other POST operations; see +[upstream contract notes](docs/UPSTREAM.md). + +Keep the generated request types intact at call sites. A type-erased call that +passes `undefined` to an operation requiring path parameters can still send a +request with unresolved path placeholders (for example, card freeze). The SDK +rejects malformed supplied JSON bodies before I/O, but does not guarantee that +every invalid type-erased request argument is rejected before transport. Do not +use such calls for financial mutations; this remains a pre-publication hardening +item. + +## Cursor pagination + +`paginateBridge` and `paginateBridgeRewards` return lazy Effect Streams, so +consumers can stop early and avoid fetching later pages. The standard helper +uses `starting_after` or `ending_before`, caps page size at 100, and requires a +stable item ID extractor. Rewards history uses its separate `cursor` and +`pagination.next_cursor` contract and caps at 90. Invalid sizes and cursor +cycles are typed failures. Pending card authorizations are explicitly +unpaginated and should not use these helpers. + +For example, a customer list can stream page by page: + +```ts +import * as Effect from "effect/Effect" +import * as Stream from "effect/Stream" +import * as Redacted from "effect/Redacted" +import { Bridge, bridgeFetchLayer } from "@misofm/bridge" +import { paginateBridge } from "@misofm/bridge/pagination" + +const firstTenProgram = Effect.gen(function*() { + const bridge = yield* Bridge + const allCustomers = paginateBridge( + { limit: 100 }, + (query) => bridge.customers.getCustomers({ query }), + { + getId: (customer) => + typeof customer === "object" && customer !== null && "id" in customer && + typeof customer.id === "string" + ? customer.id + : undefined + } + ) + return yield* Stream.runCollect(Stream.take(allCustomers, 10)) +}).pipe(Effect.provide(bridgeFetchLayer({ + apiKey: Redacted.make(process.env.BRIDGE_API_KEY ?? ""), + environment: "sandbox" +}))) + +const firstTen = await Effect.runPromise(firstTenProgram) +``` + +The page stream carries through the underlying request's errors, along with +`BridgePaginationLimitError` and `BridgePaginationCursorError`. + +## Webhooks + +Verify the exact raw request bytes before decoding the payload. The helpers +validate Bridge's `X-Webhook-Signature`, recommended ten-minute timestamp +window, RSA PKCS#1 v1.5 / SHA-256 signature, and can then run a caller-supplied +Effect Schema decoder. Web Crypto is required. The caller owns durable event-ID +deduplication and delivery/retry policy; signature verification alone does +not provide exactly-once processing. + +Bridge's documentation describes qualified `event_type` values such as +`customer.created`, while the pinned generated `WebhookEvent` enum lists suffix +values such as `created`. For deployments receiving qualified values, choose a +decoder that preserves the observed string rather than assuming the generated +enum accepts every documented example. The webhook helper keeps decoding in the +consumer's control for this reason. + +## Upstream scope and known gaps + +The generated API and schemas are based on the official OpenAPI snapshot +retrieved 2026-09-23. Regenerate only after reviewing the upstream diff and the +stable operation manifest. The snapshot includes three deprecated operations +and four operations marked `x-hidden`; they remain in the generated contract +for completeness and are not recommendations for new integrations. + +Some upstream examples conflict with that same snapshot: customer examples +include `type` although the component omits it, show `last_name: null` where the +schema says string, and omit `count` although the customer list response +requires it. A narrow output-only adjustment accepts `last_name: null`, the +documented structured associated-person value in `requirements.complete`, and +an omitted `count` on `GET /customers`. Create and update input schemas remain +strict, `data` remains required, `count` must be an integer when present, and +`Customer.type` is not added to the generated model. These adjustments cover +the pinned examples; live Bridge response behavior has not been sampled. + +Transfer response `currency` remains required by the generated schema, while +all published transfer examples omit it. There has been no live response or +Bridge confirmation to resolve that difference, so whether production returns +`currency` remains unconfirmed. Other narrow generation normalizations and the +complete coverage evidence are listed in [upstream contract notes](docs/UPSTREAM.md). + +## Development checks + +From the monorepo root: + +```sh +bun run --filter @misofm/bridge typecheck +bun run --filter @misofm/bridge test +bun run --filter @misofm/bridge build +bun run --filter @misofm/bridge generate:check +bun run --filter @misofm/bridge test:consumer +bun run --filter @misofm/bridge test:workerd +``` + +The packed-consumer check installs a real tarball into a temporary Node ESM +project, verifies every exported JavaScript/declaration path, typechecks all +subpaths, performs a mocked runtime API call, and compiles/runs the Worker +example with mocked Fetch. It needs no Bridge credentials or live Bridge calls. +The separate workerd check starts the example with pinned Wrangler under local +workerd, sends its request to a temporary mock Bridge server, and checks the +`GET /customers` path and synthetic API key. It also needs no live Bridge or +Cloudflare account and never deploys a Worker. diff --git a/packages/bridge/docs/UPSTREAM.md b/packages/bridge/docs/UPSTREAM.md new file mode 100644 index 0000000..0fc71ee --- /dev/null +++ b/packages/bridge/docs/UPSTREAM.md @@ -0,0 +1,163 @@ +# Bridge OpenAPI notes + +This SDK is based on the official [Bridge OpenAPI document](https://withbridge-image1-sv-usw2-monorail-openapi.s3.amazonaws.com/latest.json), retrieved on 2026-09-23. The committed, unmodified snapshot is `openapi/bridge-2026-09-23.json` with SHA-256 `e8aee6cee1b5518d81f384c8b718dd9d9154dd9eb55345ff73d8b8dbe88327f2` (OpenAPI 3.0.2; 100 paths; 134 operations; 263 component schemas). The stable operation IDs and lower-camel group names are in `openapi/operation-manifest.json` because the source has no `operationId` values. + +The generated surface retains all 134 operations, including the four operations marked `x-hidden` under Developer Fees and the three operations marked deprecated. `tests/coverage.test.ts` compares source and generated verb/path, parameter, body media, status, and response media metadata. + +## Idempotency + +Bridge’s [idempotency guide](https://apidocs.bridge.xyz/api-reference/introduction/idempotence) gives general guidance for POST requests. The [Create a scoped API key endpoint](https://apidocs.bridge.xyz/api-reference/api-keys/create-a-scoped-api-key) explicitly says it does not accept `Idempotency-Key`; each call creates a new key. The OpenAPI snapshot has no such parameter on `POST /api_keys`. + +The same snapshot has no `Idempotency-Key` parameter declaration on these four other POST operations: + +- `POST /customers/{customerID}/external_accounts/{externalAccountID}/verify` +- `POST /plaid_exchange_public_token/{link_token}` +- `POST /customers/{customerID}/card_accounts/{cardAccountID}/statements/{period}.pdf` +- `POST /cardholders/{cardholderID}/cards/{cardID}/statements/{period}.pdf` + +That is five POST operations total without a declaration, counting API key creation. The API key documentation is an explicit prohibition; the other four are omissions in the snapshot. The client does not infer a global requirement and does not add an idempotency header to operations whose generated contract has none. There are no live credentials or Bridge calls in this package’s tests. + +## Customer examples and schema + +The raw `Customer` schema does not declare a `type` field, while the create and list examples include `type: "individual"` or `type: "business"`. The successful business-customer response example sets `last_name` to `null` and includes a structured associated-person item in `requirements.complete`; the raw schema declares a string surname and string-only completed items. Both `GET /customers` examples omit `count`. + +The normalization overlay now applies an output-only compatibility adjustment for those published shapes: `Customer.last_name` accepts `null`, `requirements.complete` accepts strings or the documented `{ associated_person, items }` object, and only the `GET /customers` response makes `count` optional. `data` remains required and `count` remains an integer when present. Create and update payload schemas stay strict, and `Customer.type` is not added to the generated static model. Tests accept the official examples and reject a nullable surname on the create request. These checks establish compatibility with the pinned examples; no live Bridge response was sampled, so they do not confirm production wire behavior. Pagination still follows the endpoint’s cursor contract and must not infer completion from an example’s missing `count`. + +## Webhook event values + +The `WebhookEvent.event_type` enum contains suffixes such as `created` and `updated`, while its description says values are prefixed with `event_category` and gives `customer.created` as an example. Event examples also use qualified values. Keep the schema-derived enum intact and treat the qualified-value conflict explicitly at event decoding; do not replace the enum globally with an unrestricted string. See Bridge’s [webhook event structure](https://apidocs.bridge.xyz/platform/additional-information/webhooks/structure). + +## Developer Fees response schema + +`POST /developer/fees` declares an `application/json` success response and includes an example with `default_liquidation_address_fee_percent`, but omits the response schema. The generation overlay adds a reference to the existing `DeveloperFees` component, which is also used by `GET /developer/fees`. This is the narrow response repair; it does not change the raw snapshot. + +## Optional card request bodies + +OpenAPI 3.0 treats an omitted `requestBody.required` value as `false`. Four card +operations use that default: ephemeral key creation, freeze, unfreeze, and mobile +wallet push provisioning. Their generated methods accept either the operation's +request schema or an absent payload. The client sends `payload: undefined` as an +empty HTTP body without `Content-Type`, and sends supplied payloads as JSON; +compile-time and controlled-client checks cover both forms. + +The pinned Effect rc.112 `OpenApi.fromApi` projection still reports +`requestBody.required: true` for these payload unions. This is a projection +limitation only; it does not describe the generated method type or client wire +behavior. The raw snapshot remains the authority for optionality. + +## Repaired and normalized schemas + +The initial rc.112 generation emitted `Schema.Never` for non-empty contracts +below. That generation defect is fixed: the current generator produces concrete +schemas for the audited models, and a repository scan of the generated API finds +zero `Schema.Never` references. `tests/contracts.test.ts` pins the affected +operation use sites and decodes non-empty synthetic or documented examples. + +| Repaired model | Affected operations | +| --- | --- | +| `ExternalAccountResponse` | `DELETE /customers/{customerID}/external_accounts/{externalAccountID}`; `GET /customers/{customerID}/external_accounts`; `GET /customers/{customerID}/external_accounts/{externalAccountID}`; `GET /external_accounts`; `POST /customers/{customerID}/external_accounts`; `POST /customers/{customerID}/external_accounts/{externalAccountID}/deactivate`; `POST /customers/{customerID}/external_accounts/{externalAccountID}/reactivate`; `PUT /customers/{customerID}/external_accounts/{externalAccountID}` | +| `CreateExternalAccountInput` | `POST /customers/{customerID}/external_accounts` (the eight-branch `oneOf` now generates a concrete union; seven named request examples are checked) | +| `CreateLiquidationAddressResponse` | `POST /customers/{customerID}/liquidation_addresses` | +| `FeeExternalAccount` | `GET /developer/fee_external_account`; `POST /developer/fee_external_account` | +| `CreateFeeExternalAccountInput` | `POST /developer/fee_external_account` | +| `CardAccount` | `GET /customers/{customerID}/card_accounts`; `GET /customers/{customerID}/card_accounts/{cardAccountID}`; `POST /customers/{customerID}/card_accounts`; `PUT /customers/{customerID}/card_accounts/{cardAccountID}` | + +The generator also previously emitted `WebhookEvent.event_object` and +`event_object_changes` as `Record`. They now accept JSON-valued +maps; the populated event fixture exercises both through `WebhookEvent` and the +webhook-events response. The broader regression fixtures cover the other +discovered nested shapes: current and future customer endorsement requirements +(including `missing: null`, `all_of`/`any_of`, and issue-code maps), all six +virtual-account deposit-instruction rail variants, integer country counts and +decimal-string country volumes in `CardProgramSummary`, and a populated +virtual-account deactivation response. These schema fixtures remain separate +from upstream examples that contradict the pinned schemas; see the audit below. + +## Controlled contract fixtures + +`tests/contracts.test.ts` runs only against a strict local `HttpClient` fake: +an unregistered method/path defects rather than silently returning a generic +success. The Miso sequence creates an individual customer and KYC link, creates a +wallet and ACH external account under the returned customer ID, creates a +decimal-string transfer using both returned resource IDs, then reads a populated +event through the webhook-events endpoint. It is a schema and client-composition +fixture, not a live onboarding or payment test: the KYC response is +`not_started`, the wallet and external account are synthetic, and the transfer +response is `awaiting_funds`. Bridge defines [`awaiting_funds` as waiting for +customer funds before processing](https://apidocs.bridge.xyz/platform/orchestration/transfers/transfer-states), +so a successful create response does not mean the transfer settled. Consumers +must handle actual KYC and endorsement state, funding, transfer transitions, and +webhook delivery and deduplication in their own flow. A second fake-client fixture covers prefunded +accounts, liquidation-address collection, card accounts, webhook registration +reads, developer fees, and country reference data. Both tests assert request +paths and bodies, auth/idempotency headers where applicable, and decoded +responses. Additional schema fixtures cover each documented external-account +rail. These tests use only synthetic keys and fixture data; they make no live +Bridge requests. + +The pinned wallet create, list, and detail response examples decode against +their generated schemas, as do the documented external-account rail requests +and responses. By contrast, the six published external-account verification +responses are ambiguous under the declared overlapping `oneOf`; the generated +client can reject them even though their rail-shaped payloads are in the spec. +Card-account operations have no directly addressable `2xx` JSON response +examples in this snapshot, so the card fixture is synthetic and is not evidence +of live card-response conformance. + +Compile-only contract checks accept the documented requests and optional card +bodies, while `@ts-expect-error` cases pin rejected numeric decimal amounts and +invalid card currency literals. These checks do not replace runtime schema +validation or prove backend behavior. + +## Official response-example audit + +For this pass, a directly addressable response example is an inline example or a +`components.examples` reference attached to an explicit `2xx` +`application/json` response in the pinned snapshot. References are resolved, and +each operation/status use is checked against its generated success schema; +reusing one component example on another operation counts as another use. This +excludes request examples, examples attached only to component schemas, +non-JSON media, and error responses. The selection contains 181 uses across 122 +distinct example values; 86 uses fail their corresponding generated schema +after the output-only customer overlay accepts three previously failing uses. +`tests/contracts.test.ts` pins representative cases below, including the +remaining strict failures. + +| Mismatch group | Evidence in the pinned snapshot | Classification | +| --- | --- | --- | +| Customer responses | The raw declaration has a string `last_name` and string-only `requirements.complete`; `SuccessfulCustomerResponse2` uses `last_name: null` and a structured associated-person item. Both `GET /customers` examples omit `count`. | Direct raw-spec contradictions addressed by an output-only overlay: nullable response surname, string-or-structured completed items, and optional list-response `count`. `data` stays required, create/update inputs stay strict, and no static `Customer.type` field is added. Example acceptance does not confirm live wire behavior. | +| Associated persons | The `SuccessfulAssociatedPersonResponse` timestamps are ISO strings; the component declares integer milliseconds. | Direct component/example contradiction. | +| Transfers | All published transfer examples omit top-level `currency`, which `TransferResponse` requires. Their transfer states such as `awaiting_funds` are allowed. | Unresolved response example/schema contradiction. `currency` remains required; no live Bridge response or Bridge confirmation establishes whether production omits it, so transfer wire compatibility remains unconfirmed. | +| Virtual accounts | The US operation example contains quote characters in property names; other rail examples omit schema-required properties or use `payment_rails` arrays where EU/GB declare a string. | Direct operation example/schema contradictions. The generated rail union follows the component schemas. | +| External-account verification | `AccountVerification` is a six-member `oneOf`; every member has only optional keys and permits additional properties, so each rail-keyed example matches multiple members. | Ambiguous upstream composition. The generated `oneOf` correctly rejects examples that do not match exactly one member; Bridge should make the variants exclusive or change the composition. | +| Response envelopes and shapes | The ToS-link response schema is `{ url }` but its example wraps it as `{ data: { url } }`; liquidation-address drain examples use a `count`/array envelope where the schema describes one `Drain`; the prefunded-account-history example is a `count`/array envelope where the response schema is `PrefundedAccountHistory`. | Direct operation response schema/example contradictions. | +| Other value constraints | Funds-request examples use a currency outside the declared enum; RFI examples use `bridge_action_taken` values outside its enum; liquidation-address create examples omit required `destination_payment_rail`; the static-memo history example exceeds the declared `omad` length; webhook examples use category/type values outside their enums or omit a required logs `count`. | Direct response example/schema contradictions. | + +These reviewed failures point to upstream schema/example disagreement or an +ambiguous upstream `oneOf`. The implemented customer overlay accepts the +published business and list response shapes without relaxing create/update +inputs or unrelated schemas; the raw snapshot remains unchanged. The generated +`Customer` type still has no declared `type` property. Transfer response +`currency` remains required: every published transfer example omits it, but the +live response shape is unconfirmed and Bridge has not confirmed whether this is +intentional. No live Bridge calls were made, so generated-schema example checks +do not establish live wire compatibility. + +KYC status is a separate flow condition: `not_started` is accepted by the KYC +schema and is not a decoding defect, but the Miso fixture must not be read as +proof that a customer completed KYC or received the endorsement needed for a +particular product. + +## Pagination exceptions + +The [stablecoin reward history endpoint](https://apidocs.bridge.xyz/api-reference/rewards/get-daily-reward-history-for-a-stablecoin) has its own `cursor` and `pagination.next_cursor` contract, with a maximum `limit` of 90. It is not the standard `starting_after` / `ending_before` cursor pair. The [pending card authorizations endpoint](https://apidocs.bridge.xyz/api-reference/cards/retrieve-pending-card-authorizations) is explicitly unpaginated. These routes need their own handling and must not be folded into standard list pagination. + +## Webhook signature documentation + +Bridge’s [signature guide](https://apidocs.bridge.xyz/platform/additional-information/webhooks/signature) specifies hashing `timestamp + "." + rawBody` with SHA-256 and then verifying the resulting digest with RSA PKCS#1 v1.5 SHA-256. The guide’s Ruby example is inconsistent with that stated algorithm. The SDK follows the guide’s prose and compatible language examples, verifies the exact raw request bytes before decoding JSON, and tests against an independently generated signature vector. Consumers remain responsible for durable event-ID deduplication. + +## Source links + +- [Bridge API reference](https://apidocs.bridge.xyz/api-reference/introduction/introduction) +- [Bridge documentation index](https://apidocs.bridge.xyz/llms.txt) +- [Bridge deprecation guide](https://apidocs.bridge.xyz/api-reference/introduction/deprecation) diff --git a/packages/bridge/examples/cloudflare-worker/.gitignore b/packages/bridge/examples/cloudflare-worker/.gitignore new file mode 100644 index 0000000..8d8accc --- /dev/null +++ b/packages/bridge/examples/cloudflare-worker/.gitignore @@ -0,0 +1 @@ +/.wrangler/ diff --git a/packages/bridge/examples/cloudflare-worker/README.md b/packages/bridge/examples/cloudflare-worker/README.md new file mode 100644 index 0000000..396bb19 --- /dev/null +++ b/packages/bridge/examples/cloudflare-worker/README.md @@ -0,0 +1,36 @@ +# Bridge client in a Cloudflare Worker + +Bind `BRIDGE_API_KEY` as a Worker secret and optionally set `BRIDGE_ENVIRONMENT` +to `sandbox` or `production`. This handler reads the binding and constructs its +Bridge layer inside each invocation. It forwards the incoming request signal to +the Effect runner and never logs the key or upstream error body. + +For a local integration smoke, the handler also accepts an optional +`BRIDGE_API_BASE_URL` binding. Point it only at a controlled test server; the +example does not derive a Bridge host from the incoming request. + +The example exposes `GET /customers`; its Bridge request uses the currently +configured environment and requires an active credential at runtime. For a +real local-runtime check, build the package and run this from the monorepo root: + +```sh +bun run --filter @misofm/bridge build +bun run --filter @misofm/bridge test:workerd +``` + +That command uses Wrangler 4.137.0, pinned as a package development dependency, +to run the handler in local workerd. It supplies a synthetic key and a temporary +local mock Bridge server, then checks the upstream method, path, key, and +successful response. It makes no request to Bridge's hosted API, requires no +Cloudflare account, and never deploys. The packed-consumer check separately +compiles and runs the Worker in Node with mocked Fetch; that check does not +exercise workerd. + +To check the deployable bundle, run +`bunx --no-install wrangler deploy --dry-run --minify` from this directory. It +bundles locally and does not deploy. + +The `wrangler.jsonc` documents the optional environment variable; the secret is +bound outside the file. For interactive local development, put +`BRIDGE_API_KEY=...` in an untracked `.dev.vars` file. Bind a deployed secret +through the target Worker environment's secret manager; never commit a key. diff --git a/packages/bridge/examples/cloudflare-worker/src/index.ts b/packages/bridge/examples/cloudflare-worker/src/index.ts new file mode 100644 index 0000000..e44053d --- /dev/null +++ b/packages/bridge/examples/cloudflare-worker/src/index.ts @@ -0,0 +1,43 @@ +import * as Effect from "effect/Effect" +import * as Redacted from "effect/Redacted" + +import { Bridge, BridgeHttpError, BridgeTransportError, bridgeFetchLayer } from "@misofm/bridge" + +interface Env { + BRIDGE_API_KEY: string + BRIDGE_API_BASE_URL?: string + BRIDGE_ENVIRONMENT?: "production" | "sandbox" +} + +const listCustomers = Effect.gen(function*() { + const bridge = yield* Bridge + return yield* bridge.customers.getCustomers({ query: {} }) +}) + +export default { + async fetch(request: Request, env: Env): Promise { + const url = new URL(request.url) + if (request.method !== "GET" || url.pathname !== "/customers") { + return Response.json({ error: "Not found" }, { status: 404 }) + } + + // The binding is read for this invocation; do not capture a user or key in + // module state shared by the Worker isolate. + const layer = bridgeFetchLayer({ + apiKey: Redacted.make(env.BRIDGE_API_KEY), + environment: env.BRIDGE_ENVIRONMENT ?? "production", + ...(env.BRIDGE_API_BASE_URL === undefined ? {} : { baseUrl: env.BRIDGE_API_BASE_URL }) + }) + try { + const customers = await Effect.runPromise( + listCustomers.pipe(Effect.provide(layer)), + { signal: request.signal } + ) + return Response.json(customers) + } catch (error) { + if (request.signal.aborted) throw error + const status = error instanceof BridgeHttpError ? 502 : error instanceof BridgeTransportError ? 503 : 502 + return Response.json({ error: "Bridge request failed" }, { status }) + } + } +} diff --git a/packages/bridge/examples/cloudflare-worker/wrangler.jsonc b/packages/bridge/examples/cloudflare-worker/wrangler.jsonc new file mode 100644 index 0000000..9d607b8 --- /dev/null +++ b/packages/bridge/examples/cloudflare-worker/wrangler.jsonc @@ -0,0 +1,8 @@ +{ + "name": "misofm-bridge-example", + "main": "src/index.ts", + "compatibility_date": "2026-09-15", + "vars": { + "BRIDGE_ENVIRONMENT": "sandbox" + } +} diff --git a/packages/bridge/openapi/README.md b/packages/bridge/openapi/README.md new file mode 100644 index 0000000..35b2ad0 --- /dev/null +++ b/packages/bridge/openapi/README.md @@ -0,0 +1,96 @@ +# Bridge OpenAPI inputs + +`bridge-2026-09-23.json` is the unmodified official Bridge OpenAPI document +retrieved from: + + + +- Retrieved: 2026-09-23 +- SHA-256: `e8aee6cee1b5518d81f384c8b718dd9d9154dd9eb55345ff73d8b8dbe88327f2` +- OpenAPI: 3.0.2 +- Paths: 100 +- Operations: 134 +- Component schemas: 263 + +`operation-manifest.json` supplies stable `operationId` values and concise +client group keys because the source document does not define any operation IDs. +The group keys map the upstream tag names to lower-camel-case properties on the +generated `HttpApiClient`. + +`normalization-overlay.json` records narrow corrections needed to preserve the +published contracts through rc.112 generation. It references the existing +`DeveloperFees` response schema where `POST /developer/fees` has an example but +no schema, supplies implied object types for composed models, and makes four +card-account request bodies' OpenAPI-default `required: false` explicit. It +also records the following contract-specific normalizations: + +- The pinned spec has 123 non-composed component-schema nodes with `properties` + or `required` but no `type: object`; 9 were already covered by explicit + overlay entries. The overlay lists the remaining 114 JSON Pointers, and the + generator checks that list against the raw snapshot before applying it. Each + correction adds only `type: object` and, when omitted, the OpenAPI-default + `additionalProperties: true`. Required fields, enums, nullability, and + composition stay as published. This prevents these models from accepting + primitive JSON values while keeping object fields open. + +- The shared bank-account components mark input and output fields with + `writeOnly`/`readOnly` but require both directions at once. The overlay keeps + output-required fields on the original components, creates request variants + with writable required fields, and retargets only create-request references. + The fee-account create schema is similarly copied from the US response + variant and points to the request-side bank contract. +- The fee-account schema lists `customer_id` and an undeclared `account_name` + as required even though its published success example omits both. The + response overlay keeps the declared fields but does not synthesize missing + required properties. +- Card-account responses allow the `bridge` freeze initiator, while the shared + freeze request enum remains restricted to `customer` and `developer`. +- Webhook event payloads are resource-specific JSON objects, so their + `event_object` and `event_object_changes` maps remain open JSON values rather + than impossible records with `never` values. +- Customer endorsement requirements publish `missing` and `issues` objects + without `additionalProperties`; successful examples show `missing` as both + `null` and an `all_of` breakdown, while the `issues` description specifies + field-to-string issue-code maps. The overlay preserves the observed null + alternative, keeps non-null missing values JSON-compatible, and types + issue-code values as strings. `CardProgramSummary` similarly omits map value + schemas despite examples: country counts are integers and country transaction + volumes are decimal strings, so the overlay records those per-map types. +- The published successful business-customer example has `last_name: null` and + a structured `endorsements[].requirements.complete` entry alongside strings; + both successful `GET /customers` examples omit `count`. These response-side + discrepancies are modeled narrowly: `Customer.last_name` is nullable, the + completed-requirement object has exactly `associated_person` and string-array + `items`, and only the list response's integer `count` is optional. Create and + update payload schemas remain separate and unchanged. +- The six `VirtualAccountSourceDepositInstructions` alternatives use `allOf` + object compositions whose roots omit `type: object`. The shared bank fields + and rail-specific branches also rely on OpenAPI's default-open + `additionalProperties` behavior. The overlay makes those exact roots and + branches explicit for the pinned generator. `VirtualAccountResponse` also + omits its implied object type, and the deactivate operation wraps it in + another untyped `allOf` response with an example-only `status` property; + normalizing the response and branch keeps the inherited response fields and + the existing activation-status enum typed. +- A nullable liquidation fee-percent schema has a string-only example; rc.112 + copies that example to its null union branch, causing a TypeScript error. + The overlay removes only that ambiguous example metadata and keeps the + original numeric-string constraints and nullability. + +Two generated PDF body schemas also receive exact, guarded +string-to-`Uint8Array` corrections because `HttpApiSchema.asUint8Array` requires +bytes on the encoded side. Each generated override must match one exact +generator declaration or generation fails. All adjustments are applied in +memory; the raw snapshot and operation manifest remain byte-pinned and +unchanged. + +Generation applies the overlay and manifest in memory. The raw snapshot remains +unchanged and the generated output is reproducible offline with the pinned +development toolchain. + +The generator also reverses the payload schema order for those four optional +card-account POST operations. In rc.112, encoding their generated union with +`HttpApiSchema.NoContent` first can turn a supplied JSON object into +`undefined`; putting that operation's request schema first preserves the body +while retaining the no-content alternative. This guarded output correction +changes neither the public request type nor the pinned OpenAPI inputs. diff --git a/packages/bridge/openapi/bridge-2026-09-23.json b/packages/bridge/openapi/bridge-2026-09-23.json new file mode 100644 index 0000000..687eeb8 --- /dev/null +++ b/packages/bridge/openapi/bridge-2026-09-23.json @@ -0,0 +1,22629 @@ +{ + "openapi": "3.0.2", + "info": { + "title": "Bridge API", + "description": "APIs to move into, out of, and between any form of a dollar", + "version": "1" + }, + "servers": [ + { + "url": "https://api.bridge.xyz/v0", + "description": "The base path for all resources" + } + ], + "tags": [ + { + "name": "Customers" + }, + { + "name": "Fiat Payout Configuration" + }, + { + "name": "External Accounts" + }, + { + "name": "Transfers" + }, + { + "name": "Prefunded Accounts" + }, + { + "name": "Balances" + }, + { + "name": "Liquidation Addresses" + }, + { + "name": "Developer Fees" + }, + { + "name": "Developers" + }, + { + "name": "API Keys" + }, + { + "name": "Plaid" + }, + { + "name": "Virtual Accounts" + }, + { + "name": "Static Memos" + }, + { + "name": "Cards" + }, + { + "name": "Funds Requests" + }, + { + "name": "RFIs" + }, + { + "name": "Webhooks" + }, + { + "name": "Lists" + }, + { + "name": "Crypto Return Policies" + }, + { + "name": "Rewards" + }, + { + "name": "Associated Persons" + }, + { + "name": "Sandbox" + } + ], + "paths": { + "/wallets": { + "get": { + "summary": "Get all Bridge Wallets", + "description": "List of Bridge Wallets", + "tags": [ + "Bridge Wallets" + ], + "parameters": [ + { + "$ref": "#/components/parameters/LimitParameter" + }, + { + "$ref": "#/components/parameters/BridgeWalletStartingAfterParameter" + }, + { + "$ref": "#/components/parameters/BridgeWalletEndingBeforeParameter" + } + ], + "responses": { + "200": { + "description": "List of Bridge Wallets", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BridgeWalletsList" + }, + "examples": { + "SuccessfulBridgeWalletListResponse": { + "$ref": "#/components/examples/SuccessfulBridgeWalletListResponse" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "404": { + "$ref": "#/components/responses/NotFoundError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/wallets/total_balances": { + "get": { + "summary": "Get total balances of all Bridge Wallets", + "tags": [ + "Bridge Wallets" + ], + "description": "Get the total balances of all Bridge Wallets", + "responses": { + "200": { + "description": "Total balances of all Bridge Wallets", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BridgeWalletTotalBalance" + } + }, + "examples": { + "TotalBalancesFound": { + "$ref": "#/components/examples/SuccessfulTotalBalancesResponse" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "404": { + "$ref": "#/components/responses/NotFoundError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/wallets/{bridgeWalletID}": { + "get": { + "summary": "Get a Bridge Wallet", + "description": "Retrieve a Bridge Wallet by its ID", + "tags": [ + "Bridge Wallets" + ], + "parameters": [ + { + "$ref": "#/components/parameters/BridgeWalletIDParameter" + } + ], + "responses": { + "200": { + "description": "A Bridge Wallet object response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BridgeWalletWithBalances" + }, + "examples": { + "SuccessfulBridgeWalletGetResponse": { + "$ref": "#/components/examples/SuccessfulBridgeWalletGetResponse" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "404": { + "$ref": "#/components/responses/NotFoundError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/wallets/{bridgeWalletID}/history": { + "parameters": [ + { + "$ref": "#/components/parameters/BridgeWalletIDParameter" + }, + { + "$ref": "#/components/parameters/LimitParameter" + }, + { + "$ref": "#/components/parameters/BridgeWalletHistoryStartingAfterParameter" + }, + { + "$ref": "#/components/parameters/BridgeWalletHistoryEndingBeforeParameter" + }, + { + "$ref": "#/components/parameters/BridgeWalletHistoryStartingTimeParameter" + }, + { + "$ref": "#/components/parameters/BridgeWalletHistoryEndingTimeParameter" + } + ], + "get": { + "summary": "Get transaction history for a Bridge Wallet", + "tags": [ + "Bridge Wallets" + ], + "description": "Get the list of transactions involving this Bridge Wallet", + "responses": { + "200": { + "$ref": "#/components/responses/BridgeWalletHistoryResponse" + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "404": { + "$ref": "#/components/responses/NotFoundError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/customers": { + "get": { + "summary": "Get all customers", + "description": "Get the full list of all customers created on Bridge", + "tags": [ + "Customers" + ], + "parameters": [ + { + "$ref": "#/components/parameters/CustomerStartingAfterParameter" + }, + { + "$ref": "#/components/parameters/CustomerEndingBeforeParameter" + }, + { + "$ref": "#/components/parameters/LimitParameter" + }, + { + "$ref": "#/components/parameters/CustomerEmailParameter" + } + ], + "responses": { + "200": { + "description": "List of customers (the returned list is empty if none found)", + "content": { + "application/json": { + "schema": { + "title": "Customers", + "type": "object", + "required": [ + "count", + "data" + ], + "properties": { + "count": { + "description": "total number of items in data", + "type": "integer" + }, + "data": { + "type": "array", + "minItems": 0, + "items": { + "$ref": "#/components/schemas/Customer" + } + } + } + }, + "examples": { + "CustomersFound": { + "summary": "A non-empty list of customers", + "value": { + "data": [ + { + "id": "00000000-0000-0000-0000-000000000000", + "first_name": "John", + "last_name": "Doe", + "email": "johndoe@example.com", + "client_reference_id": "your_internal_id_123", + "status": "active", + "type": "individual", + "persona_inquiry_type": "gov_id_db", + "created_at": "2025-11-19T21:14:58.328Z", + "updated_at": "2025-11-19T21:16:02.894Z", + "rejection_reasons": [], + "has_accepted_terms_of_service": true, + "endorsements": [ + { + "name": "base", + "status": "approved", + "requirements": { + "complete": [ + "terms_of_service_v1", + "first_name", + "last_name", + "tax_identification_number", + "email_address", + "address_of_residence", + "date_of_birth", + "proof_of_address", + "sanctions_screen", + "pep_screen", + "blocklist_lookup", + "min_age_18", + "selfie_verification", + "government_id_rejection_checks_passed", + "government_id_review_checks_passed", + "government_id_reliance", + "post_processing" + ], + "pending": [], + "missing": null, + "issues": [] + } + }, + { + "name": "sepa", + "status": "approved", + "requirements": { + "complete": [ + "terms_of_service_v2", + "first_name", + "last_name", + "tax_identification_number", + "email_address", + "address_of_residence", + "date_of_birth", + "proof_of_address", + "sanctions_screen", + "pep_screen", + "blocklist_lookup", + "min_age_18", + "selfie_verification", + "government_id_rejection_checks_passed", + "government_id_review_checks_passed", + "government_id_reliance" + ], + "pending": [], + "missing": null, + "issues": [] + } + } + ], + "future_requirements_due": [], + "requirements_due": [ + "external_account" + ], + "capabilities": { + "payin_crypto": "active", + "payout_crypto": "active", + "payin_fiat": "pending", + "payout_fiat": "pending" + } + }, + { + "id": "00000000-0000-0000-0000-000000000000", + "first_name": "Acme Corporation", + "last_name": null, + "email": "business@example.com", + "client_reference_id": "your_internal_id_456", + "status": "active", + "type": "business", + "persona_inquiry_type": "business", + "created_at": "2025-11-19T04:41:33.296Z", + "updated_at": "2025-11-19T19:10:39.393Z", + "rejection_reasons": [], + "has_accepted_terms_of_service": true, + "endorsements": [ + { + "name": "base", + "status": "approved", + "requirements": { + "complete": [ + "terms_of_service_v1", + "business_name", + "business_type", + "business_description", + "is_dao", + "email_address", + "address_of_incorporation", + "address_of_operation", + "tax_identification_number", + "business_industry", + "control_person_ownership_attestation", + "minimal_source_of_funds_data", + "proof_of_address", + "adverse_media_screen", + "sanctions_screen", + "manual_business_ein_verification_review", + "manual_business_registry_verification_review", + "business_website", + "manual_business_website_verification_review", + "business_formation_document_verification", + "manual_business_formation_document_verification_review", + "kyb_review", + { + "associated_person": "11111111-1111-1111-1111-111111111111", + "items": [ + "has_control", + "first_name", + "last_name", + "email_address", + "address_of_residence", + "associated_person_relationship", + "date_of_birth", + "tax_identification_number", + "manual_government_id_review", + "sanctions_screen", + "adverse_media_screen", + "pep_screen", + "min_age_18", + "selfie_verification", + "has_title" + ] + } + ], + "pending": [], + "missing": null, + "issues": [] + } + }, + { + "name": "sepa", + "status": "approved", + "requirements": { + "complete": [ + "terms_of_service_v2", + "business_name", + "business_type", + "business_description", + "is_dao", + "email_address", + "address_of_incorporation", + "address_of_operation", + "tax_identification_number", + "business_industry", + "control_person_ownership_attestation", + "minimal_source_of_funds_data", + "proof_of_address", + "adverse_media_screen", + "sanctions_screen", + "manual_business_ein_verification_review", + "manual_business_registry_verification_review", + "business_website", + "manual_business_website_verification_review", + "business_formation_document_verification", + "manual_business_formation_document_verification_review", + "kyb_review", + { + "associated_person": "11111111-1111-1111-1111-111111111111", + "items": [ + "has_control", + "first_name", + "last_name", + "email_address", + "address_of_residence", + "associated_person_relationship", + "date_of_birth", + "tax_identification_number", + "manual_government_id_review", + "sanctions_screen", + "adverse_media_screen", + "pep_screen", + "min_age_18", + "selfie_verification", + "has_title" + ] + } + ], + "pending": [], + "missing": null, + "issues": [] + } + } + ], + "future_requirements_due": [], + "requirements_due": [ + "external_account" + ], + "capabilities": { + "payin_crypto": "active", + "payout_crypto": "active", + "payin_fiat": "pending", + "payout_fiat": "pending" + }, + "associated_persons": [ + { + "id": "11111111-1111-1111-1111-111111111111", + "email": "person@example.com" + } + ] + } + ] + } + }, + "NoCustomersFound": { + "summary": "An empty list of customers", + "value": { + "data": [] + } + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + }, + "post": { + "summary": "Create a customer", + "tags": [ + "Customers" + ], + "parameters": [ + { + "$ref": "#/components/parameters/IdempotencyKeyParameter" + } + ], + "requestBody": { + "description": "Customer object to be created.\n\nNo fields are strictly required by the API. For example, it is valid to create a customer without a first name, last name, or residential address, but this customer will not be granted endorsements required to transact on Bridge until the necessary information is provided, possibly via a PUT request.\n", + "required": true, + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/CreateIndividualCustomerPayload" + }, + { + "$ref": "#/components/schemas/CreateBusinessCustomerPayload" + } + ], + "discriminator": { + "propertyName": "type", + "mapping": { + "individual": "#/components/schemas/CreateIndividualCustomerPayload", + "business": "#/components/schemas/CreateBusinessCustomerPayload" + } + } + } + } + } + }, + "responses": { + "201": { + "description": "Customer object created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Customer" + }, + "examples": { + "IndividualCustomerCreated": { + "summary": "Customer successfully created", + "$ref": "#/components/examples/SuccessfulCustomerResponse" + }, + "BusinessCustomerCreated": { + "summary": "Customer successfully created", + "$ref": "#/components/examples/SuccessfulCustomerResponse2" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/customers/{customerID}": { + "parameters": [ + { + "$ref": "#/components/parameters/CustomerIDParameter" + } + ], + "get": { + "summary": "Get a single customer object", + "tags": [ + "Customers" + ], + "description": "Retrieve a customer object from the passed in customer ID", + "responses": { + "200": { + "description": "Successful customer object response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Customer" + }, + "examples": { + "SuccessfulCustomerResponse": { + "$ref": "#/components/examples/SuccessfulCustomerResponse" + }, + "RejectedCustomerResponse": { + "$ref": "#/components/examples/RejectedCustomerResponse" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "404": { + "$ref": "#/components/responses/NotFoundError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + }, + "put": { + "summary": "Update a single customer object", + "tags": [ + "Customers" + ], + "requestBody": { + "description": "Customer object to update with", + "required": true, + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/UpdateIndividualCustomerPayload" + }, + { + "$ref": "#/components/schemas/UpdateBusinessCustomerPayload" + } + ], + "discriminator": { + "propertyName": "type", + "mapping": { + "individual": "#/components/schemas/UpdateIndividualCustomerPayload", + "business": "#/components/schemas/UpdateBusinessCustomerPayload" + } + } + } + } + } + }, + "description": "Updates to be made to the specified customer.\n\nNo fields are strictly required by the API. It is generally valid to provide any subset of data in a PUT request. For business customers, associated persons cannot be updated via PUT, and should instead be managed using v0/associated_persons.\n", + "responses": { + "200": { + "description": "Successful customer object response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Customer" + }, + "examples": { + "SuccessfulCustomerResponse": { + "$ref": "#/components/examples/SuccessfulCustomerResponse" + }, + "RejectedCustomerResponse": { + "$ref": "#/components/examples/RejectedCustomerResponse" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "404": { + "$ref": "#/components/responses/NotFoundError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + }, + "delete": { + "summary": "Delete a single customer object", + "tags": [ + "Customers" + ], + "description": "Delete a customer object from the passed in customer ID", + "responses": { + "200": { + "description": "Successfully deleted customer object response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Customer" + }, + "examples": { + "DeletedCustomerResponse": { + "$ref": "#/components/examples/SuccessfulCustomerResponse" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "404": { + "$ref": "#/components/responses/NotFoundError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/customers/{customerID}/external_accounts": { + "parameters": [ + { + "$ref": "#/components/parameters/CustomerIDParameter" + } + ], + "get": { + "summary": "Get all External Accounts", + "tags": [ + "External Accounts" + ], + "description": "Get all External Accounts for a passed in customer.", + "parameters": [ + { + "$ref": "#/components/parameters/LimitParameter" + }, + { + "$ref": "#/components/parameters/ExternalAccountStartingAfterParameter" + }, + { + "$ref": "#/components/parameters/ExternalAccountEndingBeforeParameter" + } + ], + "responses": { + "200": { + "description": "List of External Accounts (the returned list is empty if no External Accounts exist)", + "content": { + "application/json": { + "schema": { + "title": "ExternalAccount", + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "type": "array", + "minItems": 0, + "items": { + "$ref": "#/components/schemas/ExternalAccountResponse" + } + }, + "count": { + "description": "total number of items in data", + "type": "integer" + } + } + }, + "examples": { + "ExternalAccountsFound": { + "summary": "A non-empty list of External Accounts", + "value": { + "data": [ + { + "id": "ea_123", + "account_type": "us", + "currency": "usd", + "customer_id": "cust_123", + "account_owner_name": "John Doe", + "bank_name": "Wells Fargo", + "last_4": "1111", + "active": true, + "beneficiary_address_valid": true, + "account": { + "last_4": "1111", + "routing_number": "121000248", + "checking_or_savings": "checking" + }, + "created_at": "2020-01-01T00:00:00.000Z", + "updated_at": "2020-01-02T00:00:00.000Z" + } + ] + } + }, + "ExternalAccountsFoundIban": { + "summary": "iban", + "value": { + "data": [ + { + "id": "ea_123", + "customer_id": "cust_123", + "account_type": "iban", + "currency": "eur", + "account_owner_name": "John Doe", + "bank_name": "AAC CAPITAL PARTNERS LIMITED", + "active": true, + "iban": { + "last_4": "5981", + "bic": "BARBGB2LLEI", + "country": "NLD" + }, + "account_owner_type": "individual", + "first_name": "John", + "last_name": "Doe", + "account_verification": { + "iban": { + "match_level": "match", + "reason_code": null, + "validated_account_owner_name": "John Doe" + }, + "requested_at": "2020-01-01T00:05:00.000Z", + "completed_at": "2020-01-01T00:05:05.000Z" + }, + "created_at": "2020-01-01T00:00:00.000Z", + "updated_at": "2020-01-02T00:00:00.000Z" + } + ] + } + }, + "ExternalAccountsFoundPixKey": { + "summary": "pix (Pix Key)", + "value": { + "data": [ + { + "id": "ea_123", + "customer_id": "cust_123", + "account_type": "pix", + "currency": "brl", + "account_owner_name": "João Silva", + "bank_name": "Banco do Brasil", + "active": true, + "pix_key": { + "account_preview": "jo****ilva****il.c**", + "document_number_last4": "8901" + }, + "account_validation": { + "validated_account_owner_name": "João Silva", + "validated_bank_name": "Banco do Brasil" + }, + "account_owner_type": "individual", + "first_name": "João", + "last_name": "Silva", + "account_verification": { + "pix": { + "matched": true, + "reason_code": null, + "validated_account_owner_name": "João Silva", + "validated_bank_name": "Banco do Brasil" + }, + "requested_at": "2020-01-01T00:05:00.000Z", + "completed_at": "2020-01-01T00:05:05.000Z" + }, + "created_at": "2020-01-01T00:00:00.000Z", + "updated_at": "2020-01-02T00:00:00.000Z" + } + ] + } + }, + "ExternalAccountsFoundBrCode": { + "summary": "pix (BR Code)", + "value": { + "data": [ + { + "id": "ea_456", + "customer_id": "cust_456", + "account_type": "pix", + "currency": "brl", + "account_owner_name": "Maria Santos", + "bank_name": "Itaú Unibanco", + "active": true, + "br_code": { + "account_preview": "11****1111****1111****1111", + "document_number_last4": "0131" + }, + "account_validation": { + "validated_account_owner_name": "Maria Santos", + "validated_bank_name": "Itaú Unibanco" + }, + "account_owner_type": "individual", + "first_name": "Maria", + "last_name": "Santos", + "account_verification": { + "pix": { + "matched": true, + "reason_code": null, + "validated_account_owner_name": "Maria Santos", + "validated_bank_name": "Itaú Unibanco" + }, + "requested_at": "2020-01-01T00:05:00.000Z", + "completed_at": "2020-01-01T00:05:05.000Z" + }, + "created_at": "2020-01-01T00:00:00.000Z", + "updated_at": "2020-01-02T00:00:00.000Z" + } + ] + } + }, + "ExternalAccountsFoundClabe": { + "summary": "clabe", + "value": { + "data": [ + { + "id": "ea_567", + "customer_id": "cust_567", + "account_type": "clabe", + "currency": "mxn", + "account_owner_name": "Juan García", + "bank_name": "Banco Santander México", + "active": true, + "clabe": { + "last_4": "0007" + }, + "account_validation": { + "validated_account_owner_name": "Juan García", + "validated_bank_name": "Banco Santander México" + }, + "account_owner_type": "individual", + "first_name": "Juan", + "last_name": "García", + "account_verification": { + "clabe": { + "matched": true, + "reason_code": null, + "validated_account_owner_name": "Juan García", + "validated_bank_name": "Banco Santander México" + }, + "requested_at": "2020-01-01T00:05:00.000Z", + "completed_at": "2020-01-01T00:05:05.000Z" + }, + "created_at": "2020-01-01T00:00:00.000Z", + "updated_at": "2020-01-02T00:00:00.000Z" + } + ] + } + }, + "ExternalAccountsFoundBreB": { + "summary": "bre_b", + "value": { + "data": [ + { + "id": "ea_789", + "customer_id": "cust_789", + "account_type": "bre_b", + "currency": "cop", + "account_owner_name": "Juan Garcia", + "bank_name": "Banco de Bogota", + "active": true, + "account": { + "last_4": "0000" + }, + "account_validation": { + "validated_account_owner_name": "Juan Garcia", + "validated_bank_name": "Banco de Bogota", + "validated_document_number_last4": "0000" + }, + "account_owner_type": "individual", + "first_name": "Juan", + "last_name": "Garcia", + "account_verification": { + "bre_b": { + "matched": true, + "reason_code": null, + "validated_account_owner_name": "Juan Garcia", + "validated_bank_name": "Banco de Bogota", + "validated_document_number_last4": "0000" + }, + "requested_at": "2020-01-01T00:05:00.000Z", + "completed_at": "2020-01-01T00:05:05.000Z" + }, + "created_at": "2020-01-01T00:00:00.000Z", + "updated_at": "2020-01-02T00:00:00.000Z" + } + ] + } + }, + "ExternalAccountsFoundCoBankTransfer": { + "summary": "co_bank_transfer", + "value": { + "data": [ + { + "id": "ea_012", + "customer_id": "cust_012", + "account_type": "co_bank_transfer", + "currency": "cop", + "account_owner_name": "Maria Lopez", + "bank_name": "Bancolombia", + "active": true, + "account": { + "last_4": "1234", + "routing_number": "1007" + }, + "account_owner_type": "individual", + "first_name": "Maria", + "last_name": "Lopez", + "account_verification": { + "co_bank_transfer": { + "matched": true, + "reason_code": null, + "validated_account_owner_name": "Maria Lopez", + "validated_bank_name": "Bancolombia", + "validated_document_number_last4": "9012" + }, + "requested_at": "2020-01-01T00:05:00.000Z", + "completed_at": "2020-01-01T00:05:05.000Z" + }, + "created_at": "2020-01-01T00:00:00.000Z", + "updated_at": "2020-01-02T00:00:00.000Z" + } + ] + } + }, + "NoExternalAccountsFound": { + "summary": "An empty list of External Accounts", + "value": { + "data": [], + "count": 0 + } + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + }, + "post": { + "summary": "Create a new External Account", + "tags": [ + "External Accounts" + ], + "description": "_Note_: If adding US external accounts, we recommend reading through the US Beneficiary Address Validation doc ([link](https://apidocs.bridge.xyz/docs/us-beneficiary-address-validation)) to avoid issues related to incorrect addresses.\n", + "parameters": [ + { + "$ref": "#/components/parameters/IdempotencyKeyParameter" + } + ], + "requestBody": { + "description": "New External Account object to be created", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateExternalAccountInput" + }, + "examples": { + "ACH": { + "$ref": "#/components/examples/CreateAchExternalAccountRequest" + }, + "IBAN": { + "$ref": "#/components/examples/CreateIbanExternalAccountRequest" + }, + "CLABE": { + "$ref": "#/components/examples/CreateClabeExternalAccountRequest" + }, + "Pix_Key": { + "$ref": "#/components/examples/CreatePixExternalAccountRequest" + }, + "Pix_BrCode": { + "$ref": "#/components/examples/CreateBrCodeExternalAccountRequest" + }, + "BreB": { + "$ref": "#/components/examples/CreateBreBExternalAccountRequest" + }, + "CO_Bank_Transfer": { + "$ref": "#/components/examples/CreateCoBankTransferExternalAccountRequest" + } + } + } + } + }, + "responses": { + "201": { + "description": "External Account object created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExternalAccountResponse" + }, + "examples": { + "ACH": { + "$ref": "#/components/examples/SuccessfulExternalAccountResponse" + }, + "IBAN": { + "$ref": "#/components/examples/SuccessfulIbanExternalAccountResponse" + }, + "CLABE": { + "$ref": "#/components/examples/SuccessfulClabeExternalAccountResponse" + }, + "Pix_Key": { + "$ref": "#/components/examples/SuccessfulPixKeyExternalAccountResponse" + }, + "Pix_BrCode": { + "$ref": "#/components/examples/SuccessfulBrCodeExternalAccountResponse" + }, + "BreB": { + "$ref": "#/components/examples/SuccessfulBreBExternalAccountResponse" + }, + "CO_Bank_Transfer": { + "$ref": "#/components/examples/SuccessfulCoBankTransferExternalAccountResponse" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/customers/{customerID}/external_accounts/{externalAccountID}": { + "parameters": [ + { + "$ref": "#/components/parameters/CustomerIDParameter" + }, + { + "$ref": "#/components/parameters/ExternalAccountIDParameter" + } + ], + "get": { + "summary": "Retrieve an External Account object", + "description": "Retrieve an External Account object (banks, debit cards etc) from the passed in customer ID and External Account ID", + "tags": [ + "External Accounts" + ], + "responses": { + "200": { + "description": "Successful External Account object response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExternalAccountResponse" + }, + "examples": { + "SuccessfulExternalAccountResponse": { + "$ref": "#/components/examples/SuccessfulExternalAccountResponse" + }, + "SuccessfulIbanExternalAccountResponse": { + "$ref": "#/components/examples/SuccessfulIbanExternalAccountResponse" + }, + "SuccessfulPixKeyExternalAccountResponse": { + "$ref": "#/components/examples/SuccessfulPixKeyExternalAccountResponse" + }, + "SuccessfulBrCodeExternalAccountResponse": { + "$ref": "#/components/examples/SuccessfulBrCodeExternalAccountResponse" + }, + "SuccessfulClabeExternalAccountResponse": { + "$ref": "#/components/examples/SuccessfulClabeExternalAccountResponse" + }, + "SuccessfulBreBExternalAccountResponse": { + "$ref": "#/components/examples/SuccessfulBreBExternalAccountResponse" + }, + "SuccessfulCoBankTransferExternalAccountResponse": { + "$ref": "#/components/examples/SuccessfulCoBankTransferExternalAccountResponse" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "404": { + "$ref": "#/components/responses/NotFoundError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + }, + "put": { + "summary": "Update an External Account", + "tags": [ + "External Accounts" + ], + "requestBody": { + "description": "External Account details to be updated", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateExternalAccountInput" + } + } + } + }, + "responses": { + "200": { + "description": "External Account object updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExternalAccountResponse" + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "400": { + "$ref": "#/components/responses/BadExternalAccountUpdateError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + }, + "delete": { + "summary": "Delete a single External Account object", + "tags": [ + "External Accounts" + ], + "description": "Delete an External Account object from the passed in External Account ID", + "responses": { + "200": { + "description": "Successfully deleted External Account object response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExternalAccountResponse" + }, + "examples": { + "DeletedExternalAccountResponse": { + "$ref": "#/components/examples/SuccessfulExternalAccountResponse" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "404": { + "$ref": "#/components/responses/NotFoundError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/customers/{customerID}/associated_persons": { + "parameters": [ + { + "$ref": "#/components/parameters/CustomerIDParameter" + } + ], + "get": { + "summary": "Get associated persons for a business customer", + "tags": [ + "Customers" + ], + "description": "Get all associated persons for a business customer.", + "responses": { + "200": { + "description": "List of associated persons (the returned list is empty if none found)", + "content": { + "application/json": { + "schema": { + "title": "AssociatedPersonsList", + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "type": "array", + "minItems": 0, + "items": { + "$ref": "#/components/schemas/AssociatedPersonResponse" + } + } + } + }, + "examples": { + "AssociatedPersonsFound": { + "summary": "A non-empty list of associated persons", + "value": { + "data": [ + { + "id": "associated_person_1234567890", + "email": "associated_person@example.com", + "first_name": "John", + "last_name": "Smith", + "has_ownership": true, + "has_control": true, + "is_signer": true, + "title": "Chief Executive Officer", + "relationship_established_at": "2025-05-27T17:55:33.308Z", + "created_at": "2025-05-27T17:55:33.308Z", + "updated_at": "2025-05-27T17:55:33.308Z" + } + ] + } + }, + "NoAssociatedPersonsFound": { + "summary": "An empty list of associated persons", + "value": { + "data": [] + } + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "404": { + "$ref": "#/components/responses/NotFoundError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + }, + "post": { + "summary": "Create a new associated person for a business customer", + "tags": [ + "Customers" + ], + "parameters": [ + { + "$ref": "#/components/parameters/IdempotencyKeyParameter" + } + ], + "requestBody": { + "description": "New associated person to be created", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AssociatedPerson" + } + } + } + }, + "responses": { + "201": { + "description": "Associated person created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AssociatedPersonResponse" + }, + "examples": { + "SuccessfulAssociatedPersonResponse": { + "$ref": "#/components/examples/SuccessfulAssociatedPersonResponse" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "404": { + "$ref": "#/components/responses/NotFoundError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/customers/{customerID}/associated_persons/{associatedPersonID}": { + "parameters": [ + { + "$ref": "#/components/parameters/CustomerIDParameter" + }, + { + "$ref": "#/components/parameters/AssociatedPersonIDParameter" + } + ], + "get": { + "summary": "Get a single associated person", + "tags": [ + "Customers" + ], + "description": "Retrieve an associated person by ID", + "responses": { + "200": { + "description": "Successful associated person response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AssociatedPersonResponse" + }, + "examples": { + "SuccessfulAssociatedPersonResponse": { + "$ref": "#/components/examples/SuccessfulAssociatedPersonResponse" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "404": { + "$ref": "#/components/responses/NotFoundError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + }, + "put": { + "summary": "Update a single associated person", + "tags": [ + "Customers" + ], + "requestBody": { + "description": "Associated person data to update", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AssociatedPerson" + } + } + } + }, + "responses": { + "200": { + "description": "Updated associated person", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AssociatedPersonResponse" + }, + "examples": { + "SuccessfulAssociatedPersonResponse": { + "$ref": "#/components/examples/SuccessfulAssociatedPersonResponse" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "404": { + "$ref": "#/components/responses/NotFoundError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + }, + "delete": { + "summary": "Delete a single associated person", + "tags": [ + "Customers" + ], + "description": "Delete an associated person by ID", + "responses": { + "200": { + "description": "Successfully deleted associated person", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AssociatedPersonResponse" + }, + "examples": { + "SuccessfulAssociatedPersonResponse": { + "$ref": "#/components/examples/SuccessfulAssociatedPersonResponse" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "404": { + "$ref": "#/components/responses/NotFoundError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/customers/{customerID}/fiat_payout_configuration": { + "parameters": [ + { + "$ref": "#/components/parameters/CustomerIDParameter" + } + ], + "get": { + "summary": "Get the fiat payout configuration for a customer", + "tags": [ + "Fiat Payout Configuration" + ], + "description": "Retrieve the fiat payout configuration for the given customer ID. This configuration determines which payout method (bridge, developer, payment_provider, or customer) is used for each currency and payment rail combination.\n\nThe configuration is a nested hash structure where:\n- Top-level keys are currency codes (e.g., \"usd\", \"eur\", \"brl\", \"mxn\")\n- Second-level keys are payment rail codes (e.g., \"wire\", \"ach\", \"sepa\", \"pix\", \"spei\")\n- Values are payout names: `bridge`, `developer`, `payment_provider`, or `customer`\n\nCurrently, only the following values are supported for the payout method:\n- usd.wire: `developer`, `customer`\n- usd.ach: `bridge`\n- eur.sepa: `bridge`\n- brl.pix: `payment_provider`\n- mxn.spei: `payment_provider`\n", + "responses": { + "200": { + "description": "Successful fiat payout configuration response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FiatPayoutConfigurationResponse" + }, + "examples": { + "SuccessfulFiatPayoutConfigurationResponse": { + "$ref": "#/components/examples/SuccessfulFiatPayoutConfigurationResponse" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "404": { + "$ref": "#/components/responses/NotFoundError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + }, + "patch": { + "summary": "Update the fiat payout configuration for a customer", + "tags": [ + "Fiat Payout Configuration" + ], + "description": "Update the fiat payout configuration for the given customer ID. This configuration determines which payout method (bridge, developer, payment_provider, or customer) is used for each currency and payment rail combination.\n\nThe configuration is a nested hash structure where:\n- Top-level keys are currency codes (e.g., \"usd\", \"eur\", \"brl\", \"mxn\")\n- Second-level keys are payment rail codes (e.g., \"wire\", \"ach\", \"sepa\", \"pix\", \"spei\")\n- Values are payout names: `bridge`, `developer`, `payment_provider`, or `customer`\n\nCurrently, only the following values are supported for the payout method:\n- usd.wire: `developer`, `customer`\n- usd.ach: `bridge`\n- eur.sepa: `bridge`\n- brl.pix: `payment_provider`\n- mxn.spei: `payment_provider`\n\nOnly the currency/payment rail combinations provided will be updated. Other existing configurations will remain unchanged.\n", + "requestBody": { + "description": "Fiat payout configuration to update", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PatchFiatPayoutConfigurationInput" + } + } + } + }, + "responses": { + "200": { + "description": "Successful fiat payout configuration update response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FiatPayoutConfigurationResponse" + }, + "examples": { + "SuccessfulPatchFiatPayoutConfigurationResponse": { + "$ref": "#/components/examples/SuccessfulPatchFiatPayoutConfigurationResponse" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "403": { + "description": "Request not allowed. Contact your account manager to be enabled for this feature. Additional fees apply.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "404": { + "$ref": "#/components/responses/NotFoundError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/customers/{customerID}/external_accounts/{externalAccountID}/deactivate": { + "post": { + "summary": "Deactivate an External Account", + "description": "Deactivate an active External Account. The External Account is preserved and can be reactivated later via the reactivate endpoint.", + "tags": [ + "External Accounts" + ], + "parameters": [ + { + "$ref": "#/components/parameters/IdempotencyKeyParameter" + }, + { + "$ref": "#/components/parameters/CustomerIDParameter" + }, + { + "$ref": "#/components/parameters/ExternalAccountIDParameter" + } + ], + "responses": { + "200": { + "description": "Deactivated External Account object", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExternalAccountResponse" + }, + "examples": { + "DeactivatedExternalAccountResponse": { + "$ref": "#/components/examples/SuccessfulExternalAccountResponse" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "404": { + "$ref": "#/components/responses/NotFoundError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/customers/{customerID}/external_accounts/{externalAccountID}/verify": { + "post": { + "summary": "Verify an External Account", + "description": "Trigger a verification check for an external account. Verifies that the `account_owner_name` matches the actual account holder at the receiving bank.\n\nSupported for `iban` (EUR), `gb` (GBP), `pix` (BRL), `clabe` (MXN), `bre_b` (COP), and `co_bank_transfer` (COP, PSE) account types only. Does not require an Idempotency-Key header.\n\nAfter triggering, poll the external account's `account_verification` field until `completed_at` is populated.\n", + "tags": [ + "External Accounts" + ], + "parameters": [ + { + "$ref": "#/components/parameters/CustomerIDParameter" + }, + { + "$ref": "#/components/parameters/ExternalAccountIDParameter" + } + ], + "responses": { + "200": { + "description": "Verification initiated successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "account_type": { + "type": "string", + "enum": [ + "iban", + "gb", + "pix", + "clabe", + "bre_b", + "co_bank_transfer" + ], + "description": "The account type that was verified." + }, + "account_verification": { + "$ref": "#/components/schemas/AccountVerification" + } + } + }, + "examples": { + "PendingIbanVerification": { + "summary": "iban", + "value": { + "account_type": "iban", + "account_verification": { + "iban": { + "match_level": "pending", + "reason_code": null, + "validated_account_owner_name": null + }, + "requested_at": "2026-01-15T12:00:00.000Z", + "completed_at": null + } + } + }, + "PendingGbVerification": { + "summary": "gb", + "value": { + "account_type": "gb", + "account_verification": { + "gb": { + "match_level": "pending", + "reason_code": null, + "validated_account_owner_name": null + }, + "requested_at": "2026-01-15T12:00:00.000Z", + "completed_at": null + } + } + }, + "PendingPixVerification": { + "summary": "pix", + "value": { + "account_type": "pix", + "account_verification": { + "pix": { + "matched": null, + "reason_code": null, + "validated_account_owner_name": null, + "validated_bank_name": null + }, + "requested_at": "2026-01-15T12:00:00.000Z", + "completed_at": null + } + } + }, + "PendingClabeVerification": { + "summary": "clabe", + "value": { + "account_type": "clabe", + "account_verification": { + "clabe": { + "matched": null, + "reason_code": null, + "validated_account_owner_name": null, + "validated_bank_name": null + }, + "requested_at": "2026-01-15T12:00:00.000Z", + "completed_at": null + } + } + }, + "PendingBreBVerification": { + "summary": "bre_b", + "value": { + "account_type": "bre_b", + "account_verification": { + "bre_b": { + "matched": null, + "reason_code": null, + "validated_account_owner_name": null, + "validated_bank_name": null, + "validated_document_number_last4": null + }, + "requested_at": "2026-01-15T12:00:00.000Z", + "completed_at": null + } + } + }, + "PendingCoBankTransferVerification": { + "summary": "co_bank_transfer", + "value": { + "account_type": "co_bank_transfer", + "account_verification": { + "co_bank_transfer": { + "matched": null, + "reason_code": null, + "validated_account_owner_name": null, + "validated_bank_name": null, + "validated_document_number_last4": null + }, + "requested_at": "2026-01-15T12:00:00.000Z", + "completed_at": null + } + } + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "404": { + "$ref": "#/components/responses/NotFoundError" + }, + "409": { + "description": "A verification is already in progress for this external account", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/customers/{customerID}/external_accounts/{externalAccountID}/reactivate": { + "post": { + "summary": "Reactivate an External Account", + "description": "Reactivate a previously deactivated External Account", + "tags": [ + "External Accounts" + ], + "parameters": [ + { + "$ref": "#/components/parameters/IdempotencyKeyParameter" + }, + { + "$ref": "#/components/parameters/CustomerIDParameter" + }, + { + "$ref": "#/components/parameters/ExternalAccountIDParameter" + } + ], + "responses": { + "200": { + "description": "Reactivated External Account object", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExternalAccountResponse" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadExternalAccountReactivateError" + } + } + } + }, + "/customers/{customerID}/tos_acceptance_link": { + "get": { + "summary": "Retrieve a hosted URL for ToS acceptance for an existing customer", + "tags": [ + "Customers" + ], + "description": "The page at the returned URL will guide the user through the Bridge Terms of Service (ToS) acceptance flow. This can be used by existing customers to accept a new version of the ToS.", + "parameters": [ + { + "$ref": "#/components/parameters/CustomerIDParameter" + } + ], + "responses": { + "200": { + "description": "A Hosted URL for ToS acceptance", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "A hosted URL for ToS acceptance" + } + } + }, + "examples": { + "TosAcceptanceLink": { + "summary": "A sample ToS acceptance link", + "value": { + "url": "https://compliance.bridge.xyz/accept-terms-of-service?email=sage%40blick-mayer.example&t=74ea7c13-2b52-5073-bd12-6879f92b88dd" + } + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/customers/{customerID}/kyc_link": { + "get": { + "summary": "Retrieve a hosted KYC Link for an existing customer", + "tags": [ + "Customers" + ], + "description": "The page at the returned URL will guide the user through a Bridge KYC flow. This can be used by existing customers to provide additional KYC information required for certain features or services that Bridge offers.\n\nFor example, to enable an existing customer to use the `SEPA`/`Euro` services, they are required to provide `proof of address`. An additional parameter, `endorsement=sepa`, can be included to request a KYC link specifically for this purpose", + "parameters": [ + { + "$ref": "#/components/parameters/CustomerIDParameter" + }, + { + "$ref": "#/components/parameters/EndorsementParameter" + }, + { + "$ref": "#/components/parameters/RedirectUriParameter" + } + ], + "responses": { + "200": { + "description": "A Hosted URL for KYC", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "A hosted KYC link" + } + } + }, + "examples": { + "KycLink": { + "summary": "A sample KYC link", + "value": { + "url": "https://bridge.withpersona.com/verify?inquiry-template-id=itmpl_NtIXpb9AbEYCPxGo5iRbc9d2&reference-id=75d2f259-6810-4cde-a9b9-83eca42b0ebf" + } + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/customers/{customerID}/transfers": { + "parameters": [ + { + "$ref": "#/components/parameters/CustomerIDParameter" + }, + { + "$ref": "#/components/parameters/LimitParameter" + }, + { + "$ref": "#/components/parameters/TransferStartingAfterParameter" + }, + { + "$ref": "#/components/parameters/TransferEndingBeforeParameter" + }, + { + "$ref": "#/components/parameters/TxHashParameter" + }, + { + "$ref": "#/components/parameters/UpdatedAfterMsParameter" + }, + { + "$ref": "#/components/parameters/UpdatedBeforeMsParameter" + }, + { + "$ref": "#/components/parameters/TransferStateParameter" + } + ], + "get": { + "summary": "Get all transfers", + "tags": [ + "Customers" + ], + "description": "Get all active and completed transfers for a customer.", + "responses": { + "200": { + "description": "List of transfers (the returned list is empty if none found)", + "content": { + "application/json": { + "schema": { + "title": "Transfers", + "type": "object", + "required": [ + "count", + "data" + ], + "properties": { + "count": { + "type": "integer", + "description": "The number of transfers returned" + }, + "data": { + "type": "array", + "minItems": 0, + "items": { + "$ref": "#/components/schemas/TransferResponse" + } + } + } + }, + "examples": { + "TransfersFound": { + "summary": "A non-empty list of transfers", + "value": { + "count": 2, + "data": [ + { + "id": "00000000-0000-0000-0000-000000000004", + "client_reference_id": "client_transfer_id_456", + "state": "funds_received", + "on_behalf_of": "00000000-0000-0000-0000-000000000001", + "amount": "500.25", + "developer_fee": "0.0", + "source": { + "payment_rail": "ach", + "currency": "usd", + "external_account_id": "00000000-0000-0000-0000-000000000002" + }, + "destination": { + "payment_rail": "ethereum", + "currency": "usdc", + "to_address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F" + }, + "receipt": { + "initial_amount": "500.25", + "developer_fee": "0.0", + "exchange_fee": "0.0", + "subtotal_amount": "500.25", + "gas_fee": "0.0", + "final_amount": "500.25", + "destination_tx_hash": "0xdeadbeef", + "url": "https://dashboard.bridge.xyz/transaction/00000000-0000-0000-0000-000000000000/receipt/00000000-0000-0000-0000-000000000000" + }, + "created_at": "2020-01-02T00:00:00.000Z", + "updated_at": "2020-01-03T00:00:00.000Z" + }, + { + "id": "00000000-0000-0000-0000-000000000003", + "client_reference_id": "client_transfer_id_123", + "state": "awaiting_funds", + "on_behalf_of": "00000000-0000-0000-0000-000000000001", + "amount": "75.0", + "developer_fee": "0.0", + "source": { + "payment_rail": "ethereum", + "currency": "usdc", + "from_address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F" + }, + "destination": { + "payment_rail": "ach", + "currency": "usd", + "external_account_id": "00000000-0000-0000-0000-000000000002" + }, + "source_deposit_instructions": { + "payment_rail": "ethereum", + "amount": "75.0", + "currency": "usdc", + "from_address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F", + "to_address": "0xb794f5ea0ba39494ce839613fffba74279579268" + }, + "receipt": { + "initial_amount": "75.0", + "developer_fee": "0.0", + "exchange_fee": "0.0", + "subtotal_amount": "75.0", + "gas_fee": "0.0", + "final_amount": "75.0", + "url": "https://dashboard.bridge.xyz/transaction/00000000-0000-0000-0000-000000000000/receipt/00000000-0000-0000-0000-000000000000" + }, + "created_at": "2020-01-01T00:00:00.000Z", + "updated_at": "2020-01-02T00:00:00.000Z" + } + ] + } + }, + "NoTransfersFound": { + "summary": "An empty list of transfers", + "value": { + "count": 0, + "data": [] + } + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/customers/{customerID}/transfers/static_templates": { + "parameters": [ + { + "$ref": "#/components/parameters/CustomerIDParameter" + }, + { + "$ref": "#/components/parameters/LimitParameter" + }, + { + "$ref": "#/components/parameters/TransferStartingAfterParameter" + }, + { + "$ref": "#/components/parameters/TransferEndingBeforeParameter" + } + ], + "get": { + "summary": "Get all static templates for a customer", + "tags": [ + "Customers" + ], + "description": "Get all static templates for a customer. Static templates are transfers that are used as templates for other transfers and can be created using the static_templates feature flag.", + "responses": { + "200": { + "description": "List of static templates (the returned list is empty if none found)", + "content": { + "application/json": { + "schema": { + "title": "Static Templates", + "type": "object", + "required": [ + "count", + "data" + ], + "properties": { + "count": { + "type": "integer", + "description": "The number of static templates returned" + }, + "data": { + "type": "array", + "minItems": 0, + "items": { + "$ref": "#/components/schemas/TransferResponse" + } + } + } + }, + "examples": { + "StaticTemplatesFound": { + "summary": "A non-empty list of static templates", + "value": { + "count": 2, + "data": [ + { + "id": "00000000-0000-0000-0000-000000000004", + "client_reference_id": "client_transfer_id_456", + "state": "funds_received", + "on_behalf_of": "00000000-0000-0000-0000-000000000001", + "amount": "500.25", + "developer_fee": "0.0", + "source": { + "payment_rail": "ach", + "currency": "usd", + "external_account_id": "00000000-0000-0000-0000-000000000002" + }, + "destination": { + "payment_rail": "ethereum", + "currency": "usdc", + "to_address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F" + }, + "receipt": { + "initial_amount": "500.25", + "developer_fee": "0.0", + "exchange_fee": "0.0", + "subtotal_amount": "500.25", + "gas_fee": "0.0", + "final_amount": "500.25", + "destination_tx_hash": "0xdeadbeef", + "url": "https://dashboard.bridge.xyz/transaction/00000000-0000-0000-0000-000000000000/receipt/00000000-0000-0000-0000-000000000000" + }, + "created_at": "2020-01-02T00:00:00.000Z", + "updated_at": "2020-01-03T00:00:00.000Z" + }, + { + "id": "00000000-0000-0000-0000-000000000003", + "client_reference_id": "client_transfer_id_123", + "state": "awaiting_funds", + "on_behalf_of": "00000000-0000-0000-0000-000000000001", + "amount": "75.0", + "developer_fee": "0.0", + "source": { + "payment_rail": "ethereum", + "currency": "usdc", + "from_address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F" + }, + "destination": { + "payment_rail": "ach", + "currency": "usd", + "external_account_id": "00000000-0000-0000-0000-000000000002" + }, + "source_deposit_instructions": { + "payment_rail": "ethereum", + "amount": "75.0", + "currency": "usdc", + "from_address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F", + "to_address": "0xb794f5ea0ba39494ce839613fffba74279579268" + }, + "receipt": { + "initial_amount": "75.0", + "developer_fee": "0.0", + "exchange_fee": "0.0", + "subtotal_amount": "75.0", + "gas_fee": "0.0", + "final_amount": "75.0", + "url": "https://dashboard.bridge.xyz/transaction/00000000-0000-0000-0000-000000000000/receipt/00000000-0000-0000-0000-000000000000" + }, + "created_at": "2020-01-01T00:00:00.000Z", + "updated_at": "2020-01-02T00:00:00.000Z" + } + ] + } + }, + "NoStaticTemplatesFound": { + "summary": "An empty list of static templates", + "value": { + "count": 0, + "data": [] + } + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "404": { + "$ref": "#/components/responses/NotFoundError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/customers/tos_links": { + "post": { + "summary": "Request a hosted URL for ToS acceptance for new customer creation", + "tags": [ + "Customers" + ], + "parameters": [ + { + "$ref": "#/components/parameters/IdempotencyKeyParameter" + } + ], + "description": "The URL endpoint returned will guide the user through a Bridge TOS flow. Signing this acceptance flow is a requirement for creating customers.", + "responses": { + "201": { + "description": "A Bridge hosted URL for users to complete terms of service signing.", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "A Bridge hosted URL for users to complete terms of service signing." + } + } + }, + "examples": { + "TosUrl": { + "summary": "A sample Bridge hosted URL", + "value": { + "data": { + "url": "https://compliance.bridge.xyz/accept-terms-of-service?session_token=4d5d8c45-9feb-422a-bb5e-0fd32e3b3c53&redirect_uri=https%3A%2F%2Fgoogle.com" + } + } + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/customers/{customerID}/plaid_link_requests": { + "post": { + "summary": "Generate a Plaid Link token for a customer", + "tags": [ + "Plaid" + ], + "parameters": [ + { + "$ref": "#/components/parameters/IdempotencyKeyParameter" + }, + { + "$ref": "#/components/parameters/CustomerIDParameter" + } + ], + "responses": { + "201": { + "description": "Plaid Link token generated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PlaidLinkRequest" + }, + "examples": { + "PlaidLinkRequestSuccessResponse": { + "$ref": "#/components/examples/PlaidLinkRequestSuccessResponse" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/plaid_exchange_public_token/{link_token}": { + "post": { + "summary": "Exchange Plaid public token for an access token", + "tags": [ + "Plaid" + ], + "parameters": [ + { + "name": "link_token", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Plaid Link token" + } + ], + "requestBody": { + "description": "Plaid public token to be exchanged", + "required": true, + "content": { + "application/json": { + "schema": { + "required": [ + "id", + "type" + ], + "$ref": "#/components/schemas/PlaidExchangePublicToken" + } + } + } + }, + "responses": { + "201": { + "description": "Plaid public token exchanged", + "content": { + "application/json": { + "schema": { + "title": "Plaid public token exchanged", + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Message indicating the status of the request" + } + } + }, + "examples": { + "PlaidExchangePublicTokenSuccessResponse": { + "$ref": "#/components/examples/PlaidExchangePublicTokenSuccessResponse" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/transfers": { + "get": { + "summary": "Get all transfers", + "tags": [ + "Transfers" + ], + "parameters": [ + { + "$ref": "#/components/parameters/LimitParameter" + }, + { + "$ref": "#/components/parameters/TransferStartingAfterParameter" + }, + { + "$ref": "#/components/parameters/TransferEndingBeforeParameter" + }, + { + "$ref": "#/components/parameters/TxHashParameter" + }, + { + "$ref": "#/components/parameters/UpdatedAfterMsParameter" + }, + { + "$ref": "#/components/parameters/UpdatedBeforeMsParameter" + }, + { + "$ref": "#/components/parameters/TemplateIDParameter" + }, + { + "$ref": "#/components/parameters/TransferStateParameter" + } + ], + "responses": { + "200": { + "description": "List of transfers (the returned list is empty if none found)", + "content": { + "application/json": { + "schema": { + "title": "Transfers", + "type": "object", + "required": [ + "count", + "data" + ], + "properties": { + "count": { + "type": "integer", + "description": "The number of transfers returned" + }, + "data": { + "type": "array", + "minItems": 0, + "items": { + "$ref": "#/components/schemas/TransferResponse" + } + } + } + }, + "examples": { + "TransfersFound": { + "summary": "A non-empty list of transfers", + "value": { + "count": 2, + "data": [ + { + "id": "00000000-0000-0000-0000-000000000004", + "client_reference_id": "client_transfer_id_456", + "state": "funds_received", + "on_behalf_of": "00000000-0000-0000-0000-000000000001", + "amount": "500.25", + "developer_fee": "0.0", + "source": { + "payment_rail": "ach", + "currency": "usd", + "external_account_id": "00000000-0000-0000-0000-000000000002" + }, + "destination": { + "payment_rail": "ethereum", + "currency": "usdc", + "to_address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F" + }, + "receipt": { + "initial_amount": "500.25", + "developer_fee": "0.0", + "exchange_fee": "0.0", + "subtotal_amount": "500.25", + "gas_fee": "0.0", + "final_amount": "500.25", + "destination_tx_hash": "0xdeadbeef", + "url": "https://dashboard.bridge.xyz/transaction/00000000-0000-0000-0000-000000000000/receipt/00000000-0000-0000-0000-000000000000" + }, + "created_at": "2020-01-02T00:00:00.000Z", + "updated_at": "2020-01-03T00:00:00.000Z" + }, + { + "id": "00000000-0000-0000-0000-000000000003", + "client_reference_id": "client_transfer_id_123", + "state": "awaiting_funds", + "on_behalf_of": "00000000-0000-0000-0000-000000000001", + "amount": "75.0", + "developer_fee": "0.0", + "source": { + "payment_rail": "ethereum", + "currency": "usdc", + "from_address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F" + }, + "destination": { + "payment_rail": "ach", + "currency": "usd", + "external_account_id": "00000000-0000-0000-0000-000000000002" + }, + "source_deposit_instructions": { + "payment_rail": "ethereum", + "amount": "75.0", + "currency": "usdc", + "from_address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F", + "to_address": "0xb794f5ea0ba39494ce839613fffba74279579268" + }, + "receipt": { + "initial_amount": "75.0", + "developer_fee": "0.0", + "exchange_fee": "0.0", + "subtotal_amount": "75.0", + "gas_fee": "0.0", + "final_amount": "75.0", + "url": "https://dashboard.bridge.xyz/transaction/00000000-0000-0000-0000-000000000000/receipt/00000000-0000-0000-0000-000000000000" + }, + "created_at": "2020-01-01T00:00:00.000Z", + "updated_at": "2020-01-02T00:00:00.000Z" + } + ] + } + }, + "NoTransfersFound": { + "summary": "An empty list of transfers", + "value": { + "count": 0, + "data": [] + } + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + }, + "post": { + "summary": "Create a transfer", + "description": "Create a transfer.\n\nIf this transfer cannot be created because the funding source is temporarily busy processing another update, this endpoint may return `409 resource_state_conflict`.\nThis is a transient, retryable response. You may safely retry the same request with the same `Idempotency-Key`.\n", + "tags": [ + "Transfers" + ], + "parameters": [ + { + "$ref": "#/components/parameters/IdempotencyKeyParameter" + } + ], + "requestBody": { + "description": "Transfer object to be created", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TransferRequest" + } + } + } + }, + "responses": { + "201": { + "description": "Transfer object created", + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/TransferResponse" + }, + { + "$ref": "#/components/schemas/TransferRouteResponse" + } + ] + }, + "examples": { + "AchOnrampTransferResponse": { + "$ref": "#/components/examples/AchOnrampTransferResponse" + }, + "AchOfframpTransferResponse": { + "$ref": "#/components/examples/AchOfframpTransferResponse" + }, + "AchOfframpWithMemoTransferResponse": { + "$ref": "#/components/examples/AchOfframpWithMemoTransferResponse" + }, + "WireOnrampTransferResponse": { + "$ref": "#/components/examples/WireOnrampTransferResponse" + }, + "WireOfframpTransferResponse": { + "$ref": "#/components/examples/WireOfframpTransferResponse" + }, + "SepaOnrampTransferResponse": { + "$ref": "#/components/examples/SepaOnrampTransferResponse" + }, + "SepaOfframpTransferResponse": { + "$ref": "#/components/examples/SepaOfframpTransferResponse" + }, + "PixOnrampTransferResponse": { + "$ref": "#/components/examples/PixOnrampTransferResponse" + }, + "PixOfframpTransferResponse": { + "$ref": "#/components/examples/PixOfframpTransferResponse" + }, + "SpeiOnrampTransferResponse": { + "$ref": "#/components/examples/SpeiOnrampTransferResponse" + }, + "SpeiOfframpTransferResponse": { + "$ref": "#/components/examples/SpeiOfframpTransferResponse" + }, + "BreBOnrampTransferResponse": { + "$ref": "#/components/examples/BreBOnrampTransferResponse" + }, + "BreBOfframpTransferResponse": { + "$ref": "#/components/examples/BreBOfframpTransferResponse" + }, + "CoBankTransferOnrampTransferResponse": { + "$ref": "#/components/examples/CoBankTransferOnrampTransferResponse" + }, + "CoBankTransferOfframpTransferResponse": { + "$ref": "#/components/examples/CoBankTransferOfframpTransferResponse" + }, + "ValidTransferRouteResponse": { + "$ref": "#/components/examples/ValidTransferRouteResponse" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "409": { + "$ref": "#/components/responses/ResourceStateConflictError" + }, + "403": { + "$ref": "#/components/responses/TransferAmlError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/transfers/pending": { + "get": { + "summary": "List transfers with pending USDT trades", + "description": "Returns transfers that have a stuck USDT-to-USD trade awaiting execution. Results are sorted by creation time (newest first) and paginated.\n\nUse `POST /transfers/{transferID}/execute` to force-execute a pending trade at the current market rate.\n", + "tags": [ + "Transfers" + ], + "parameters": [ + { + "$ref": "#/components/parameters/LimitParameter" + }, + { + "$ref": "#/components/parameters/TransferStartingAfterParameter" + }, + { + "$ref": "#/components/parameters/TransferEndingBeforeParameter" + } + ], + "responses": { + "200": { + "description": "List of transfers with pending trades (the returned list is empty if none found)", + "content": { + "application/json": { + "schema": { + "title": "PendingTransfers", + "type": "object", + "required": [ + "count", + "data" + ], + "properties": { + "count": { + "type": "integer", + "description": "The number of transfers returned" + }, + "data": { + "type": "array", + "minItems": 0, + "items": { + "$ref": "#/components/schemas/TransferResponse" + } + } + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/transfers/{transferID}": { + "parameters": [ + { + "$ref": "#/components/parameters/TransferIDParameter" + } + ], + "get": { + "summary": "Get a transfer", + "description": "Retrieve a transfer object from the passed in transfer ID", + "tags": [ + "Transfers" + ], + "responses": { + "200": { + "description": "Successful transfer object response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TransferResponse" + }, + "examples": { + "AchOnrampTransferResponse": { + "$ref": "#/components/examples/AchOnrampTransferResponse" + }, + "AchOfframpTransferResponse": { + "$ref": "#/components/examples/AchOfframpTransferResponse" + }, + "AchOfframpWithMemoTransferResponse": { + "$ref": "#/components/examples/AchOfframpWithMemoTransferResponse" + }, + "WireOnrampTransferResponse": { + "$ref": "#/components/examples/WireOnrampTransferResponse" + }, + "WireOfframpTransferResponse": { + "$ref": "#/components/examples/WireOfframpTransferResponse" + }, + "SepaOnrampTransferResponse": { + "$ref": "#/components/examples/SepaOnrampTransferResponse" + }, + "SepaOfframpTransferResponse": { + "$ref": "#/components/examples/SepaOfframpTransferResponse" + }, + "PixOnrampTransferResponse": { + "$ref": "#/components/examples/PixOnrampTransferResponse" + }, + "PixOfframpTransferResponse": { + "$ref": "#/components/examples/PixOfframpTransferResponse" + }, + "SpeiOnrampTransferResponse": { + "$ref": "#/components/examples/SpeiOnrampTransferResponse" + }, + "SpeiOfframpTransferResponse": { + "$ref": "#/components/examples/SpeiOfframpTransferResponse" + }, + "BreBOnrampTransferResponse": { + "$ref": "#/components/examples/BreBOnrampTransferResponse" + }, + "BreBOfframpTransferResponse": { + "$ref": "#/components/examples/BreBOfframpTransferResponse" + }, + "CoBankTransferOnrampTransferResponse": { + "$ref": "#/components/examples/CoBankTransferOnrampTransferResponse" + }, + "CoBankTransferOfframpTransferResponse": { + "$ref": "#/components/examples/CoBankTransferOfframpTransferResponse" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "404": { + "$ref": "#/components/responses/NotFoundError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + }, + "put": { + "summary": "Update a transfer", + "description": "Update a transfer that was previously created. Must be in the awaiting_funds state.", + "tags": [ + "Transfers" + ], + "requestBody": { + "description": "Transfer object to be updated", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TransferUpdateRequest" + } + } + } + }, + "responses": { + "201": { + "description": "Transfer object created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TransferResponse" + }, + "examples": { + "AchOnrampTransferResponse": { + "$ref": "#/components/examples/AchOnrampTransferResponse" + }, + "AchOfframpTransferResponse": { + "$ref": "#/components/examples/AchOfframpTransferResponse" + }, + "AchOfframpWithMemoTransferResponse": { + "$ref": "#/components/examples/AchOfframpWithMemoTransferResponse" + }, + "WireOnrampTransferResponse": { + "$ref": "#/components/examples/WireOnrampTransferResponse" + }, + "WireOfframpTransferResponse": { + "$ref": "#/components/examples/WireOfframpTransferResponse" + }, + "SepaOnrampTransferResponse": { + "$ref": "#/components/examples/SepaOnrampTransferResponse" + }, + "SepaOfframpTransferResponse": { + "$ref": "#/components/examples/SepaOfframpTransferResponse" + }, + "PixOnrampTransferResponse": { + "$ref": "#/components/examples/PixOnrampTransferResponse" + }, + "PixOfframpTransferResponse": { + "$ref": "#/components/examples/PixOfframpTransferResponse" + }, + "SpeiOnrampTransferResponse": { + "$ref": "#/components/examples/SpeiOnrampTransferResponse" + }, + "SpeiOfframpTransferResponse": { + "$ref": "#/components/examples/SpeiOfframpTransferResponse" + }, + "BreBOnrampTransferResponse": { + "$ref": "#/components/examples/BreBOnrampTransferResponse" + }, + "BreBOfframpTransferResponse": { + "$ref": "#/components/examples/BreBOfframpTransferResponse" + }, + "CoBankTransferOnrampTransferResponse": { + "$ref": "#/components/examples/CoBankTransferOnrampTransferResponse" + }, + "CoBankTransferOfframpTransferResponse": { + "$ref": "#/components/examples/CoBankTransferOfframpTransferResponse" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "403": { + "$ref": "#/components/responses/TransferAmlError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + }, + "delete": { + "summary": "Delete a transfer", + "description": "Delete a transfer that was previously created. Must be in the awaiting_funds state.", + "tags": [ + "Transfers" + ], + "responses": { + "200": { + "description": "Successful deletion of transfer" + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "404": { + "$ref": "#/components/responses/NotFoundError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/transfers/{transferID}/execute": { + "parameters": [ + { + "$ref": "#/components/parameters/TransferIDParameter" + } + ], + "post": { + "summary": "Execute a pending USDT trade on a transfer", + "description": "Force-executes a stuck USDT-to-USD trade at the current market rate. The transfer must have a pending trade (i.e. appear in `GET /transfers/pending`).\n\nAfter execution, the transfer will continue processing normally with the executed market rate.\n", + "tags": [ + "Transfers" + ], + "parameters": [ + { + "$ref": "#/components/parameters/IdempotencyKeyParameter" + } + ], + "responses": { + "200": { + "description": "Transfer with trade execute at market rate enabled successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TransferResponse" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "404": { + "$ref": "#/components/responses/NotFoundError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/transfers/static_templates": { + "get": { + "summary": "Get all static templates", + "tags": [ + "Transfers" + ], + "parameters": [ + { + "$ref": "#/components/parameters/LimitParameter" + }, + { + "$ref": "#/components/parameters/TransferStartingAfterParameter" + }, + { + "$ref": "#/components/parameters/TransferEndingBeforeParameter" + } + ], + "responses": { + "200": { + "description": "List of static templates (the returned list is empty if none found). Static templates are transfers that are used as templates for other transfers and can be created using the static_templates feature flag.", + "content": { + "application/json": { + "schema": { + "title": "Static Templates", + "type": "object", + "required": [ + "count", + "data" + ], + "properties": { + "count": { + "type": "integer", + "description": "The number of static templates returned" + }, + "data": { + "type": "array", + "minItems": 0, + "items": { + "$ref": "#/components/schemas/TransferResponse" + } + } + } + }, + "examples": { + "TransfersFound": { + "summary": "A non-empty list of static templates", + "value": { + "count": 2, + "data": [ + { + "id": "00000000-0000-0000-0000-000000000004", + "client_reference_id": "client_transfer_id_456", + "state": "funds_received", + "on_behalf_of": "00000000-0000-0000-0000-000000000001", + "amount": "500.25", + "developer_fee": "0.0", + "source": { + "payment_rail": "ach", + "currency": "usd", + "external_account_id": "00000000-0000-0000-0000-000000000002" + }, + "destination": { + "payment_rail": "ethereum", + "currency": "usdc", + "to_address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F" + }, + "receipt": { + "initial_amount": "500.25", + "developer_fee": "0.0", + "exchange_fee": "0.0", + "subtotal_amount": "500.25", + "gas_fee": "0.0", + "final_amount": "500.25", + "destination_tx_hash": "0xdeadbeef", + "url": "https://dashboard.bridge.xyz/transaction/00000000-0000-0000-0000-000000000000/receipt/00000000-0000-0000-0000-000000000000" + }, + "created_at": "2020-01-02T00:00:00.000Z", + "updated_at": "2020-01-03T00:00:00.000Z" + }, + { + "id": "00000000-0000-0000-0000-000000000003", + "client_reference_id": "client_transfer_id_123", + "state": "awaiting_funds", + "on_behalf_of": "00000000-0000-0000-0000-000000000001", + "amount": "75.0", + "developer_fee": "0.0", + "source": { + "payment_rail": "ethereum", + "currency": "usdc", + "from_address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F" + }, + "destination": { + "payment_rail": "ach", + "currency": "usd", + "external_account_id": "00000000-0000-0000-0000-000000000002" + }, + "source_deposit_instructions": { + "payment_rail": "ethereum", + "amount": "75.0", + "currency": "usdc", + "from_address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F", + "to_address": "0xb794f5ea0ba39494ce839613fffba74279579268" + }, + "receipt": { + "initial_amount": "75.0", + "developer_fee": "0.0", + "exchange_fee": "0.0", + "subtotal_amount": "75.0", + "gas_fee": "0.0", + "final_amount": "75.0", + "url": "https://dashboard.bridge.xyz/transaction/00000000-0000-0000-0000-000000000000/receipt/00000000-0000-0000-0000-000000000000" + }, + "created_at": "2020-01-01T00:00:00.000Z", + "updated_at": "2020-01-02T00:00:00.000Z" + } + ] + } + }, + "NoTransfersFound": { + "summary": "An empty list of static templates", + "value": { + "count": 0, + "data": [] + } + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/prefunded_accounts": { + "get": { + "summary": "Get a list of all Prefunded Account", + "tags": [ + "Prefunded Accounts" + ], + "description": "Retrieve a all Prefunded Accounts", + "responses": { + "200": { + "description": "List of prefunded accounts.", + "content": { + "application/json": { + "schema": { + "title": "Prefunded Accounts", + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "type": "array", + "minItems": 0, + "items": { + "$ref": "#/components/schemas/PrefundedAccount" + } + } + } + }, + "examples": { + "PrefundedAccountsFound": { + "summary": "A non-empty list of prefunded accounts", + "value": { + "data": [ + { + "id": "f15972de-4cdd-460c-9da3-34f7321bfa3f", + "currency": "usd", + "available_balance": "134.12", + "name": "my_account", + "created_at": "2020-01-01T00:00:00.000Z", + "updated_at": "2020-01-02T00:00:00.000Z" + } + ] + } + }, + "NoPrefundedAccountsFound": { + "summary": "An empty list of prefunded accounts", + "value": { + "data": [] + } + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "404": { + "$ref": "#/components/responses/NotFoundError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/prefunded_accounts/{prefundedAccountID}": { + "parameters": [ + { + "$ref": "#/components/parameters/PrefundedAccountIDParameter" + } + ], + "get": { + "summary": "Get details for a specific Prefunded Account", + "tags": [ + "Prefunded Accounts" + ], + "description": "Retrieve a Prefunded Account", + "responses": { + "200": { + "description": "Successful Prefunded Account object response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PrefundedAccount" + }, + "examples": { + "SuccessfulPrefundedAccountResponse": { + "$ref": "#/components/examples/SuccessfulPrefundedAccountResponse" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "404": { + "$ref": "#/components/responses/NotFoundError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/prefunded_accounts/{prefundedAccountID}/history": { + "parameters": [ + { + "$ref": "#/components/parameters/PrefundedAccountIDParameter" + }, + { + "$ref": "#/components/parameters/LimitParameter" + }, + { + "$ref": "#/components/parameters/PrefundedAccountHistoryStartingAfterParameter" + }, + { + "$ref": "#/components/parameters/PrefundedAccountHistoryEndingBeforeParameter" + } + ], + "get": { + "summary": "Get funding history of a Prefunded Account", + "tags": [ + "Prefunded Accounts" + ], + "description": "Retrieve the funding events and returns for a Prefunded Account", + "responses": { + "200": { + "description": "Successful Prefunded Account object response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PrefundedAccountHistory" + }, + "examples": { + "SuccessfulCustomerResponse": { + "$ref": "#/components/examples/SuccessfulPrefundedAccountHistoryResponse" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "404": { + "$ref": "#/components/responses/NotFoundError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/customers/{customerID}/wallets": { + "get": { + "summary": "Get all Bridge Wallets for a customer", + "description": "List of Bridge Wallets for the specified Customer ID", + "tags": [ + "Bridge Wallets" + ], + "parameters": [ + { + "$ref": "#/components/parameters/CustomerIDParameter" + }, + { + "$ref": "#/components/parameters/LimitParameter" + }, + { + "$ref": "#/components/parameters/BridgeWalletStartingAfterParameter" + }, + { + "$ref": "#/components/parameters/BridgeWalletEndingBeforeParameter" + } + ], + "responses": { + "200": { + "description": "List of Bridge Wallets", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BridgeWalletsList" + }, + "examples": { + "SuccessfulBridgeWalletListResponse": { + "$ref": "#/components/examples/SuccessfulBridgeWalletListResponse" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "404": { + "$ref": "#/components/responses/NotFoundError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + }, + "post": { + "summary": "Create a Bridge Wallet", + "tags": [ + "Bridge Wallets" + ], + "parameters": [ + { + "$ref": "#/components/parameters/CustomerIDParameter" + }, + { + "$ref": "#/components/parameters/IdempotencyKeyParameter" + } + ], + "requestBody": { + "description": "Bridge Wallet to be created", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateBridgeWallet" + } + } + } + }, + "responses": { + "201": { + "description": "Bridge Wallet created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateBridgeWalletResponse" + }, + "examples": { + "SuccessfulLiquidationAddressCreateResponse": { + "$ref": "#/components/examples/SuccessfulBridgeWalletCreateResponse" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "404": { + "$ref": "#/components/responses/NotFoundError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/customers/{customerID}/wallets/{bridgeWalletID}": { + "get": { + "summary": "Get a Bridge Wallet", + "description": "Retrieve a Bridge Wallet for the specified Bridge Wallet ID", + "tags": [ + "Bridge Wallets" + ], + "parameters": [ + { + "$ref": "#/components/parameters/CustomerIDParameter" + }, + { + "$ref": "#/components/parameters/BridgeWalletIDParameter" + } + ], + "responses": { + "200": { + "description": "A Bridge Wallet object response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BridgeWalletWithBalances" + }, + "examples": { + "SuccessfulLiquidationAddressGetResponse": { + "$ref": "#/components/examples/SuccessfulBridgeWalletGetResponse" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "404": { + "$ref": "#/components/responses/NotFoundError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/customers/{customerID}/liquidation_addresses": { + "post": { + "summary": "Create a Liquidation Address", + "tags": [ + "Liquidation Addresses" + ], + "parameters": [ + { + "$ref": "#/components/parameters/CustomerIDParameter" + }, + { + "$ref": "#/components/parameters/IdempotencyKeyParameter" + } + ], + "requestBody": { + "description": "Liquidation Address object to be created", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateLiquidationAddress" + } + } + } + }, + "responses": { + "201": { + "description": "Liquidation Address object created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateLiquidationAddressResponse" + }, + "examples": { + "SuccessfulLiquidationAddressCreateResponse": { + "$ref": "#/components/examples/SuccessfulLiquidationAddressCreateResponse" + }, + "SuccessfulSepaLiquidationAddressCreateResponse": { + "$ref": "#/components/examples/SuccessfulSepaLiquidationAddressCreateResponse" + }, + "SuccessfulMultiChainLiquidationAddressCreateResponse": { + "$ref": "#/components/examples/SuccessfulMultiChainLiquidationAddressCreateResponse" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + }, + "get": { + "summary": "Get all Liquidation Addresses for a customer", + "description": "Get Liquidation Addresses", + "tags": [ + "Liquidation Addresses" + ], + "parameters": [ + { + "$ref": "#/components/parameters/CustomerIDParameter" + }, + { + "$ref": "#/components/parameters/LimitParameter" + }, + { + "$ref": "#/components/parameters/LiquidationScheduleStartingAfterParameter" + }, + { + "$ref": "#/components/parameters/LiquidationScheduleEndingBeforeParameter" + } + ], + "responses": { + "200": { + "description": "List of Liquidation Addresses (the returned list is empty if none found)", + "content": { + "application/json": { + "schema": { + "title": "Liquidation Addresses", + "type": "object", + "required": [ + "count", + "data" + ], + "properties": { + "count": { + "description": "total number of items in data", + "type": "integer" + }, + "data": { + "type": "array", + "minItems": 0, + "items": { + "$ref": "#/components/schemas/LiquidationAddress" + } + } + } + }, + "examples": { + "SuccessfulGetAllLiquidationAddressResponse": { + "$ref": "#/components/examples/SuccessfulGetAllLiquidationAddressResponse" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/liquidation_addresses": { + "get": { + "summary": "Get all Liquidation Addresses", + "description": "Get Liquidation Addresses", + "tags": [ + "Liquidation Addresses" + ], + "parameters": [ + { + "$ref": "#/components/parameters/LimitParameter" + }, + { + "$ref": "#/components/parameters/LiquidationScheduleStartingAfterParameter" + }, + { + "$ref": "#/components/parameters/LiquidationScheduleEndingBeforeParameter" + } + ], + "responses": { + "200": { + "description": "List of Liquidation Addresses (the returned list is empty if none found)", + "content": { + "application/json": { + "schema": { + "title": "Liquidation Addresses", + "type": "object", + "required": [ + "count", + "data" + ], + "properties": { + "count": { + "description": "total number of items in data", + "type": "integer" + }, + "data": { + "type": "array", + "minItems": 0, + "items": { + "$ref": "#/components/schemas/LiquidationAddress" + } + } + } + }, + "examples": { + "SuccessfulGetAllLiquidationAddressResponse": { + "$ref": "#/components/examples/SuccessfulGetAllLiquidationAddressResponse" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/customers/{customerID}/liquidation_addresses/{liquidationAddressID}": { + "get": { + "summary": "Get a Liquidation Address", + "description": "Retrieve a Liquidation Address for the specified Liquidation Address ID", + "tags": [ + "Liquidation Addresses" + ], + "parameters": [ + { + "$ref": "#/components/parameters/CustomerIDParameter" + }, + { + "$ref": "#/components/parameters/LiquidationAddressIDParameter" + } + ], + "responses": { + "200": { + "description": "A Liquidation Address object response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LiquidationAddress" + }, + "examples": { + "SuccessfulLiquidationAddressGetResponse": { + "$ref": "#/components/examples/SuccessfulLiquidationAddressGetResponse" + }, + "SuccessfulSepaLiquidationAddressGetResponse": { + "$ref": "#/components/examples/SuccessfulSepaLiquidationAddressGetResponse" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "404": { + "$ref": "#/components/responses/NotFoundError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + }, + "put": { + "summary": "Update a Liquidation Address", + "description": "Update a Liquidation Address for the specified liquidation address ID. Fields (`external_account_id`, `custom_developer_fee_percent`, `destination`) can be updated independently and are not all required.", + "tags": [ + "Liquidation Addresses" + ], + "parameters": [ + { + "$ref": "#/components/parameters/CustomerIDParameter" + }, + { + "$ref": "#/components/parameters/LiquidationAddressIDParameter" + } + ], + "requestBody": { + "description": "Liquidation Address details to be updated", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateLiquidationAddress" + } + } + } + }, + "responses": { + "200": { + "description": "Updated Liquidation Address object", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LiquidationAddress" + }, + "examples": { + "SuccessfulLiquidationAddressUpdateResponse": { + "$ref": "#/components/examples/SuccessfulLiquidationAddressGetResponse" + }, + "SuccessfulSepaLiquidationAddressUpdateResponse": { + "$ref": "#/components/examples/SuccessfulSepaLiquidationAddressGetResponse" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/customers/{customerID}/liquidation_addresses/{liquidationAddressID}/drains": { + "get": { + "summary": "Get drain history of a Liquidation Address", + "description": "Get drain history of a Liquidation Address", + "tags": [ + "Liquidation Addresses" + ], + "parameters": [ + { + "$ref": "#/components/parameters/CustomerIDParameter" + }, + { + "$ref": "#/components/parameters/LiquidationAddressIDParameter" + }, + { + "$ref": "#/components/parameters/TxHashParameter" + }, + { + "$ref": "#/components/parameters/LimitParameter" + }, + { + "$ref": "#/components/parameters/DrainStartingAfterParameter" + }, + { + "$ref": "#/components/parameters/DrainEndingBeforeParameter" + }, + { + "$ref": "#/components/parameters/UpdatedAfterMsParameter" + }, + { + "$ref": "#/components/parameters/UpdatedBeforeMsParameter" + }, + { + "$ref": "#/components/parameters/DrainIDQueryParameter" + } + ], + "responses": { + "200": { + "description": "List of drains (the returned list is empty if none found)", + "content": { + "application/json": { + "schema": { + "properties": { + "data": { + "$ref": "#/components/schemas/Drain" + } + } + }, + "examples": { + "DrainsToCryptoFound": { + "$ref": "#/components/examples/SuccessfulLiquidationAddressDrainsToCryptoResponse" + }, + "DrainsToFiatFound": { + "$ref": "#/components/examples/SuccessfulLiquidationAddressDrainsToFiatResponse" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/customers/{customerID}/liquidation_addresses/{liquidationAddressID}/drains/{drainID}/execute": { + "parameters": [ + { + "$ref": "#/components/parameters/CustomerIDParameter" + }, + { + "$ref": "#/components/parameters/LiquidationAddressIDParameter" + }, + { + "name": "drainID", + "in": "path", + "required": true, + "schema": { + "$ref": "#/components/schemas/Id" + } + } + ], + "post": { + "summary": "Execute a pending USDT trade on a drain", + "description": "Force-executes a stuck USDT-to-USD trade at the current market rate. The drain must have a pending trade (i.e. appear in `GET /liquidation_addresses/drains/pending`).\n\nAfter execution, the drain will continue processing normally with the executed market rate.\n", + "tags": [ + "Liquidation Addresses" + ], + "parameters": [ + { + "$ref": "#/components/parameters/IdempotencyKeyParameter" + } + ], + "responses": { + "200": { + "description": "Drain with trade execute at market rate enabled successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Drain" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "404": { + "$ref": "#/components/responses/NotFoundError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/customers/{customerID}/liquidation_addresses/{liquidationAddressID}/balances": { + "get": { + "summary": "Get the balance of a Liquidation Address (deprecated)", + "description": "Get the balance of a Liquidation Address. Note that most Liquidation Addresses no longer hold a balance. To check recent activity on a Liquidation Address, use the `/customers/{customerID}/liquidation_addresses/{liquidationAddressID}/drains` endpoint.", + "deprecated": true, + "tags": [ + "Liquidation Addresses" + ], + "parameters": [ + { + "$ref": "#/components/parameters/CustomerIDParameter" + }, + { + "$ref": "#/components/parameters/LiquidationAddressIDParameter" + } + ], + "responses": { + "200": { + "description": "Get the current balance of a Liquidation Address", + "content": { + "application/json": { + "schema": { + "properties": { + "data": { + "$ref": "#/components/schemas/Balance" + } + } + }, + "examples": { + "DrainsFound": { + "$ref": "#/components/examples/SuccessfulLiquidationAddressBalanceResponse" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/customers/{customerID}/virtual_accounts": { + "post": { + "summary": "Create a Virtual Account", + "description": "Create a Virtual Account or Virtual IBAN for the specified customer", + "tags": [ + "Virtual Accounts" + ], + "parameters": [ + { + "$ref": "#/components/parameters/IdempotencyKeyParameter" + }, + { + "$ref": "#/components/parameters/CustomerIDParameter" + } + ], + "requestBody": { + "description": "Virtual Account object to be created", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateVirtualAccount" + }, + "examples": { + "us": { + "summary": "Virtual Account", + "value": { + "developer_fee_percent": "0.1", + "source": { + "currency": "usd" + }, + "destination": { + "currency": "usdc", + "payment_rail": "base", + "address": "0xdeadbeef" + } + } + }, + "us_fee_config_request_only": { + "summary": "Virtual Account with fee_config (available by request only)", + "value": { + "fee_config": { + "source": { + "ach_push": { + "fee_percent": "0.5", + "minimum_fee": "1.00" + }, + "wire": { + "fee_amount": "10.00", + "fee_percent": "1.0" + } + } + }, + "source": { + "currency": "usd" + }, + "destination": { + "currency": "usdc", + "payment_rail": "base", + "address": "0xdeadbeef" + } + } + }, + "eu": { + "summary": "Virtual IBAN", + "value": { + "developer_fee_percent": "0.1", + "source": { + "currency": "eu" + }, + "destination": { + "currency": "eurc", + "payment_rail": "solana", + "adddress": "DeAdBeEf" + } + } + }, + "mx": { + "summary": "Virtual Account Mexico", + "value": { + "developer_fee_percent": "0.1", + "source": { + "currency": "mxn" + }, + "destination": { + "currency": "usdc", + "payment_rail": "base", + "address": "0xdeadbeef" + } + } + }, + "gb": { + "summary": "Virtual Account United Kingdom (beta)", + "value": { + "developer_fee_percent": "0.1", + "source": { + "currency": "gbp" + }, + "destination": { + "currency": "usdc", + "payment_rail": "base", + "address": "0xdeadbeef" + } + } + }, + "co": { + "summary": "Virtual Account Colombia (Bre-B)", + "value": { + "developer_fee_percent": "0.1", + "source": { + "currency": "cop" + }, + "destination": { + "currency": "usdc", + "payment_rail": "ethereum", + "address": "0xdeadbeef" + } + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Virtual Account object created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VirtualAccountResponse" + }, + "examples": { + "us": { + "summary": "Virtual Account", + "value": { + "id": "59waova4hbt1vhabj3jo7don6j1mj5peq8i8rhc5l1", + "status": "activated", + "developer_fee_percent": "0.1", + "source_deposit_instructions": { + "currency": "usd", + "payment_rails": [ + "ach_push", + "fednow", + "wire" + ], + "bank_name": "Lead Bank", + "bank_address": "1801 Main St., Kansas City, MO 64108", + "bank_beneficiary_name\"": "Customer Name", + "bank_beneficiary_address\"": "1234 Main St., Kansas City, MO 64108", + "bank_account_number\"": "123456789", + "bank_routing_number\"": "87654321" + }, + "destination": { + "currency": "usdc", + "payment_rail": "polygon", + "address": "0xdeadbeef" + } + } + }, + "us_fee_config_request_only": { + "summary": "Virtual Account with fee_config (available by request only)", + "value": { + "id": "59waova4hbt1vhabj3jo7don6j1mj5peq8i8rhc5l1", + "status": "activated", + "developer_fee_percent": "0.0", + "fee_config": { + "source": { + "ach_push": { + "fee_percent": "0.5", + "minimum_fee": "1.00" + }, + "fednow": { + "fee_percent": "1.0", + "minimum_fee": "1.00" + }, + "wire": { + "fee_amount": "10.00", + "fee_percent": "1.0" + } + } + }, + "source_deposit_instructions": { + "currency": "usd", + "payment_rails": [ + "ach_push", + "fednow", + "wire" + ], + "bank_name": "Lead Bank", + "bank_address": "1801 Main St., Kansas City, MO 64108", + "bank_beneficiary_name\"": "Customer Name", + "bank_beneficiary_address\"": "1234 Main St., Kansas City, MO 64108", + "bank_account_number\"": "123456789", + "bank_routing_number\"": "87654321" + }, + "destination": { + "currency": "usdc", + "payment_rail": "polygon", + "address": "0xdeadbeef" + } + } + }, + "eu": { + "summary": "Virtual IBAN", + "value": { + "id": "59waova4hbt1vhabj3jo7don6j1mj5peq8i8rhc5l1", + "status": "activated", + "developer_fee_percent": "0.1", + "source_deposit_instructions": { + "currency": "eur", + "payment_rails": [ + "sepa" + ], + "iban": "X6099", + "bic": "BCIRLULL", + "account_holder_name": "Bridge Building Sp. Z.o.o.", + "bank_name": "Banking Circle S.A.", + "bank_address": "2 Boulevard de la Foire, L-1528 Luxembourg" + }, + "destination": { + "currency": "eurc", + "payment_rail": "solana", + "address": "DeAdBeEf" + } + } + }, + "mx": { + "summary": "Virtual Account Mexico", + "value": { + "id": "59waova4hbt1vhabj3jo7don6j1mj5peq8i8rhc5l1", + "status": "activated", + "developer_fee_percent": "0.1", + "source_deposit_instructions": { + "currency": "mxn", + "payment_rails": [ + "spei" + ], + "bank_name": "Banco Azteca", + "bank_address": "Av. Aztecas 215, Santa Cruz Acatlán, Naucalpan de Juárez, Estado de México", + "bank_beneficiary_name": "Customer Name", + "bank_beneficiary_address": "Calle Ejemplo 123, Ciudad de México, CDMX 01234", + "bank_account_number": "1234567890123456789", + "clabe": "127180001234567890" + }, + "destination": { + "currency": "usdc", + "payment_rail": "solana", + "address": "DeAdBeEf" + } + } + }, + "gb": { + "summary": "Virtual Account United Kingdom (beta)", + "value": { + "id": "2ecad10b-f44b-4ffa-8c53-39a6b63ab9ab", + "status": "activated", + "developer_fee_percent": "0.1", + "source_deposit_instructions": { + "currency": "gbp", + "payment_rails": [ + "faster_payments" + ], + "account_number": "01234567", + "sort_code": "987654", + "bank_name": "Banking Circle S.A.", + "bank_address": "2 Boulevard de la Foire, L-1528 Luxembourg", + "bank_benficiary_name": "Bridge Building Sp. Z.o.o.", + "bank_benficiary_address": "2 Boulevard de la Foire, L-1528 Luxembourg", + "account_holder_name": "Bridge Building Sp. Z.o.o." + } + } + }, + "co": { + "summary": "Virtual Account Colombia (Bre-B)", + "value": { + "id": "59waova4hbt1vhabj3jo7don6j1mj5peq8i8rhc5l1", + "status": "activated", + "developer_fee_percent": "0.1", + "source_deposit_instructions": { + "currency": "cop", + "payment_rails": [ + "bre_b" + ], + "bre_b_key": "12345678901234567890", + "account_holder_name": "Bridge Developer Name", + "deposit_message": "COP7depositmessage" + }, + "destination": { + "currency": "usdc", + "payment_rail": "ethereum", + "address": "0xdeadbeef" + } + } + } + } + } + } + } + } + }, + "get": { + "summary": "List Virtual Accounts by Customer", + "description": "List all Virtual Account objects for a customer", + "tags": [ + "Virtual Accounts" + ], + "parameters": [ + { + "$ref": "#/components/parameters/CustomerIDParameter" + }, + { + "$ref": "#/components/parameters/FiatInstructionsActivationStatusParameter" + }, + { + "$ref": "#/components/parameters/LimitParameter" + }, + { + "$ref": "#/components/parameters/VirtualAccountStartingAfterParameter" + }, + { + "$ref": "#/components/parameters/VirtualAccountEndingBeforeParameter" + } + ], + "responses": { + "200": { + "description": "List of Virtual Accounts", + "content": { + "application/json": { + "schema": { + "title": "Virtual Accounts", + "type": "object", + "required": [ + "count", + "data" + ], + "properties": { + "count": { + "description": "total number of items in data", + "type": "integer" + }, + "data": { + "type": "array", + "minItems": 0, + "items": { + "$ref": "#/components/schemas/VirtualAccountResponse" + } + } + } + } + } + } + } + } + } + }, + "/customers/{customerID}/virtual_accounts/{virtualAccountID}": { + "get": { + "summary": "Get a Virtual Account", + "description": "Retrieve the Virtual Account object from the passed ID", + "tags": [ + "Virtual Accounts" + ], + "parameters": [ + { + "$ref": "#/components/parameters/CustomerIDParameter" + }, + { + "$ref": "#/components/parameters/VirtualAccountIDParameter" + } + ], + "responses": { + "200": { + "description": "Successful Virtual Account object response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VirtualAccountResponse" + } + } + } + } + } + }, + "put": { + "summary": "Update a Virtual Account", + "description": "Update instructions for an existing Virtual Account", + "tags": [ + "Virtual Accounts" + ], + "parameters": [ + { + "$ref": "#/components/parameters/CustomerIDParameter" + }, + { + "$ref": "#/components/parameters/VirtualAccountIDParameter" + } + ], + "requestBody": { + "description": "The Virtual Account details to be updated", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateVirtualAccount" + } + } + } + }, + "responses": { + "200": { + "description": "Updated Virtual Account object", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VirtualAccountResponse" + } + } + } + } + } + } + }, + "/customers/{customerID}/virtual_accounts/{virtualAccountID}/deactivate": { + "post": { + "summary": "Deactivate a Virtual Account", + "description": "Deactivate a Virtual Account to prevent it from acceping new incoming transactions", + "tags": [ + "Virtual Accounts" + ], + "parameters": [ + { + "$ref": "#/components/parameters/IdempotencyKeyParameter" + }, + { + "$ref": "#/components/parameters/CustomerIDParameter" + }, + { + "$ref": "#/components/parameters/VirtualAccountIDParameter" + } + ], + "responses": { + "200": { + "description": "Deactivated Virtual Account object", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/VirtualAccountResponse" + }, + { + "type": "object", + "properties": { + "status": { + "example": "deactivated" + } + } + } + ] + } + } + } + } + } + } + }, + "/customers/{customerID}/virtual_accounts/{virtualAccountID}/reactivate": { + "post": { + "summary": "Reactivate a Virtual Account", + "description": "Reactivate a previously deactivated Virtual Account", + "tags": [ + "Virtual Accounts" + ], + "parameters": [ + { + "$ref": "#/components/parameters/IdempotencyKeyParameter" + }, + { + "$ref": "#/components/parameters/CustomerIDParameter" + }, + { + "$ref": "#/components/parameters/VirtualAccountIDParameter" + } + ], + "responses": { + "200": { + "description": "Reactivated Virtual Account object", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VirtualAccountResponse" + } + } + } + } + } + } + }, + "/customers/{customerID}/virtual_accounts/{virtualAccountID}/history": { + "parameters": [ + { + "$ref": "#/components/parameters/CustomerIDParameter" + }, + { + "$ref": "#/components/parameters/VirtualAccountIDParameter" + }, + { + "$ref": "#/components/parameters/DepositIDQueryParameter" + }, + { + "$ref": "#/components/parameters/DepositIDsQueryParameter" + }, + { + "$ref": "#/components/parameters/TxHashParameter" + }, + { + "$ref": "#/components/parameters/LimitParameter" + }, + { + "$ref": "#/components/parameters/EventStartingAfterParameter" + }, + { + "$ref": "#/components/parameters/EventEndingBeforeParameter" + }, + { + "$ref": "#/components/parameters/EventTypeParameter" + } + ], + "get": { + "summary": "Virtual Account Activity", + "tags": [ + "Virtual Accounts" + ], + "description": "History of activity for a Virtual Account", + "responses": { + "200": { + "description": "List of Virtual Account events", + "content": { + "application/json": { + "schema": { + "title": "Virtual Account history", + "type": "object", + "required": [ + "count", + "data" + ], + "properties": { + "count": { + "type": "integer", + "description": "The number of events returned" + }, + "data": { + "type": "array", + "minItems": 0, + "items": { + "$ref": "#/components/schemas/VirtualAccountEvent" + } + } + } + }, + "examples": { + "History": { + "$ref": "#/components/examples/VirtualAccountHistoryExample" + } + } + } + } + } + } + } + }, + "/static_memos": { + "get": { + "summary": "List Static Memos", + "description": "List all Static Memo objects", + "tags": [ + "Static Memos" + ], + "parameters": [ + { + "$ref": "#/components/parameters/FiatInstructionsActivationStatusParameter" + }, + { + "$ref": "#/components/parameters/LimitParameter" + }, + { + "$ref": "#/components/parameters/StaticMemoStartingAfterParameter" + }, + { + "$ref": "#/components/parameters/StaticMemoEndingBeforeParameter" + } + ], + "responses": { + "200": { + "description": "List of Static Memos", + "content": { + "application/json": { + "schema": { + "title": "Static Memos", + "type": "object", + "required": [ + "count", + "data" + ], + "properties": { + "count": { + "description": "total number of items in data", + "type": "integer" + }, + "data": { + "type": "array", + "minItems": 0, + "items": { + "$ref": "#/components/schemas/StaticMemoResponse" + } + } + } + } + } + } + } + } + } + }, + "/customers/{customerID}/static_memos": { + "post": { + "summary": "Create a Static Memo", + "description": "Create a Static Memo for the specified customer", + "tags": [ + "Static Memos" + ], + "parameters": [ + { + "$ref": "#/components/parameters/IdempotencyKeyParameter" + }, + { + "$ref": "#/components/parameters/CustomerIDParameter" + } + ], + "requestBody": { + "description": "Static Memo object to be created", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateStaticMemo" + } + } + } + }, + "responses": { + "200": { + "description": "Static Memo object created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StaticMemoResponse" + } + } + } + } + } + }, + "get": { + "summary": "List Static Memos for Customer", + "description": "List all Static Memo objects for a customer", + "tags": [ + "Static Memos" + ], + "parameters": [ + { + "$ref": "#/components/parameters/CustomerIDParameter" + }, + { + "$ref": "#/components/parameters/FiatInstructionsActivationStatusParameter" + }, + { + "$ref": "#/components/parameters/LimitParameter" + }, + { + "$ref": "#/components/parameters/StaticMemoStartingAfterParameter" + }, + { + "$ref": "#/components/parameters/StaticMemoEndingBeforeParameter" + } + ], + "responses": { + "200": { + "description": "List of Static Memos", + "content": { + "application/json": { + "schema": { + "title": "Static Memos", + "type": "object", + "required": [ + "count", + "data" + ], + "properties": { + "count": { + "description": "total number of items in data", + "type": "integer" + }, + "data": { + "type": "array", + "minItems": 0, + "items": { + "$ref": "#/components/schemas/StaticMemoResponse" + } + } + } + } + } + } + } + } + } + }, + "/customers/{customerID}/static_memos/{staticMemoID}": { + "get": { + "summary": "Get a Static Memo", + "description": "Retrieve the Static Memo object from the passed ID", + "tags": [ + "Static Memos" + ], + "parameters": [ + { + "$ref": "#/components/parameters/CustomerIDParameter" + }, + { + "$ref": "#/components/parameters/StaticMemoIDParameter" + } + ], + "responses": { + "200": { + "description": "Successful static memo object response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StaticMemoResponse" + } + } + } + } + } + }, + "put": { + "summary": "Update a Static Memo", + "description": "Update instructions for an existing Static Memo", + "tags": [ + "Static Memos" + ], + "parameters": [ + { + "$ref": "#/components/parameters/CustomerIDParameter" + }, + { + "$ref": "#/components/parameters/StaticMemoIDParameter" + } + ], + "requestBody": { + "description": "The Static Memo details to be updated", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateStaticMemo" + } + } + } + }, + "responses": { + "200": { + "description": "Updated Static Memo object", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StaticMemoResponse" + } + } + } + } + } + } + }, + "/customers/{customerID}/card_accounts/{cardAccountID}/pin": { + "post": { + "summary": "Create Card PIN Update URL", + "description": "Generates a URL that can be used to render a secure frame to update the PIN for a card account. The URL is single-use and time-limited.", + "tags": [ + "Cards" + ], + "parameters": [ + { + "$ref": "#/components/parameters/CustomerIDParameter" + }, + { + "$ref": "#/components/parameters/IdempotencyKeyParameter" + }, + { + "name": "cardAccountID", + "in": "path", + "required": true, + "description": "The ID of the card account", + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "URL to update the card PIN", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CardPinUpdateResponse" + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/customers/{customerID}/card_accounts/{cardAccountID}/ephemeral_keys": { + "post": { + "summary": "Generate an Ephemeral Key to Reveal Card Details", + "description": "Generates a one-time ephemeral key that can be used to reveal card details. Please see the integration guide on [safely revealing card details](https://apidocs.bridge.xyz/docs/safely-reveal-card-details-to-customers) for more information.", + "tags": [ + "Cards" + ], + "parameters": [ + { + "$ref": "#/components/parameters/CustomerIDParameter" + }, + { + "$ref": "#/components/parameters/IdempotencyKeyParameter" + }, + { + "name": "cardAccountID", + "in": "path", + "required": true, + "description": "The ID of the card account", + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "description": "The client-side nonce that will be associated with the ephemeral key", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PostCardAccountEphemeralKeyInput" + } + } + } + }, + "responses": { + "200": { + "description": "Ephemeral key to reveal card details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CardAccountEphemeralKeyResponse" + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/customers/{customerID}/static_memos/{staticMemoID}/history": { + "parameters": [ + { + "$ref": "#/components/parameters/CustomerIDParameter" + }, + { + "$ref": "#/components/parameters/StaticMemoIDParameter" + }, + { + "$ref": "#/components/parameters/DepositIDQueryParameter" + }, + { + "$ref": "#/components/parameters/DepositIDsQueryParameter" + }, + { + "$ref": "#/components/parameters/TxHashParameter" + }, + { + "$ref": "#/components/parameters/LimitParameter" + }, + { + "$ref": "#/components/parameters/EventStartingAfterParameter" + }, + { + "$ref": "#/components/parameters/EventEndingBeforeParameter" + }, + { + "$ref": "#/components/parameters/EventTypeParameter" + } + ], + "get": { + "summary": "Static Memo Activity", + "tags": [ + "Static Memos" + ], + "description": "History of activity for a Static Memo", + "responses": { + "200": { + "description": "List of Static Memo events", + "content": { + "application/json": { + "schema": { + "title": "Static Memo history", + "type": "object", + "required": [ + "count", + "data" + ], + "properties": { + "count": { + "type": "integer", + "description": "The number of events returned" + }, + "data": { + "type": "array", + "minItems": 0, + "items": { + "$ref": "#/components/schemas/StaticMemoEvent" + } + } + } + }, + "examples": { + "History": { + "$ref": "#/components/examples/StaticMemoHistoryExample" + } + } + } + } + } + } + } + }, + "/customers/{customerID}/batch_settlement_schedules": { + "post": { + "summary": "Create a Batch Settlement Schedule", + "deprecated": true, + "description": "Creates a Batch Settlement Schedule that can be used as the destination of a liquidation address.", + "tags": [ + "Batch Settlements" + ], + "parameters": [ + { + "$ref": "#/components/parameters/CustomerIDParameter" + }, + { + "$ref": "#/components/parameters/IdempotencyKeyParameter" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateBatchSettlementSchedule" + } + } + } + }, + "responses": { + "200": { + "description": "Batch Settlement Schedule object created", + "content": { + "application/json": { + "schema": { + "title": "Batch Settlement Schedule", + "type": "object", + "required": [ + "id" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/Id", + "description": "ID of the batch settlement schedule" + } + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/external_accounts": { + "parameters": [ + { + "$ref": "#/components/parameters/LimitParameter" + }, + { + "$ref": "#/components/parameters/ExternalAccountStartingAfterParameter" + }, + { + "$ref": "#/components/parameters/ExternalAccountEndingBeforeParameter" + } + ], + "get": { + "summary": "Get all External Accounts", + "tags": [ + "External Accounts" + ], + "description": "Get all External Accounts.", + "responses": { + "200": { + "description": "List of External Accounts (the returned list is empty if no External Accounts exist)", + "content": { + "application/json": { + "schema": { + "title": "ExternalAccount", + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "type": "array", + "minItems": 0, + "items": { + "$ref": "#/components/schemas/ExternalAccountResponse" + } + }, + "count": { + "description": "total number of items in data", + "type": "integer" + } + } + }, + "examples": { + "ExternalAccountsFound": { + "summary": "A non-empty list of External Accounts", + "value": { + "data": [ + { + "id": "ea_123", + "account_type": "us", + "currency": "usd", + "customer_id": "cust_123", + "account_owner_name": "John Doe", + "bank_name": "Wells Fargo", + "last_4": "1111", + "active": true, + "beneficiary_address_valid": true, + "account": { + "last_4": "1111", + "routing_number": "121000248", + "checking_or_savings": "checking" + }, + "created_at": "2020-01-01T00:00:00.000Z", + "updated_at": "2020-01-02T00:00:00.000Z" + } + ] + } + }, + "ExternalAccountsFoundIban": { + "summary": "iban", + "value": { + "data": [ + { + "id": "ea_123", + "customer_id": "cust_123", + "account_type": "iban", + "currency": "eur", + "account_owner_name": "John Doe", + "bank_name": "AAC CAPITAL PARTNERS LIMITED", + "active": true, + "iban": { + "last_4": "5981", + "bic": "BARBGB2LLEI", + "country": "NLD" + }, + "account_owner_type": "individual", + "first_name": "John", + "last_name": "Doe", + "account_verification": { + "iban": { + "match_level": "match", + "reason_code": null, + "validated_account_owner_name": "John Doe" + }, + "requested_at": "2020-01-01T00:05:00.000Z", + "completed_at": "2020-01-01T00:05:05.000Z" + }, + "created_at": "2020-01-01T00:00:00.000Z", + "updated_at": "2020-01-02T00:00:00.000Z" + } + ] + } + }, + "ExternalAccountsFoundPixKey": { + "summary": "pix (Pix Key)", + "value": { + "data": [ + { + "id": "ea_123", + "customer_id": "cust_123", + "account_type": "pix", + "currency": "brl", + "account_owner_name": "João Silva", + "bank_name": "Banco do Brasil", + "active": true, + "pix_key": { + "account_preview": "jo****ilva****il.c**", + "document_number_last4": "8901" + }, + "account_validation": { + "validated_account_owner_name": "João Silva", + "validated_bank_name": "Banco do Brasil" + }, + "account_owner_type": "individual", + "first_name": "João", + "last_name": "Silva", + "account_verification": { + "pix": { + "matched": true, + "reason_code": null, + "validated_account_owner_name": "João Silva", + "validated_bank_name": "Banco do Brasil" + }, + "requested_at": "2020-01-01T00:05:00.000Z", + "completed_at": "2020-01-01T00:05:05.000Z" + }, + "created_at": "2020-01-01T00:00:00.000Z", + "updated_at": "2020-01-02T00:00:00.000Z" + } + ] + } + }, + "ExternalAccountsFoundBrCode": { + "summary": "pix (BR Code)", + "value": { + "data": [ + { + "id": "ea_456", + "customer_id": "cust_456", + "account_type": "pix", + "currency": "brl", + "account_owner_name": "Maria Santos", + "bank_name": "Itaú Unibanco", + "active": true, + "br_code": { + "account_preview": "11****1111****1111****1111", + "document_number_last4": "0131" + }, + "account_validation": { + "validated_account_owner_name": "Maria Santos", + "validated_bank_name": "Itaú Unibanco" + }, + "account_owner_type": "individual", + "first_name": "Maria", + "last_name": "Santos", + "account_verification": { + "pix": { + "matched": true, + "reason_code": null, + "validated_account_owner_name": "Maria Santos", + "validated_bank_name": "Itaú Unibanco" + }, + "requested_at": "2020-01-01T00:05:00.000Z", + "completed_at": "2020-01-01T00:05:05.000Z" + }, + "created_at": "2020-01-01T00:00:00.000Z", + "updated_at": "2020-01-02T00:00:00.000Z" + } + ] + } + }, + "ExternalAccountsFoundClabe": { + "summary": "clabe", + "value": { + "data": [ + { + "id": "ea_567", + "customer_id": "cust_567", + "account_type": "clabe", + "currency": "mxn", + "account_owner_name": "Juan García", + "bank_name": "Banco Santander México", + "active": true, + "clabe": { + "last_4": "0007" + }, + "account_validation": { + "validated_account_owner_name": "Juan García", + "validated_bank_name": "Banco Santander México" + }, + "account_owner_type": "individual", + "first_name": "Juan", + "last_name": "García", + "account_verification": { + "clabe": { + "matched": true, + "reason_code": null, + "validated_account_owner_name": "Juan García", + "validated_bank_name": "Banco Santander México" + }, + "requested_at": "2020-01-01T00:05:00.000Z", + "completed_at": "2020-01-01T00:05:05.000Z" + }, + "created_at": "2020-01-01T00:00:00.000Z", + "updated_at": "2020-01-02T00:00:00.000Z" + } + ] + } + }, + "ExternalAccountsFoundBreB": { + "summary": "bre_b", + "value": { + "data": [ + { + "id": "ea_789", + "customer_id": "cust_789", + "account_type": "bre_b", + "currency": "cop", + "account_owner_name": "Juan Garcia", + "bank_name": "Banco de Bogota", + "active": true, + "account": { + "last_4": "0000" + }, + "account_validation": { + "validated_account_owner_name": "Juan Garcia", + "validated_bank_name": "Banco de Bogota", + "validated_document_number_last4": "0000" + }, + "account_owner_type": "individual", + "first_name": "Juan", + "last_name": "Garcia", + "account_verification": { + "bre_b": { + "matched": true, + "reason_code": null, + "validated_account_owner_name": "Juan Garcia", + "validated_bank_name": "Banco de Bogota", + "validated_document_number_last4": "0000" + }, + "requested_at": "2020-01-01T00:05:00.000Z", + "completed_at": "2020-01-01T00:05:05.000Z" + }, + "created_at": "2020-01-01T00:00:00.000Z", + "updated_at": "2020-01-02T00:00:00.000Z" + } + ] + } + }, + "ExternalAccountsFoundCoBankTransfer": { + "summary": "co_bank_transfer", + "value": { + "data": [ + { + "id": "ea_012", + "customer_id": "cust_012", + "account_type": "co_bank_transfer", + "currency": "cop", + "account_owner_name": "Maria Lopez", + "bank_name": "Bancolombia", + "active": true, + "account": { + "last_4": "1234", + "routing_number": "1007" + }, + "account_owner_type": "individual", + "first_name": "Maria", + "last_name": "Lopez", + "account_verification": { + "co_bank_transfer": { + "matched": true, + "reason_code": null, + "validated_account_owner_name": "Maria Lopez", + "validated_bank_name": "Bancolombia", + "validated_document_number_last4": "9012" + }, + "requested_at": "2020-01-01T00:05:00.000Z", + "completed_at": "2020-01-01T00:05:05.000Z" + }, + "created_at": "2020-01-01T00:00:00.000Z", + "updated_at": "2020-01-02T00:00:00.000Z" + } + ] + } + }, + "NoExternalAccountsFound": { + "summary": "An empty list of External Accounts", + "value": { + "data": [], + "count": 0 + } + } + } + } + } + } + } + } + }, + "/virtual_accounts": { + "get": { + "summary": "List Virtual Accounts", + "description": "List all Virtual Account objects", + "tags": [ + "Virtual Accounts" + ], + "parameters": [ + { + "$ref": "#/components/parameters/FiatInstructionsActivationStatusParameter" + }, + { + "$ref": "#/components/parameters/LimitParameter" + }, + { + "$ref": "#/components/parameters/VirtualAccountStartingAfterParameter" + }, + { + "$ref": "#/components/parameters/VirtualAccountEndingBeforeParameter" + } + ], + "responses": { + "200": { + "description": "List of Virtual Accounts", + "content": { + "application/json": { + "schema": { + "title": "Virtual Accounts", + "type": "object", + "required": [ + "count", + "data" + ], + "properties": { + "count": { + "description": "total number of items in data", + "type": "integer" + }, + "data": { + "type": "array", + "minItems": 0, + "items": { + "$ref": "#/components/schemas/VirtualAccountResponse" + } + } + } + } + } + } + } + } + } + }, + "/virtual_accounts/history": { + "parameters": [ + { + "$ref": "#/components/parameters/DepositIDQueryParameter" + }, + { + "$ref": "#/components/parameters/DepositIDsQueryParameter" + }, + { + "$ref": "#/components/parameters/TxHashParameter" + }, + { + "$ref": "#/components/parameters/LimitParameter" + }, + { + "$ref": "#/components/parameters/EventStartingAfterParameter" + }, + { + "$ref": "#/components/parameters/EventEndingBeforeParameter" + }, + { + "$ref": "#/components/parameters/EventTypeParameter" + }, + { + "$ref": "#/components/parameters/UpdatedAfterMsParameter" + }, + { + "$ref": "#/components/parameters/UpdatedBeforeMsParameter" + } + ], + "get": { + "summary": "Virtual Account Activity Across All Customers", + "tags": [ + "Virtual Accounts" + ], + "description": "History of activity across all customers and Virtual Accounts", + "responses": { + "200": { + "description": "List of Virtual Account events", + "content": { + "application/json": { + "schema": { + "title": "Virtual Account history", + "type": "object", + "required": [ + "count", + "data" + ], + "properties": { + "count": { + "type": "integer", + "description": "The number of events returned" + }, + "data": { + "type": "array", + "minItems": 0, + "items": { + "$ref": "#/components/schemas/VirtualAccountEvent" + } + } + } + }, + "examples": { + "History": { + "$ref": "#/components/examples/VirtualAccountHistoryExample" + } + } + } + } + } + } + } + }, + "/developer/fees": { + "get": { + "summary": "Get the configured fees", + "description": "Get fees that have been configured for supported products.", + "tags": [ + "Developers" + ], + "responses": { + "200": { + "description": "The configured fees for your developer account.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeveloperFees" + }, + "examples": { + "SuccessfulResponse": { + "summary": "The fees configured for the account.", + "value": { + "default_liquidation_address_fee_percent": "1.3" + } + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + }, + "post": { + "summary": "Update the configured fees", + "description": "Update fees for supported products.", + "tags": [ + "Developers" + ], + "parameters": [ + { + "$ref": "#/components/parameters/IdempotencyKeyParameter" + } + ], + "requestBody": { + "description": "The default fee percent that will be applied to all your Liquidation Addresses. The value is a base 100 percentage, i.e. 10.2% is 10.2 in the API.", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeveloperFees" + } + } + } + }, + "responses": { + "200": { + "description": "The configured fees have been updated for your developer account.", + "content": { + "application/json": { + "examples": { + "SuccessfulResponse": { + "summary": "The fees have been updated.", + "value": { + "default_liquidation_address_fee_percent": "1.3" + } + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/developer/fee_external_account": { + "get": { + "summary": "Get the configured fee External Account", + "description": "Get the configured fee External Account.", + "tags": [ + "Developers" + ], + "responses": { + "200": { + "description": "Get the configured fee External Account.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FeeExternalAccount" + }, + "examples": { + "SuccessfulFeeExternalAccountResponse": { + "$ref": "#/components/examples/SuccessfulFeeExternalAccountResponse" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + }, + "post": { + "summary": "Configure a fee External Account", + "description": "Configure a fee External Account.", + "tags": [ + "Developers" + ], + "parameters": [ + { + "$ref": "#/components/parameters/IdempotencyKeyParameter" + } + ], + "requestBody": { + "description": "New External Account object to be created", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateFeeExternalAccountInput" + }, + "examples": { + "ACH": { + "$ref": "#/components/examples/CreateAchExternalAccountRequest" + } + } + } + } + }, + "responses": { + "201": { + "description": "External Account object created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FeeExternalAccount" + }, + "examples": { + "SuccessfulFeeExternalAccountResponse": { + "$ref": "#/components/examples/SuccessfulFeeExternalAccountResponse" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/developer/cards/summary": { + "get": { + "summary": "Get a summary of your card program", + "description": "Get a summary of your card program, optionally for a specific period.", + "tags": [ + "Cards" + ], + "parameters": [ + { + "$ref": "#/components/parameters/CardProgramSummaryPeriodParameter" + }, + { + "$ref": "#/components/parameters/CardProgramSummaryPeriodKeyParameter" + } + ], + "responses": { + "200": { + "description": "The summary of a card program", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CardProgramSummary" + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/developer/cards/designs": { + "get": { + "summary": "Get a listing of your card program's card designs", + "description": "Get a listing of the designs that you can use to issue a card with.", + "tags": [ + "Cards" + ], + "responses": { + "200": { + "description": "A listing of the designs that you can use to issue a card with.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CardDesigns" + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/api_keys": { + "post": { + "summary": "Create a scoped API key", + "description": "Create a new API key restricted to a subset of scopes. The returned `value` is the only\nopportunity to retrieve the plaintext secret — store it securely. This endpoint does not\naccept an `Idempotency-Key` header; each call creates a new key.\n\nCallers may only grant scopes they themselves hold (scope subsetting). Unrestricted keys\nmay create scoped keys; scoped keys need the `api_key:create` scope. Up to 500 scoped\nkeys may exist per developer.\n", + "tags": [ + "API Keys" + ], + "requestBody": { + "description": "The scopes to grant the new API key. Must be a non-empty array drawn from `ApiKeyScope`.", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateApiKeyInput" + }, + "examples": { + "ScopedKey": { + "$ref": "#/components/examples/CreateApiKeyRequest" + } + } + } + } + }, + "responses": { + "201": { + "description": "The API key was created. `value` is returned exactly once.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiKeyWithSecret" + }, + "examples": { + "SuccessfulCreateApiKeyResponse": { + "$ref": "#/components/examples/SuccessfulCreateApiKeyResponse" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/api_keys/whoami": { + "get": { + "summary": "Describe the calling API key", + "description": "Return metadata about the API key authenticating this request, including its scopes. The plaintext secret is never returned.", + "tags": [ + "API Keys" + ], + "responses": { + "200": { + "description": "Metadata describing the calling API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiKey" + }, + "examples": { + "SuccessfulWhoAmIResponse": { + "$ref": "#/components/examples/SuccessfulWhoAmIResponse" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/kyc_links": { + "post": { + "summary": "Generate the Links needs to complete KYC for an individual or business", + "tags": [ + "KYC Links" + ], + "parameters": [ + { + "$ref": "#/components/parameters/IdempotencyKeyParameter" + } + ], + "requestBody": { + "description": "Information about the customer to create KYC Links for", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateKycLinks" + } + } + } + }, + "responses": { + "200": { + "description": "KYC Links generated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndividualKycLinkResponse" + }, + "examples": { + "SuccessfulLiquidationAddressCreateResponse": { + "summary": "KYC Links generated", + "$ref": "#/components/examples/SuccessfulKycLinkCreateResponse" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + }, + "get": { + "summary": "Get all KYC links.", + "description": "Retrieve the full list of kyc links.", + "tags": [ + "KYC Links" + ], + "parameters": [ + { + "$ref": "#/components/parameters/KycLinksCustomerIDParameter" + }, + { + "$ref": "#/components/parameters/KycLinksEmailParameter" + }, + { + "$ref": "#/components/parameters/CustomerStartingAfterParameter" + }, + { + "$ref": "#/components/parameters/CustomerEndingBeforeParameter" + }, + { + "$ref": "#/components/parameters/LimitParameter" + } + ], + "responses": { + "200": { + "description": "Successful KYC links status response", + "content": { + "application/json": { + "schema": { + "title": "Kyc Links", + "type": "object", + "required": [ + "count", + "data" + ], + "properties": { + "count": { + "description": "total number of items in data", + "type": "integer" + }, + "data": { + "type": "array", + "minItems": 0, + "items": { + "$ref": "#/components/schemas/IndividualKycLinkResponse" + } + } + } + }, + "examples": { + "KycLinksGetResponse": { + "summary": "KYC link status for multiple customers", + "$ref": "#/components/examples/KycLinksGetResponse" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "404": { + "$ref": "#/components/responses/NotFoundError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/kyc_links/{kycLinkID}": { + "parameters": [ + { + "$ref": "#/components/parameters/KycLinkIDParameter" + } + ], + "get": { + "summary": "Check the status of a KYC link", + "description": "Retrieve the status of a KYC request from the passed in KYC link id", + "tags": [ + "KYC Links" + ], + "responses": { + "200": { + "description": "Successful KYC link status response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndividualKycLinkResponse" + }, + "examples": { + "ApprovedKYCLinkGetResponse": { + "summary": "KYC link status for an approved customer", + "$ref": "#/components/examples/ApprovedKycLinkGetResponse" + }, + "RejectedKYCLinkGetResponse": { + "summary": "KYC link status for a rejected customer", + "$ref": "#/components/examples/RejectedKycLinkGetResponse" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "404": { + "$ref": "#/components/responses/NotFoundError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/rfis": { + "get": { + "summary": "Get all RFIs", + "description": "Retrieve a list of requests for information (RFIs) raised against your developer or customer accounts", + "tags": [ + "RFIs" + ], + "parameters": [ + { + "$ref": "#/components/parameters/LimitParameter" + }, + { + "$ref": "#/components/parameters/RfiStartingAfterParameter" + }, + { + "$ref": "#/components/parameters/RfiEndingBeforeParameter" + }, + { + "$ref": "#/components/parameters/CustomerIDQueryParameter" + }, + { + "$ref": "#/components/parameters/RfiStateParameter" + } + ], + "responses": { + "200": { + "description": "List of RFIs", + "content": { + "application/json": { + "schema": { + "title": "List of RFIs", + "type": "object", + "required": [ + "count", + "data" + ], + "properties": { + "count": { + "type": "integer", + "description": "The number of items returned" + }, + "data": { + "type": "array", + "minItems": 0, + "items": { + "$ref": "#/components/schemas/Rfi" + } + } + } + }, + "examples": { + "RfiListResponse": { + "$ref": "#/components/examples/RfiListResponse" + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/rfis/{rfiID}": { + "parameters": [ + { + "$ref": "#/components/parameters/RfiIDParameter" + } + ], + "get": { + "summary": "Get an RFI", + "description": "Retrieve a single request for information (RFI) by id", + "tags": [ + "RFIs" + ], + "responses": { + "200": { + "description": "Successful RFI response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Rfi" + }, + "examples": { + "RfiResponse": { + "$ref": "#/components/examples/RfiResponse" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "404": { + "$ref": "#/components/responses/NotFoundError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/static_memos/history": { + "parameters": [ + { + "$ref": "#/components/parameters/DepositIDQueryParameter" + }, + { + "$ref": "#/components/parameters/DepositIDsQueryParameter" + }, + { + "$ref": "#/components/parameters/TxHashParameter" + }, + { + "$ref": "#/components/parameters/LimitParameter" + }, + { + "$ref": "#/components/parameters/EventStartingAfterParameter" + }, + { + "$ref": "#/components/parameters/EventEndingBeforeParameter" + }, + { + "$ref": "#/components/parameters/EventTypeParameter" + } + ], + "get": { + "summary": "Static Memo Activity Across All Customers", + "tags": [ + "Static Memos" + ], + "description": "History of activity across all customers and Virtual Accounts", + "responses": { + "200": { + "description": "List of Static Memo events", + "content": { + "application/json": { + "schema": { + "title": "Static Memo history", + "type": "object", + "required": [ + "count", + "data" + ], + "properties": { + "count": { + "type": "integer", + "description": "The number of events returned" + }, + "data": { + "type": "array", + "minItems": 0, + "items": { + "$ref": "#/components/schemas/StaticMemoEvent" + } + } + } + }, + "examples": { + "History": { + "$ref": "#/components/examples/StaticMemoHistoryExample" + } + } + } + } + } + } + } + }, + "/funds_requests": { + "get": { + "summary": "Get all funds requests", + "description": "Retrieve a list of all funds requests submitted by partnered banks and financial institutions", + "tags": [ + "Funds Requests" + ], + "parameters": [ + { + "$ref": "#/components/parameters/LimitParameter" + }, + { + "$ref": "#/components/parameters/FundsRequestStartingAfterParameter" + }, + { + "$ref": "#/components/parameters/FundsRequestEndingBeforeParameter" + }, + { + "$ref": "#/components/parameters/CustomerIDQueryParameter" + }, + { + "$ref": "#/components/parameters/FraudParameter" + }, + { + "$ref": "#/components/parameters/NoticeDateStartingOnParameter" + }, + { + "$ref": "#/components/parameters/NoticeDateEndingOnParameter" + } + ], + "responses": { + "200": { + "description": "List of funds requests", + "content": { + "application/json": { + "schema": { + "title": "List of funds requests", + "type": "object", + "required": [ + "count", + "data" + ], + "properties": { + "count": { + "type": "integer", + "description": "The number of items returned" + }, + "data": { + "type": "array", + "minItems": 0, + "items": { + "$ref": "#/components/schemas/FundsRequest" + } + } + } + }, + "examples": { + "FundsRequestsResponse": { + "$ref": "#/components/examples/FundsRequestsResponse" + } + } + } + } + } + } + } + }, + "/webhooks": { + "get": { + "summary": "Get all webhook endpoints", + "description": "Get the full list of active and disabled webhook endpoints configured on Bridge", + "tags": [ + "Webhooks" + ], + "responses": { + "200": { + "description": "List of webhook endpoints (the returned list is empty if none found)", + "content": { + "application/json": { + "schema": { + "title": "Webhooks", + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "type": "array", + "minItems": 0, + "items": { + "$ref": "#/components/schemas/Webhook" + } + } + } + }, + "examples": { + "WebhooksFound": { + "summary": "A non-empty list of webhook endpoints", + "value": { + "data": [ + { + "id": "wep_123", + "url": "https://my_endpoint.xyz/hooks", + "status": "active", + "public_key": "-----BEGIN PUBLIC KEY-----\\nFAKEhFnaPLmxxG4a5w0BAQEFAAOCAQ8AMIIBCgKCAQEAtYhc6PV2LOs/nqDRHi0B\\nMKTsdMLHtg58a1NDxaYfw4IZJ3hpy1qIFUgt5X0HhCYZE0Y40MyLGIejPyitEjYw\\ni9/aE+9F/PN+btqN7OK6cVuF9s/R9cZCtNc27UdTQXrUO5T8GXNAMmRr0KFh8yPv\\nfIgpoZn5ZhnyRbZpDvrxHzLmcZJFAX8Ca+KZLzgGVybEqJtP6fKAT0zrrUS1z44s\\nRDOLiXl543cRAmBnUyrT6cXiNz/PNbm4zRK5Nx7LGxBFrCWQCao4Yi8hrwWsnHxg\\n0Tcy3UyZhAcgL6ydVJfLD5x58Ri4BN32WPBtgSSO6JxZZwCiX0d1BOgq7+eNgmzN\\nJQIDAQAB\\n-----END PUBLIC KEY-----\\n" + }, + { + "id": "wep_456", + "url": "https://my_endpoint.xyz/hooks", + "status": "active", + "public_key": "-----BEGIN PUBLIC KEY-----\\nFAKEc27UdTQxxG4a5w0BAQEFAAOCAQ8AMIIBCgKCAQEAtYhc6PV2LOs/nqDRHi0B\\nMKTsdMLHtg58a1NDxaYfw4IZJ3hpy1qIFUgt5X0HhCYZE0Y40MyLGIejPyitEjYw\\ni9/aE+9F/PN+btqN7OK6cVuF9sxG4a5w0BAQEXrUO5T8GXNAMmRr0KFh8yPv\\nfIgpoZn5ZhnyRbZpDvrxHzLmcZJFAX8Ca+KZLzgGVybEqJtP6fKAT0zrrUS1z44s\\nRDOLiXl543cRAmBnUyrT6cXiNz/PNbm4zRK5Nx7LGxBFrCWQCao4Yi8hrwWsnHxg\\n0Tcy3UyZhAcgL6ydVJfLD5x58Ri4BN32WPBtgSSO6JxZZwCiX0d1BOgq7+eNgmzN\\nJQIDAQAB\\n-----END PUBLIC KEY-----\\n" + } + ] + } + }, + "NoWebhooksFound": { + "summary": "An empty list of webhook endpoints", + "value": { + "data": [] + } + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + }, + "post": { + "summary": "Create a webhook endpoint", + "description": "Create a new webhook endpoint to receive events from Bridge. Webhook endpoints begin in a disabled state and can be enabled with a PUT request. A maximum of 5 webhooks can be active or disabled at one time. Webhook endpoints can be created in Sandbox, but no webhook events will be sent.", + "tags": [ + "Webhooks" + ], + "parameters": [ + { + "$ref": "#/components/parameters/IdempotencyKeyParameter" + } + ], + "requestBody": { + "description": "Information about the webhook endpoint to be created", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateWebhook" + } + } + } + }, + "responses": { + "201": { + "description": "Webhook endpoint created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Webhook" + }, + "examples": { + "SuccessfulWebhookCreateResponse": { + "summary": "Webhook created", + "$ref": "#/components/examples/SuccessfulWebhookCreateResponse" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/webhooks/{webhookID}": { + "parameters": [ + { + "$ref": "#/components/parameters/WebhookIDParameter" + } + ], + "put": { + "summary": "Update a webhook", + "description": "Update the specified webhook object", + "tags": [ + "Webhooks" + ], + "requestBody": { + "description": "Updated webhook endpoint object", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PutWebhookPayload" + } + } + } + }, + "responses": { + "200": { + "description": "Successful webhook object response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Webhook" + }, + "examples": { + "SuccessfulWebhookResponse": { + "$ref": "#/components/examples/SuccessfulWebhookUpdateResponse" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "404": { + "$ref": "#/components/responses/NotFoundError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + }, + "delete": { + "summary": "Delete a webhook", + "tags": [ + "Webhooks" + ], + "description": "Delete the specified webhook object. This webhook will no longer be accessible via API.", + "responses": { + "200": { + "description": "Successfully deleted webhook response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Webhook" + }, + "examples": { + "DeletedCustomerResponse": { + "$ref": "#/components/examples/SuccessfulWebhookDeleteResponse" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "404": { + "$ref": "#/components/responses/NotFoundError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/webhooks/{webhookID}/events": { + "parameters": [ + { + "$ref": "#/components/parameters/WebhookIDParameter" + } + ], + "get": { + "summary": "List upcoming events", + "description": "List the next 10 events that will be delivered to the specified webhook.", + "tags": [ + "Webhooks" + ], + "responses": { + "200": { + "description": "List of events (the returned list is empty if none found)", + "content": { + "application/json": { + "schema": { + "title": "Webhook Events", + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "type": "array", + "minItems": 0, + "items": { + "$ref": "#/components/schemas/WebhookEvent" + } + } + } + }, + "examples": { + "WebhookEventsFound": { + "summary": "A non-empty list of webhook events", + "value": { + "data": [ + { + "api_version": "v0", + "event_id": "wh_tmneA3b1rTv1q4gkvmPU53n", + "event_developer_id": "2d127766-02fa-44b0-9fc8-a67665dbf109", + "event_sequence": 1, + "event_category": "transfer", + "event_type": "transfer.deleted", + "event_object_id": "cc598628-29ab-448e-851f-7aaffb1a1171", + "event_object_status": null, + "event_object": { + "id": "cc598628-29ab-448e-851f-7aaffb1a1171", + "state": "awaiting_funds", + "amount": "50.0", + "source": { + "currency": "usdc", + "from_address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F", + "payment_rail": "ethereum" + }, + "receipt": { + "gas_fee": "0.0", + "exchange_fee": "0.0", + "final_amount": "50.0", + "developer_fee": "0.0", + "initial_amount": "50.0", + "subtotal_amount": "50.0", + "url": "https://dashboard.bridge.xyz/transaction/00000000-0000-0000-0000-000000000000/receipt/00000000-0000-0000-0000-000000000000" + }, + "currency": "usd", + "created_at": "2024-05-02T17:48:19.366Z", + "updated_at": "2024-05-02T17:48:19.366Z", + "destination": { + "currency": "usd", + "payment_rail": "ach", + "external_account_id": "24fd61e9-80b6-464a-b5ee-9f7a521cb1f0" + }, + "on_behalf_of": "474c32b3-f3d6-43e3-92ce-a7d4e07fa0a4", + "developer_fee": "0.0", + "source_deposit_instructions": { + "amount": "50.0", + "currency": "usdc", + "to_address": null, + "from_address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F", + "payment_rail": "ethereum" + } + }, + "event_object_changes": { + "state": [ + "pending", + "canceled" + ], + "updated_at": [ + "2024-05-02T15:14:02.842Z", + "2024-05-02T15:15:07.163Z" + ] + }, + "event_created_at": "2024-05-02T17:48:19.465Z" + } + ] + } + }, + "NoWebhooksFound": { + "summary": "An empty list of webhook events", + "value": { + "data": [] + } + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/webhooks/{webhookID}/logs": { + "parameters": [ + { + "$ref": "#/components/parameters/WebhookIDParameter" + } + ], + "get": { + "summary": "View logs", + "description": "Display the most recent logs for deliveries to the specified webhook.", + "tags": [ + "Webhooks" + ], + "responses": { + "200": { + "description": "Recent delivery looks for the webhook (the returned list is empty if none found)", + "content": { + "application/json": { + "schema": { + "title": "Delivery Logs", + "type": "object", + "required": [ + "count", + "data" + ], + "properties": { + "count": { + "type": "integer", + "description": "The number of logs returned" + }, + "data": { + "type": "array", + "minItems": 0, + "items": { + "$ref": "#/components/schemas/WebhookEventDeliveryLog" + } + } + } + }, + "examples": { + "WebhookEventsFound": { + "summary": "A non-empty list of webhook events", + "value": { + "count": 2, + "data": [ + { + "status": 200, + "event_id": "wh_event_id_123", + "response_body": "{\"message\":\"OK\"}", + "created_at": "2024-01-01T00:00:00.000Z" + }, + { + "status": 200, + "event_id": "wh_event_id_456", + "response_body": "{\"message\":\"OK\"}", + "created_at": "2024-01-01T00:00:00.000Z" + } + ] + } + }, + "NoWebhookEventsFound": { + "summary": "An empty list of webhook events", + "value": { + "data": [] + } + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/webhooks/{webhookID}/send": { + "parameters": [ + { + "$ref": "#/components/parameters/WebhookIDParameter" + }, + { + "$ref": "#/components/parameters/IdempotencyKeyParameter" + } + ], + "post": { + "summary": "Send event", + "description": "Send an event to the specified webhook endpoint. This will not effect other events in the delivery queue. This operation is possible for both active and disabled webhook endpoints.", + "tags": [ + "Webhooks" + ], + "requestBody": { + "description": "Specify the event to send to your endpoint.", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SendWebhookPayload" + } + } + } + }, + "responses": { + "200": { + "description": "Event sent successfully", + "content": { + "application/json": { + "schema": { + "title": "Webhook Event Sent", + "type": "object", + "required": [ + "message" + ], + "properties": { + "message": { + "type": "string", + "description": "Message indicating the status of the request" + } + } + }, + "examples": { + "WebhookEventSendSuccessResponse": { + "$ref": "#/components/examples/WebhookEventSendSuccessResponse" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/webhook_events": { + "get": { + "summary": "List webhook events", + "description": "List all webhook events for your account. Events are ordered by their event_sequence in ascending order. Results are limited to the events created in last 90 days.", + "tags": [ + "Webhooks" + ], + "parameters": [ + { + "name": "starting_after", + "in": "query", + "description": "Cursor for forward pagination. Returns events after the specified event ID.", + "required": false, + "schema": { + "type": "string" + }, + "example": "wh_123abc" + }, + { + "name": "ending_before", + "in": "query", + "description": "Cursor for backward pagination. Returns events before the specified event ID.", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "description": "Maximum number of events to return (1-500, default 100).", + "required": false, + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 500, + "default": 100 + } + }, + { + "name": "category", + "in": "query", + "description": "Filter events by category.", + "required": false, + "schema": { + "type": "string", + "enum": [ + "customer", + "external_account", + "kyc_link", + "liquidation_address", + "liquidation_address.drain", + "static_memo.activity", + "transfer", + "virtual_account", + "virtual_account.activity", + "bridge_wallet.activity", + "shift4_base_deposit", + "indexed_deposit", + "card_account", + "posted_card_account_transaction", + "card_transaction", + "card_withdrawal" + ] + } + } + ], + "responses": { + "200": { + "description": "List of webhook events", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "data", + "count" + ], + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/WebhookEvent" + } + }, + "count": { + "type": "integer", + "description": "Number of webhook events returned in this response" + } + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/associated_persons/{associatedPersonID}": { + "parameters": [ + { + "$ref": "#/components/parameters/AssociatedPersonIDParameter" + } + ], + "get": { + "summary": "Get a single associated person", + "tags": [ + "Associated Persons" + ], + "description": "Retrieve an associated person by ID", + "responses": { + "200": { + "description": "Successful associated person response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AssociatedPersonResponse" + }, + "examples": { + "SuccessfulAssociatedPersonResponse": { + "$ref": "#/components/examples/SuccessfulAssociatedPersonResponse" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "404": { + "$ref": "#/components/responses/NotFoundError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + }, + "put": { + "summary": "Update a single associated person", + "tags": [ + "Associated Persons" + ], + "requestBody": { + "description": "Associated person data to update", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AssociatedPerson" + } + } + } + }, + "responses": { + "200": { + "description": "Updated associated person", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AssociatedPersonResponse" + }, + "examples": { + "SuccessfulAssociatedPersonResponse": { + "$ref": "#/components/examples/SuccessfulAssociatedPersonResponse" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "404": { + "$ref": "#/components/responses/NotFoundError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + }, + "delete": { + "summary": "Delete a single associated person", + "tags": [ + "Associated Persons" + ], + "description": "Delete an associated person by ID", + "responses": { + "200": { + "description": "Successfully deleted associated person", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AssociatedPersonResponse" + }, + "examples": { + "SuccessfulAssociatedPersonResponse": { + "$ref": "#/components/examples/SuccessfulAssociatedPersonResponse" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "404": { + "$ref": "#/components/responses/NotFoundError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/travel_rule_data/{id}": { + "post": { + "summary": "Submit travel rule data.", + "tags": [ + "Travel Rule" + ], + "description": "Use this endpoint to submit originator, beneficiary, and transfer purpose data for travel rule compliance.\n", + "parameters": [ + { + "$ref": "#/components/parameters/IdempotencyKeyParameter" + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the resource to associate with this Travel Rule payload. Supported IDs include transfer IDs, virtual account IDs, virtual account event IDs, liquidation address IDs, bridge wallet event IDs, and drain IDs.", + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "The Travel Rule payload to associate with the specified resource.", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TravelRuleData" + } + } + } + }, + "responses": { + "200": { + "description": "Travel Rule data processed successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "message" + ], + "properties": { + "message": { + "type": "string", + "description": "Message indicating the status of the request." + } + } + }, + "examples": { + "TravelRuleDataProcessed": { + "summary": "A successful Travel Rule submission", + "value": { + "message": "Travel rule data processed successfully" + } + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "404": { + "$ref": "#/components/responses/NotFoundError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/exchange_rates": { + "get": { + "summary": "Get current exchange rate between two currencies.", + "description": "Returns the current exchange rate from the \"from\" currency to the \"to\" currency.\nThe exchange rate is updated roughly every 30s. Note that as of this writing,\nBridge does not offer a \"quote\" by which a user can lock in a rate for a given\namount of time. This is provided only as a courtesy to estimate what you are\nlikely to get in a subsequent transfer request that involves currency exchange.\n\nAs of March 2026, we support:\n - `USD <> BRL`\n - `USD <> COP`\n - `USD <> EUR`\n - `USD <> GBP`\n - `USD <> MXN`\n - `USD <> USDT`\n", + "tags": [ + "Exchange Rates" + ], + "parameters": [ + { + "in": "query", + "name": "from", + "required": true, + "description": "The currency code to convert from.", + "example": "usd", + "schema": { + "type": "string", + "enum": [ + "brl", + "cop", + "eur", + "gbp", + "mxn", + "usd", + "usdt" + ] + } + }, + { + "in": "query", + "name": "to", + "required": true, + "description": "The currency code to convert to.", + "example": "eur", + "schema": { + "type": "string", + "enum": [ + "brl", + "cop", + "eur", + "gbp", + "mxn", + "usd", + "usdt" + ] + } + } + ], + "responses": { + "200": { + "description": "The exchange rate information.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "midmarket_rate": { + "type": "string", + "example": "0.93425", + "description": "The midmarket exchange rate." + }, + "buy_rate": { + "type": "string", + "example": "0.9389", + "description": "The rate for buying the target currency, including Bridge's fee." + }, + "sell_rate": { + "type": "string", + "example": "0.9296", + "description": "The rate for selling the target currency, including Bridge's fee." + }, + "updated_at": { + "type": "string", + "format": "date-time", + "example": "2026-01-15T12:00:00.000Z", + "description": "The timestamp when the exchange rate was last collected from the market data provider." + } + } + } + } + } + } + } + } + }, + "/lists/occupation_codes": { + "get": { + "summary": "Get occupation codes", + "description": "Provide this list of occupation codes to your users as possible answers to the Source of Funds section in the KYC flow. The returned list will resemble the list of occupation codes found [here](https://apidocs.bridge.xyz/page/sof-eu-most-recent-occupation-list).\n", + "tags": [ + "Lists" + ], + "responses": { + "200": { + "description": "The list of occupations that can be used during the KYC flow.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "display_name": { + "type": "string", + "example": "Accountant and auditor", + "description": "Human readable name that customers can select." + }, + "code": { + "type": "string", + "example": "132011", + "description": "The corresponding code that should be sent to the Bridge API representing the customers selection." + } + } + } + }, + "examples": { + "OccupationCodesSuccessResponse": { + "$ref": "#/components/examples/OccupationCodesSuccessResponse" + } + } + } + } + } + } + } + }, + "/lists/countries": { + "get": { + "summary": "Get countries", + "description": "Returns a list of countries and subdivisions recognized by Bridge. Inclusion in this list does not guarantee Bridge product support for any country or subdivision.", + "tags": [ + "Lists" + ], + "responses": { + "200": { + "description": "List of supported countries", + "content": { + "application/json": { + "schema": { + "title": "Countries", + "type": "object", + "required": [ + "count", + "data" + ], + "properties": { + "count": { + "description": "The total number of countries recognized by Bridge", + "type": "integer" + }, + "data": { + "type": "array", + "description": "The list of countries recognized by Bridge", + "minItems": 0, + "items": { + "$ref": "#/components/schemas/Country" + } + } + } + } + } + } + } + } + } + }, + "/crypto_return_policies": { + "get": { + "summary": "Get all crypto return policies", + "tags": [ + "Crypto Return Policies" + ], + "description": "Retrieve all crypto return policies for the authenticated developer", + "responses": { + "200": { + "description": "List of crypto return policies", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CryptoReturnPolicy" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + }, + "post": { + "summary": "Create a new crypto return policy", + "tags": [ + "Crypto Return Policies" + ], + "parameters": [ + { + "$ref": "#/components/parameters/IdempotencyKeyParameter" + } + ], + "requestBody": { + "description": "Crypto return policy object to be created", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PostCryptoReturnPoliciesInput" + } + } + } + }, + "responses": { + "201": { + "description": "Crypto return policy created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CryptoReturnPolicy" + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/crypto_return_policies/{policyID}": { + "parameters": [ + { + "name": "policyID", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "put": { + "summary": "Update an existing crypto return policy", + "tags": [ + "Crypto Return Policies" + ], + "requestBody": { + "description": "Crypto return policy object to be updated", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PostCryptoReturnPoliciesInput" + } + } + } + }, + "responses": { + "200": { + "description": "Crypto return policy updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CryptoReturnPolicy" + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "404": { + "$ref": "#/components/responses/NotFoundError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + }, + "delete": { + "summary": "Delete a single crypto return policy object", + "tags": [ + "Crypto Return Policies" + ], + "description": "Delete a crypto return policy object from the passed in crypto return policy ID", + "responses": { + "200": { + "description": "Successfully deleted crypto return policy object response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CryptoReturnPolicy" + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "404": { + "$ref": "#/components/responses/NotFoundError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/customers/{customerID}/card_accounts/{cardAccountID}": { + "parameters": [ + { + "$ref": "#/components/parameters/CustomerIDParameter" + }, + { + "$ref": "#/components/parameters/CardAccountIDParameter" + } + ], + "get": { + "summary": "Retrieve a card account", + "tags": [ + "Cards" + ], + "description": "Retrieve the card account with the specified ID", + "responses": { + "200": { + "description": "The retrieved card account", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CardAccount" + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + }, + "put": { + "summary": "Update a card account", + "description": "Update a card account. Supports changing the settlement currency or closing a card account by setting the status to \"inactive\". Closing permanently cancels all associated cards and is irreversible.", + "tags": [ + "Cards" + ], + "requestBody": { + "description": "The card account update", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "currency": { + "type": "string", + "description": "The new settlement currency for the card account." + }, + "status": { + "type": "string", + "enum": [ + "inactive" + ], + "description": "The desired status for the card account. Currently only \"inactive\" is supported." + } + } + } + } + } + }, + "responses": { + "200": { + "description": "The updated card account", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CardAccount" + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/customers/{customerID}/card_accounts": { + "get": { + "summary": "Get all card accounts", + "tags": [ + "Cards" + ], + "description": "Retrieve all card accounts for a customer. Currently, only one account is supported. An empty array will be returned if no card has been provisioned", + "parameters": [ + { + "$ref": "#/components/parameters/CustomerIDParameter" + } + ], + "responses": { + "200": { + "description": "List of all card accounts owned by the customer", + "content": { + "application/json": { + "schema": { + "title": "Array of all card accounts", + "type": "object", + "required": [ + "count", + "data" + ], + "properties": { + "count": { + "type": "integer", + "description": "The number of card accounts returned" + }, + "data": { + "type": "array", + "minItems": 0, + "items": { + "$ref": "#/components/schemas/CardAccount" + } + } + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + }, + "post": { + "summary": "Provision a card account", + "description": "Provision a card account. NOTE: the legacy Bridge Cards API is deprecated, and stablecoin card issuing capabilities are now natively integrated into Stripe Issuing. Please see [this guide](https://apidocs.bridge.xyz/platform/cards/overview/stripe-issuing) for more details on how to enable your account for Stripe Issuing.", + "deprecated": true, + "tags": [ + "Cards" + ], + "parameters": [ + { + "$ref": "#/components/parameters/IdempotencyKeyParameter" + }, + { + "$ref": "#/components/parameters/CustomerIDParameter" + } + ], + "requestBody": { + "description": "The card account to be provisioned", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PostCardAccountsInput" + } + } + } + }, + "responses": { + "201": { + "description": "The successfully created card account", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CardAccount" + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/customers/{customerID}/card_accounts/{cardAccountID}/freeze": { + "post": { + "summary": "Place a freeze on the card account", + "description": "Place a freeze on the card account", + "tags": [ + "Cards" + ], + "parameters": [ + { + "$ref": "#/components/parameters/IdempotencyKeyParameter" + }, + { + "$ref": "#/components/parameters/CustomerIDParameter" + }, + { + "$ref": "#/components/parameters/CardAccountIDParameter" + } + ], + "requestBody": { + "description": "The freeze to be placed on the card account", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PostCardFreezeInput" + } + } + } + }, + "responses": { + "200": { + "description": "The successfully placed freeze", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/CardFreeze" + } + ], + "properties": { + "status": { + "type": "string", + "description": "The processing status of the freeze request", + "readOnly": true, + "enum": [ + "freeze_created", + "freeze_replaced" + ] + } + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/customers/{customerID}/card_accounts/{cardAccountID}/unfreeze": { + "post": { + "summary": "Unfreeze the card account", + "description": "Remove the freeze on the card account placed by the specified initiator", + "tags": [ + "Cards" + ], + "parameters": [ + { + "$ref": "#/components/parameters/IdempotencyKeyParameter" + }, + { + "$ref": "#/components/parameters/CustomerIDParameter" + }, + { + "$ref": "#/components/parameters/CardAccountIDParameter" + } + ], + "requestBody": { + "description": "A request to unfreeze the card account", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PostCardUnfreezeInput" + } + } + } + }, + "responses": { + "200": { + "description": "The successfully removed freeze", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CardUnfreezeResponse" + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/customers/{customerID}/card_accounts/{cardAccountID}/create_mobile_wallet_provisioning_request": { + "post": { + "summary": "Create a mobile wallet push provisioning request", + "description": "Create a request to push-provision a virtual card to a mobile wallet. This endpoint is part of a multiple-step integration that must be completed with each mobile wallet partner", + "tags": [ + "Cards" + ], + "parameters": [ + { + "$ref": "#/components/parameters/IdempotencyKeyParameter" + }, + { + "$ref": "#/components/parameters/CustomerIDParameter" + }, + { + "$ref": "#/components/parameters/CardAccountIDParameter" + } + ], + "requestBody": { + "description": "A mobile wallet push provisioning request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PostCardPushProvisioningInput" + } + } + } + }, + "responses": { + "200": { + "description": "A successful push provisioning response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CardPushProvisioningResponse" + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/customers/{customerID}/card_accounts/{cardAccountID}/authorizations": { + "get": { + "summary": "Retrieve pending card authorizations", + "description": "Retrieve pending card authorizations.\nNote: this endpoint is not paginated", + "tags": [ + "Cards" + ], + "parameters": [ + { + "$ref": "#/components/parameters/CustomerIDParameter" + }, + { + "$ref": "#/components/parameters/CardAccountIDParameter" + }, + { + "$ref": "#/components/parameters/CardAuthorizationLimitParameter" + }, + { + "$ref": "#/components/parameters/StartingTimeParameter" + }, + { + "$ref": "#/components/parameters/EndingTimeParameter" + }, + { + "$ref": "#/components/parameters/CardAuthorizationStatusParameter" + } + ], + "responses": { + "200": { + "description": "Pending card authorizations", + "content": { + "application/json": { + "schema": { + "title": "List of pending card authorizations", + "type": "object", + "required": [ + "count", + "data" + ], + "properties": { + "count": { + "type": "integer", + "description": "The number of card authorizations returned" + }, + "data": { + "type": "array", + "minItems": 0, + "items": { + "$ref": "#/components/schemas/CardAuthorization" + } + } + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/customers/{customerID}/card_accounts/{cardAccountID}/transactions": { + "get": { + "summary": "Retrieve card transactions", + "description": "Retrieve completed card transactions and card-related crypto transaction activities", + "tags": [ + "Cards" + ], + "parameters": [ + { + "$ref": "#/components/parameters/CustomerIDParameter" + }, + { + "$ref": "#/components/parameters/CardAccountIDParameter" + }, + { + "$ref": "#/components/parameters/CardTransactionLimitParameter" + }, + { + "$ref": "#/components/parameters/StartingTimeParameter" + }, + { + "$ref": "#/components/parameters/EndingTimeParameter" + }, + { + "$ref": "#/components/parameters/PageSizeParameter" + }, + { + "$ref": "#/components/parameters/PageNumberParameter" + }, + { + "$ref": "#/components/parameters/CardTransactionStatusParameter" + }, + { + "$ref": "#/components/parameters/CardTransactionPaginationTokenParameter" + }, + { + "$ref": "#/components/parameters/CardTransactionCategoryFamilyParameter" + } + ], + "responses": { + "200": { + "description": "Card transactions", + "content": { + "application/json": { + "schema": { + "title": "List of card transactions", + "type": "object", + "required": [ + "page", + "count", + "total_pages", + "total_count", + "data" + ], + "properties": { + "page": { + "type": "integer", + "description": "The current page number, starting at 1. Note that this will be returned only for navigating posted transactions." + }, + "pagination_token": { + "type": "string", + "description": "The pagination token to be used to retrieve the next page of transactions. If not provided, use the `page` parameter to navigate by page number." + }, + "count": { + "type": "integer", + "description": "The number of transactions returned" + }, + "total_pages": { + "type": "integer", + "description": "The total number of pages" + }, + "total_count": { + "type": "integer", + "description": "The total number of transactions" + }, + "data": { + "type": "array", + "minItems": 0, + "items": { + "$ref": "#/components/schemas/CardTransaction" + } + } + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/customers/{customerID}/card_accounts/{cardAccountID}/transactions/{transactionID}": { + "get": { + "summary": "Retrieve a card transaction", + "description": "Retrieve a card transaction with the specified ID", + "tags": [ + "Cards" + ], + "parameters": [ + { + "$ref": "#/components/parameters/CustomerIDParameter" + }, + { + "$ref": "#/components/parameters/CardAccountIDParameter" + }, + { + "$ref": "#/components/parameters/CardTransactionIDParameter" + } + ], + "responses": { + "200": { + "description": "Card transactions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CardTransaction" + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/customers/{customerID}/card_accounts/{cardAccountID}/auth_controls": { + "get": { + "summary": "Retrieve authorization controls", + "description": "Retrieve the applicable spend limits for the given card account", + "tags": [ + "Cards" + ], + "parameters": [ + { + "$ref": "#/components/parameters/CustomerIDParameter" + }, + { + "$ref": "#/components/parameters/CardAccountIDParameter" + } + ], + "responses": { + "200": { + "description": "The authorization controls", + "content": { + "application/json": { + "schema": { + "title": "Authorization controls", + "type": "object", + "required": [ + "customer_id", + "card_account_id", + "spending_limits" + ], + "properties": { + "customer_id": { + "type": "string", + "description": "The ID of the customer" + }, + "card_account_id": { + "type": "string", + "description": "The ID of the card account" + }, + "spending_limits": { + "type": "array", + "description": "The various spending limits for the card account for the current time period", + "items": { + "$ref": "#/components/schemas/CardSpendingLimit" + } + } + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/customers/{customerID}/card_accounts/{cardAccountID}/deposit_addresses": { + "post": { + "summary": "Provision an additional top-up deposit address for the card account", + "description": "Provision an additional deposit address for the card account, to allow topping up the card from multiple chains. This is only applicable to Bridge-custodied top-up card accounts. These additional deposit addresses will also be shown in the `additional_funding_instructions` field when fetching the card account details afterwards.", + "tags": [ + "Cards" + ], + "parameters": [ + { + "$ref": "#/components/parameters/IdempotencyKeyParameter" + }, + { + "$ref": "#/components/parameters/CustomerIDParameter" + }, + { + "$ref": "#/components/parameters/CardAccountIDParameter" + } + ], + "requestBody": { + "description": "The chain to provision the new deposit address on.", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PostCardAccountDepositAddressInput" + } + } + } + }, + "responses": { + "200": { + "description": "Details of the successfully created deposit address", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CardAccountFundingInstructions" + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/customers/{customerID}/card_accounts/{cardAccountID}/withdrawals": { + "post": { + "summary": "Create a funds withdrawal request", + "description": "Request a funds withdrawal from the card account, applicable to top-up accounts only. For Bridge wallets, create a [transfer](/api-reference/transfers/create-a-transfer) from the Bridge wallet.", + "tags": [ + "Cards" + ], + "parameters": [ + { + "$ref": "#/components/parameters/IdempotencyKeyParameter" + }, + { + "$ref": "#/components/parameters/CustomerIDParameter" + }, + { + "$ref": "#/components/parameters/CardAccountIDParameter" + } + ], + "requestBody": { + "description": "The withdrawal request", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CardWithdrawal" + } + } + } + }, + "responses": { + "201": { + "description": "The successfully created card funds withdrawal", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CardWithdrawal" + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + }, + "get": { + "summary": "Retrieve the withdrawal history of funds", + "description": "Retrieve the withdrawal history of funds, applicable to top-up accounts only", + "tags": [ + "Cards" + ], + "parameters": [ + { + "$ref": "#/components/parameters/CustomerIDParameter" + }, + { + "$ref": "#/components/parameters/CardAccountIDParameter" + }, + { + "$ref": "#/components/parameters/LimitParameter" + }, + { + "$ref": "#/components/parameters/WithdrawalStartingAfterParameter" + }, + { + "$ref": "#/components/parameters/WithdrawalEndingBeforeParameter" + } + ], + "responses": { + "200": { + "description": "The withdrawal history", + "content": { + "application/json": { + "schema": { + "title": "List of withdrawals", + "type": "object", + "required": [ + "count", + "data" + ], + "properties": { + "count": { + "type": "integer", + "description": "The number of withdrawals returned" + }, + "data": { + "type": "array", + "minItems": 0, + "items": { + "$ref": "#/components/schemas/CardWithdrawal" + } + } + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/customers/{customerID}/card_accounts/{cardAccountID}/withdrawals/{cardWithdrawalID}": { + "get": { + "summary": "Retrieve a card withdrawal", + "description": "Retrieve a card withdrawal with the specified ID, applicable to top-up accounts only", + "tags": [ + "Cards" + ], + "parameters": [ + { + "$ref": "#/components/parameters/CustomerIDParameter" + }, + { + "$ref": "#/components/parameters/CardAccountIDParameter" + }, + { + "$ref": "#/components/parameters/CardWithdrawalIDParameter" + } + ], + "responses": { + "200": { + "description": "The retrieved withdrawal", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CardWithdrawal" + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/customers/{customerID}/card_accounts/{cardAccountID}/statements/{period}.pdf": { + "post": { + "summary": "Generate a card account statement", + "description": "Generate a card account statement for the specified period", + "tags": [ + "Cards" + ], + "parameters": [ + { + "$ref": "#/components/parameters/CustomerIDParameter" + }, + { + "$ref": "#/components/parameters/CardAccountIDParameter" + }, + { + "$ref": "#/components/parameters/CardStatementPeriodParameter" + } + ], + "responses": { + "200": { + "description": "The HTTP response that includes a PDF file as an attachment, with the `Content-Type` set to `application/pdf` and the `Content-Disposition` header configured to indicate it is a statement PDF attachment", + "content": { + "application/pdf": { + "schema": { + "type": "string", + "format": "binary" + } + } + }, + "headers": { + "Content-Disposition": { + "description": "Indicates the content is an attachment with a statement PDF file", + "schema": { + "type": "string", + "example": "inline; filename=\"statement_202412.pdf\"; filename*=UTF-8''statement_202412.pdf" + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/cardholders/{cardholderID}/cards/{cardID}/statements/{period}.pdf": { + "post": { + "summary": "Generate a card statement using Stripe IDs", + "description": "Generate a card account statement for the specified period, using Stripe cardholder and card IDs instead of Bridge internal IDs", + "tags": [ + "Cards" + ], + "parameters": [ + { + "name": "cardholderID", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "The Stripe cardholder ID (e.g. `ich_...`)" + }, + { + "name": "cardID", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "The Stripe card ID (e.g. `ic_...`)" + }, + { + "$ref": "#/components/parameters/CardStatementPeriodParameter" + } + ], + "responses": { + "200": { + "description": "The HTTP response that includes a PDF file as an attachment, with the `Content-Type` set to `application/pdf` and the `Content-Disposition` header configured to indicate it is a statement PDF attachment", + "content": { + "application/pdf": { + "schema": { + "type": "string", + "format": "binary" + } + } + }, + "headers": { + "Content-Disposition": { + "description": "Indicates the content is an attachment with a statement PDF file", + "schema": { + "type": "string", + "example": "inline; filename=\"statement_202412.pdf\"; filename*=UTF-8''statement_202412.pdf" + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/liquidation_addresses/drains": { + "get": { + "summary": "Liquidation Address Activity Across All Customers", + "description": "History of activity across all customers and Liquidation Addresses", + "tags": [ + "Liquidation Addresses" + ], + "parameters": [ + { + "$ref": "#/components/parameters/TxHashParameter" + }, + { + "$ref": "#/components/parameters/LimitParameter" + }, + { + "$ref": "#/components/parameters/DrainStartingAfterParameter" + }, + { + "$ref": "#/components/parameters/DrainEndingBeforeParameter" + }, + { + "$ref": "#/components/parameters/UpdatedAfterMsParameter" + }, + { + "$ref": "#/components/parameters/UpdatedBeforeMsParameter" + }, + { + "$ref": "#/components/parameters/DrainIDQueryParameter" + } + ], + "responses": { + "200": { + "description": "List of drains for all liquidation addresses (the returned list is empty if none found)", + "content": { + "application/json": { + "schema": { + "title": "Liquidation Address history", + "type": "object", + "required": [ + "count", + "data" + ], + "properties": { + "count": { + "type": "integer", + "description": "The number of events returned" + }, + "data": { + "type": "array", + "minItems": 0, + "items": { + "$ref": "#/components/schemas/Drain" + } + } + } + }, + "examples": { + "DrainsToCryptoFound": { + "$ref": "#/components/examples/SuccessfulLiquidationAddressDrainsToCryptoResponse" + }, + "DrainsToFiatFound": { + "$ref": "#/components/examples/SuccessfulLiquidationAddressDrainsToFiatResponse" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/liquidation_addresses/drains/pending": { + "get": { + "summary": "List drains with pending USDT trades", + "description": "Returns drains that have a stuck USDT-to-USD trade awaiting execution. Results are sorted by creation time (newest first) and paginated.\n\nUse `POST /customers/{customerID}/liquidation_addresses/{liquidationAddressID}/drains/{drainID}/execute` to force-execute a pending trade at the current market rate.\n", + "tags": [ + "Liquidation Addresses" + ], + "parameters": [ + { + "$ref": "#/components/parameters/LimitParameter" + }, + { + "$ref": "#/components/parameters/DrainStartingAfterParameter" + }, + { + "$ref": "#/components/parameters/DrainEndingBeforeParameter" + }, + { + "$ref": "#/components/parameters/UpdatedAfterMsParameter" + }, + { + "$ref": "#/components/parameters/UpdatedBeforeMsParameter" + } + ], + "responses": { + "200": { + "description": "List of drains with pending trades (the returned list is empty if none found)", + "content": { + "application/json": { + "schema": { + "title": "PendingDrains", + "type": "object", + "required": [ + "count", + "data" + ], + "properties": { + "count": { + "type": "integer", + "description": "The number of drains returned" + }, + "data": { + "type": "array", + "minItems": 0, + "items": { + "$ref": "#/components/schemas/Drain" + } + } + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/fees/configurations": { + "get": { + "summary": "Get all Developer Fee Configs", + "description": "Beta: available by request only. Contact Bridge to enable this feature for your developer account.\n\nList Developer Fee Configs for the current developer.\n", + "tags": [ + "Developer Fees" + ], + "x-hidden": true, + "parameters": [ + { + "$ref": "#/components/parameters/LimitParameter" + }, + { + "$ref": "#/components/parameters/DeveloperFeeConfigStartingAfterParameter" + }, + { + "$ref": "#/components/parameters/DeveloperFeeConfigEndingBeforeParameter" + } + ], + "responses": { + "200": { + "description": "List of Developer Fee Configs (the returned list is empty if none found)", + "content": { + "application/json": { + "schema": { + "title": "DeveloperFeeConfigs", + "type": "object", + "required": [ + "count", + "data" + ], + "properties": { + "count": { + "description": "total number of items in data", + "type": "integer" + }, + "data": { + "type": "array", + "minItems": 0, + "items": { + "$ref": "#/components/schemas/DeveloperFeeConfig" + } + } + } + }, + "example": { + "count": 1, + "data": [ + { + "id": "dfc_123", + "name": "Standard partner rate", + "schema": "v1", + "default_fee_percentage": "0.1", + "source_asset_fee": { + "usdc": "0.05", + "usdt": "0.2" + }, + "description": null, + "created_at": "2023-11-22T21:31:30.515Z", + "updated_at": "2023-11-22T21:31:30.515Z" + } + ] + } + } + } + }, + "401": { + "$ref": "#/components/responses/DeveloperFeeConfigAuthenticationError" + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + }, + "post": { + "summary": "Create a Developer Fee Config", + "description": "Beta: available by request only. Contact Bridge to enable this feature for your developer account.\n\nCreate a Developer Fee Config.\n", + "tags": [ + "Developer Fees" + ], + "x-hidden": true, + "parameters": [ + { + "$ref": "#/components/parameters/IdempotencyKeyParameter" + } + ], + "requestBody": { + "description": "Developer Fee Config details to be created", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateDeveloperFeeConfig" + } + } + } + }, + "responses": { + "201": { + "description": "A Developer Fee Config object response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeveloperFeeConfig" + } + } + } + }, + "401": { + "$ref": "#/components/responses/DeveloperFeeConfigAuthenticationError" + }, + "400": { + "$ref": "#/components/responses/DeveloperFeeConfigBadRequestError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/fees/configurations/{developerFeeConfigID}": { + "get": { + "summary": "Get a Developer Fee Config", + "description": "Beta: available by request only. Contact Bridge to enable this feature for your developer account.\n\nRetrieve a Developer Fee Config for the specified Developer Fee Config ID.\n", + "tags": [ + "Developer Fees" + ], + "x-hidden": true, + "parameters": [ + { + "$ref": "#/components/parameters/DeveloperFeeConfigIDParameter" + } + ], + "responses": { + "200": { + "description": "A Developer Fee Config object response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeveloperFeeConfig" + } + } + } + }, + "401": { + "$ref": "#/components/responses/DeveloperFeeConfigAuthenticationError" + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "404": { + "$ref": "#/components/responses/DeveloperFeeConfigNotFoundError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + }, + "put": { + "summary": "Update a Developer Fee Config", + "description": "Beta: available by request only. Contact Bridge to enable this feature for your developer account.\n\nFully replaces the Developer Fee Config for the specified Developer Fee Config ID.\n", + "tags": [ + "Developer Fees" + ], + "x-hidden": true, + "parameters": [ + { + "$ref": "#/components/parameters/DeveloperFeeConfigIDParameter" + } + ], + "requestBody": { + "description": "Developer Fee Config details to fully replace the existing config", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateDeveloperFeeConfig" + } + } + } + }, + "responses": { + "200": { + "description": "A Developer Fee Config object response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeveloperFeeConfig" + } + } + } + }, + "401": { + "$ref": "#/components/responses/DeveloperFeeConfigAuthenticationError" + }, + "400": { + "$ref": "#/components/responses/DeveloperFeeConfigBadRequestError" + }, + "404": { + "$ref": "#/components/responses/DeveloperFeeConfigNotFoundError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/rewards/{currency}": { + "get": { + "summary": "Get a summary of all rewards for a given stablecoin", + "description": "Get a summary of all rewards for a given stablecoin", + "tags": [ + "Rewards" + ], + "parameters": [ + { + "$ref": "#/components/parameters/RewardCurrencyParameter" + } + ], + "responses": { + "200": { + "description": "The summary of all rewards for a given stablecoin", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeveloperRewardSummary" + }, + "examples": { + "RewardSummary": { + "$ref": "#/components/examples/DeveloperRewardSummary" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/rewards/{currency}/history": { + "get": { + "summary": "Get daily reward history for a stablecoin", + "description": "Returns paginated daily reward records with per-provider breakdowns, AUM, fees, and distribution status. Data is calculated with a t-2 business day lag; the most recent available record corresponds to two business days prior to the current date.", + "tags": [ + "Rewards" + ], + "parameters": [ + { + "$ref": "#/components/parameters/RewardCurrencyParameter" + }, + { + "name": "limit", + "in": "query", + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 90, + "default": 30 + }, + "description": "Number of days to return per page" + }, + { + "name": "cursor", + "in": "query", + "schema": { + "type": "string" + }, + "description": "Pagination cursor from a previous response" + } + ], + "responses": { + "200": { + "description": "Daily reward history", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeveloperRewardHistory" + }, + "examples": { + "DeveloperRewardHistory": { + "$ref": "#/components/examples/DeveloperRewardHistory" + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequestError" + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/rewards/{currency}/customer/{customerID}": { + "get": { + "summary": "Get a summary of a customer's rewards", + "description": "Get a summary of a customer's rewards", + "tags": [ + "Rewards" + ], + "parameters": [ + { + "$ref": "#/components/parameters/RewardCurrencyParameter" + }, + { + "$ref": "#/components/parameters/CustomerIDParameter" + } + ], + "responses": { + "200": { + "description": "The summary of a customer's rewards", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomerRewardSummary" + }, + "examples": { + "CustomerRewardSummary": { + "$ref": "#/components/examples/CustomerRewardSummary" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/rewards/{currency}/customer/{customerID}/history": { + "get": { + "summary": "Get a history of a customer's rewards", + "description": "Get a history of a customer's rewards. Data is calculated with a t-2 business day lag; the most recent available record corresponds to two business days prior to the current date.", + "tags": [ + "Rewards" + ], + "parameters": [ + { + "$ref": "#/components/parameters/RewardCurrencyParameter" + }, + { + "$ref": "#/components/parameters/CustomerIDParameter" + } + ], + "responses": { + "200": { + "description": "The history of a customer's rewards", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomerRewardHistory" + }, + "examples": { + "CustomerRewardHistory": { + "$ref": "#/components/examples/CustomerRewardHistory" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + }, + "/customers/{customerID}/simulate_kyc_approval": { + "parameters": [ + { + "$ref": "#/components/parameters/CustomerIDParameter" + } + ], + "post": { + "summary": "Simulate KYC approval (sandbox only)", + "tags": [ + "Sandbox" + ], + "parameters": [ + { + "$ref": "#/components/parameters/IdempotencyKeyParameter" + } + ], + "description": "Simulates a KYC/KYB approval for a customer in the sandbox environment. This endpoint is not available in production.\n\nMimics what happens when a customer completes identity verification through the KYC provider in production:\n- Sets the customer's KYC status to `approved`\n- Populates required entity data (name, address, date of birth) using any data already on the customer, falling back to sandbox defaults\n- Approves any pending endorsements, enabling the customer to initiate transfers\n\nUseful for testing the full customer lifecycle without integrating with a real KYC provider.\n", + "responses": { + "200": { + "description": "KYC approval simulated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SimulateKycApprovalResponse" + }, + "examples": { + "SimulateKycApprovalResponse": { + "$ref": "#/components/examples/SimulateKycApprovalResponse" + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/AuthenticationError" + }, + "404": { + "$ref": "#/components/responses/NotFoundError" + }, + "500": { + "$ref": "#/components/responses/UnexpectedError" + } + } + } + } + }, + "components": { + "examples": { + "SimulateKycApprovalResponse": { + "summary": "Successful KYC simulation response", + "value": { + "success": true, + "customer_id": "00000000-0000-0000-0000-000000000000", + "kyc_status": "approved", + "message": "Simulated KYC approval processed. Customer endorsements will be evaluated." + } + }, + "SuccessfulAssociatedPersonResponse": { + "summary": "An associated person object", + "value": { + "id": "associated_person_1234567890", + "email": "associated_person@business.co", + "first_name": "John", + "last_name": "Smith", + "has_ownership": true, + "has_control": true, + "is_signer": true, + "title": "Chief Executive Officer", + "relationship_established_at": "2025-05-27T17:55:33.308Z", + "created_at": "2025-05-27T17:55:33.308Z", + "updated_at": "2025-05-27T17:55:33.308Z" + } + }, + "SuccessfulCustomerResponse": { + "summary": "An individual customer object", + "value": { + "id": "00000000-0000-0000-0000-000000000000", + "first_name": "John", + "last_name": "Doe", + "email": "johndoe@example.com", + "client_reference_id": "your_internal_id_123", + "status": "active", + "type": "individual", + "persona_inquiry_type": "gov_id_db", + "created_at": "2025-11-19T21:14:58.328Z", + "updated_at": "2025-11-19T21:16:02.894Z", + "rejection_reasons": [], + "has_accepted_terms_of_service": true, + "endorsements": [ + { + "name": "base", + "status": "approved", + "requirements": { + "complete": [ + "terms_of_service_v1", + "first_name", + "last_name", + "tax_identification_number", + "email_address", + "address_of_residence", + "date_of_birth", + "proof_of_address", + "sanctions_screen", + "pep_screen", + "blocklist_lookup", + "min_age_18", + "selfie_verification", + "government_id_rejection_checks_passed", + "government_id_review_checks_passed", + "government_id_reliance", + "post_processing" + ], + "pending": [], + "missing": null, + "issues": [] + } + }, + { + "name": "sepa", + "status": "approved", + "requirements": { + "complete": [ + "terms_of_service_v2", + "first_name", + "last_name", + "tax_identification_number", + "email_address", + "address_of_residence", + "date_of_birth", + "proof_of_address", + "sanctions_screen", + "pep_screen", + "blocklist_lookup", + "min_age_18", + "selfie_verification", + "government_id_rejection_checks_passed", + "government_id_review_checks_passed", + "government_id_reliance" + ], + "pending": [], + "missing": null, + "issues": [] + } + } + ], + "future_requirements_due": [], + "requirements_due": [ + "external_account" + ], + "capabilities": { + "payin_crypto": "active", + "payout_crypto": "active", + "payin_fiat": "pending", + "payout_fiat": "pending" + } + } + }, + "SuccessfulCustomerResponse2": { + "summary": "A business customer object", + "value": { + "id": "00000000-0000-0000-0000-000000000000", + "first_name": "Acme Corporation", + "last_name": null, + "email": "business@example.com", + "client_reference_id": "your_internal_id_456", + "status": "active", + "type": "business", + "persona_inquiry_type": "business", + "created_at": "2025-11-19T04:41:33.296Z", + "updated_at": "2025-11-19T19:10:39.393Z", + "rejection_reasons": [], + "has_accepted_terms_of_service": true, + "endorsements": [ + { + "name": "base", + "status": "approved", + "requirements": { + "complete": [ + "terms_of_service_v1", + "business_name", + "business_type", + "business_description", + "is_dao", + "email_address", + "address_of_incorporation", + "address_of_operation", + "tax_identification_number", + "business_industry", + "control_person_ownership_attestation", + "minimal_source_of_funds_data", + "proof_of_address", + "adverse_media_screen", + "sanctions_screen", + "manual_business_ein_verification_review", + "manual_business_registry_verification_review", + "business_website", + "manual_business_website_verification_review", + "business_formation_document_verification", + "manual_business_formation_document_verification_review", + "kyb_review", + { + "associated_person": "11111111-1111-1111-1111-111111111111", + "items": [ + "has_control", + "first_name", + "last_name", + "email_address", + "address_of_residence", + "associated_person_relationship", + "date_of_birth", + "tax_identification_number", + "manual_government_id_review", + "sanctions_screen", + "adverse_media_screen", + "pep_screen", + "min_age_18", + "selfie_verification", + "has_title" + ] + } + ], + "pending": [], + "missing": null, + "issues": [] + } + }, + { + "name": "sepa", + "status": "approved", + "requirements": { + "complete": [ + "terms_of_service_v2", + "business_name", + "business_type", + "business_description", + "is_dao", + "email_address", + "address_of_incorporation", + "address_of_operation", + "tax_identification_number", + "business_industry", + "control_person_ownership_attestation", + "minimal_source_of_funds_data", + "proof_of_address", + "adverse_media_screen", + "sanctions_screen", + "manual_business_ein_verification_review", + "manual_business_registry_verification_review", + "business_website", + "manual_business_website_verification_review", + "business_formation_document_verification", + "manual_business_formation_document_verification_review", + "kyb_review", + { + "associated_person": "11111111-1111-1111-1111-111111111111", + "items": [ + "has_control", + "first_name", + "last_name", + "email_address", + "address_of_residence", + "associated_person_relationship", + "date_of_birth", + "tax_identification_number", + "manual_government_id_review", + "sanctions_screen", + "adverse_media_screen", + "pep_screen", + "min_age_18", + "selfie_verification", + "has_title" + ] + } + ], + "pending": [], + "missing": null, + "issues": [] + } + } + ], + "future_requirements_due": [], + "requirements_due": [ + "external_account" + ], + "capabilities": { + "payin_crypto": "active", + "payout_crypto": "active", + "payin_fiat": "pending", + "payout_fiat": "pending" + }, + "associated_persons": [ + { + "id": "11111111-1111-1111-1111-111111111111", + "email": "person@example.com" + } + ] + } + }, + "SuccessfulFiatPayoutConfigurationResponse": { + "summary": "A fiat payout configuration response", + "value": { + "fiat_payout_configuration": { + "usd": { + "wire": "developer", + "ach": "bridge" + }, + "eur": { + "sepa": "bridge" + }, + "brl": { + "pix": "payment_provider" + }, + "mxn": { + "spei": "payment_provider" + } + } + } + }, + "SuccessfulPatchFiatPayoutConfigurationResponse": { + "summary": "A successful fiat payout configuration update response", + "value": { + "fiat_payout_configuration": { + "usd": { + "wire": "customer", + "ach": "bridge" + }, + "eur": { + "sepa": "bridge" + }, + "brl": { + "pix": "payment_provider" + }, + "mxn": { + "spei": "payment_provider" + } + } + } + }, + "RejectedCustomerResponse": { + "summary": "A rejected customer object", + "value": { + "id": "00000000-0000-0000-0000-000000000000", + "first_name": "John", + "last_name": "Doe", + "email": "johndoe@example.com", + "client_reference_id": "your_internal_id_123", + "status": "rejected", + "type": "individual", + "persona_inquiry_type": "gov_id_db", + "created_at": "2025-11-19T21:05:11.276Z", + "updated_at": "2025-11-19T21:06:20.970Z", + "rejection_reasons": [ + { + "developer_reason": "Incorrect ID type selected.", + "reason": "Incorrect ID type selected.", + "created_at": "2025-11-19T21:05:59.788Z" + }, + { + "developer_reason": "ID from disallowed country.", + "reason": "Cannot accept provided ID", + "created_at": "2025-11-19T21:05:59.788Z" + } + ], + "has_accepted_terms_of_service": true, + "endorsements": [ + { + "name": "base", + "status": "incomplete", + "requirements": { + "complete": [ + "terms_of_service_v1", + "first_name", + "last_name", + "email_address", + "address_of_residence", + "date_of_birth", + "proof_of_address", + "sanctions_screen", + "pep_screen", + "blocklist_lookup", + "min_age_18", + "selfie_verification" + ], + "pending": [ + "manual_review" + ], + "missing": { + "all_of": [ + "tax_identification_number", + "source_of_funds_questionnaire" + ] + }, + "issues": [ + "government_id_verification_failed" + ] + }, + "additional_requirements": [ + "kyc_approval" + ] + }, + { + "name": "sepa", + "status": "incomplete", + "requirements": { + "complete": [ + "terms_of_service_v2", + "first_name", + "last_name", + "email_address", + "address_of_residence", + "date_of_birth", + "proof_of_address", + "sanctions_screen", + "pep_screen", + "blocklist_lookup", + "min_age_18", + "selfie_verification" + ], + "pending": [ + "manual_review" + ], + "missing": { + "all_of": [ + "tax_identification_number", + "source_of_funds_questionnaire" + ] + }, + "issues": [ + "government_id_verification_failed" + ] + }, + "additional_requirements": [ + "kyc_approval", + "kyc_with_proof_of_address" + ] + } + ], + "future_requirements_due": [], + "requirements_due": [ + "external_account" + ], + "capabilities": { + "payin_crypto": "pending", + "payout_crypto": "pending", + "payin_fiat": "pending", + "payout_fiat": "pending" + } + } + }, + "AchOfframpTransferResponse": { + "summary": "A successful ACH offramp transfer (crypto to ACH)", + "value": { + "id": "00000000-0000-0000-0000-000000000003", + "client_reference_id": "client_transfer_id_123", + "state": "awaiting_funds", + "on_behalf_of": "00000000-0000-0000-0000-000000000001", + "amount": "75.0", + "developer_fee": "0.0", + "source": { + "payment_rail": "ethereum", + "currency": "usdc", + "from_address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F" + }, + "destination": { + "payment_rail": "ach", + "currency": "usd", + "external_account_id": "00000000-0000-0000-0000-000000000002" + }, + "source_deposit_instructions": { + "payment_rail": "ethereum", + "amount": "75.0", + "currency": "usdc", + "from_address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F", + "to_address": "0xb794f5ea0ba39494ce839613fffba74279579268" + }, + "receipt": { + "initial_amount": "75.0", + "developer_fee": "0.0", + "exchange_fee": "0.0", + "subtotal_amount": "75.0", + "gas_fee": "0.0", + "final_amount": "75.0", + "url": "https://dashboard.bridge.xyz/transaction/00000000-0000-0000-0000-000000000000/receipt/00000000-0000-0000-0000-000000000000" + }, + "created_at": "2020-01-01T00:00:00.000Z", + "updated_at": "2020-01-02T00:00:00.000Z" + } + }, + "AchOfframpWithMemoTransferResponse": { + "summary": "A successful ACH offramp transfer with memo (Tron/Stellar to ACH)", + "value": { + "id": "00000000-0000-0000-0000-000000000003", + "client_reference_id": "client_transfer_id_123", + "state": "awaiting_funds", + "on_behalf_of": "00000000-0000-0000-0000-000000000001", + "amount": "75.0", + "developer_fee": "0.0", + "source": { + "payment_rail": "tron", + "currency": "usdt", + "from_address": "TFCVwYhQxMXTeFGmWb45uMk1qsJ4DRMPVS" + }, + "destination": { + "payment_rail": "ach", + "currency": "usd", + "external_account_id": "00000000-0000-0000-0000-000000000002" + }, + "source_deposit_instructions": { + "payment_rail": "tron", + "amount": "75.0", + "currency": "usdc", + "from_address": "TFCVwYhQxMXTeFGmWb45uMk1qsJ4DRMPVS", + "to_address": "TUEB3vjcMx7mPvc8DmeDLevZU3wEnkZ1zs", + "blockchain_memo": "BRGEXAMPLEMEMO" + }, + "receipt": { + "initial_amount": "75.0", + "developer_fee": "0.0", + "exchange_fee": "0.0", + "subtotal_amount": "75.0", + "gas_fee": "0.0", + "final_amount": "75.0", + "url": "https://dashboard.bridge.xyz/transaction/00000000-0000-0000-0000-000000000000/receipt/00000000-0000-0000-0000-000000000000" + }, + "created_at": "2020-01-01T00:00:00.000Z", + "updated_at": "2020-01-02T00:00:00.000Z" + } + }, + "SepaOfframpTransferResponse": { + "summary": "A successful SEPA offramp transfer (crypto to SEPA)", + "value": { + "id": "00000000-0000-0000-0000-000000000003", + "client_reference_id": "client_transfer_id_123", + "state": "awaiting_funds", + "on_behalf_of": "00000000-0000-0000-0000-000000000001", + "amount": "75.0", + "developer_fee": "0.0", + "source": { + "payment_rail": "ethereum", + "currency": "usdc", + "from_address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F" + }, + "destination": { + "payment_rail": "sepa", + "currency": "eur", + "external_account_id": "00000000-0000-0000-0000-000000000002", + "sepa_reference": "SEPA reference" + }, + "source_deposit_instructions": { + "payment_rail": "ethereum", + "amount": "75.0", + "currency": "usdc", + "from_address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F", + "to_address": "0xb794f5ea0ba39494ce839613fffba74279579268" + }, + "receipt": { + "initial_amount": "75.0", + "developer_fee": "0.0", + "exchange_fee": "0.0", + "subtotal_amount": "75.0", + "gas_fee": "0.0", + "final_amount": "68.27", + "url": "https://dashboard.bridge.xyz/transaction/00000000-0000-0000-0000-000000000000/receipt/00000000-0000-0000-0000-000000000000" + }, + "created_at": "2020-01-01T00:00:00.000Z", + "updated_at": "2020-01-02T00:00:00.000Z" + } + }, + "AchOnrampFundsReceivedTransferResponse": { + "summary": "A successful ACH onramp transfer in funds_received state (ACH to crypto)", + "value": { + "id": "00000000-0000-0000-0000-000000000004", + "client_reference_id": "client_transfer_id_456", + "state": "funds_received", + "on_behalf_of": "00000000-0000-0000-0000-000000000001", + "amount": "500.25", + "developer_fee": "0.0", + "source": { + "payment_rail": "ach", + "currency": "usd", + "external_account_id": "00000000-0000-0000-0000-000000000002" + }, + "destination": { + "payment_rail": "ethereum", + "currency": "usdc", + "to_address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F" + }, + "receipt": { + "initial_amount": "500.25", + "developer_fee": "0.0", + "exchange_fee": "0.0", + "subtotal_amount": "500.25", + "gas_fee": "0.0", + "final_amount": "500.25", + "destination_tx_hash": "0xdeadbeef", + "url": "https://dashboard.bridge.xyz/transaction/00000000-0000-0000-0000-000000000000/receipt/00000000-0000-0000-0000-000000000000" + }, + "created_at": "2020-01-02T00:00:00.000Z", + "updated_at": "2020-01-03T00:00:00.000Z" + } + }, + "WireOnrampTransferResponse": { + "summary": "A successful Wire onramp transfer (wire to crypto)", + "value": { + "id": "00000000-0000-0000-0000-000000000003", + "client_reference_id": "client_transfer_id_123", + "state": "pending", + "on_behalf_of": "00000000-0000-0000-0000-000000000001", + "amount": "75.0", + "developer_fee": "0.0", + "source": { + "payment_rail": "wire", + "currency": "usd", + "external_account_id": null, + "bank_beneficiary_name": "Sender name, if available", + "bank_beneficiary_address": "Sender address, if available", + "bank_routing_number": "Sender routing, if available", + "bank_name": "Sender bank, if available", + "imad": "IMAD of incoming wire, if available", + "omad": "OMAD of incoming wire, if available (deprecated)" + }, + "destination": { + "payment_rail": "ethereum", + "currency": "usdc", + "to_address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F" + }, + "source_deposit_instructions": { + "payment_rail": "wire", + "amount": "75.0", + "currency": "usd", + "deposit_message": "BVI7depositmessage", + "bank_name": "Bank name", + "bank_address": "Bank address", + "bank_routing_number": "123456789", + "bank_account_number": "1234567890", + "bank_beneficiary_name": "Bank beneficiary", + "bank_beneficiary_address": "Bank beneficiary address" + }, + "receipt": { + "initial_amount": "75.0", + "developer_fee": "0.0", + "exchange_fee": "0.0", + "subtotal_amount": "75.0", + "gas_fee": "0.0", + "final_amount": "75.0", + "url": "https://dashboard.bridge.xyz/transaction/00000000-0000-0000-0000-000000000000/receipt/00000000-0000-0000-0000-000000000000" + }, + "created_at": "2020-01-01T00:00:00.000Z", + "updated_at": "2020-01-02T00:00:00.000Z" + } + }, + "AchOnrampTransferResponse": { + "summary": "A successful ACH onramp transfer (ACH to crypto)", + "value": { + "id": "00000000-0000-0000-0000-000000000003", + "client_reference_id": "client_transfer_id_123", + "state": "pending", + "on_behalf_of": "00000000-0000-0000-0000-000000000001", + "amount": "75.0", + "developer_fee": "0.0", + "source": { + "payment_rail": "ach_push", + "currency": "usd", + "external_account_id": null, + "description": "ACH description, if available" + }, + "destination": { + "payment_rail": "ethereum", + "currency": "usdc", + "to_address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F" + }, + "source_deposit_instructions": { + "payment_rail": "ach_push", + "amount": "75.0", + "currency": "usd", + "deposit_message": "BVI7depositmessage", + "bank_name": "Bank name", + "bank_address": "Bank address", + "bank_routing_number": "123456789", + "bank_account_number": "1234567890", + "bank_beneficiary_name": "Bank beneficiary", + "bank_beneficiary_address": "Bank beneficiary address" + }, + "receipt": { + "initial_amount": "75.0", + "developer_fee": "0.0", + "exchange_fee": "0.0", + "subtotal_amount": "75.0", + "gas_fee": "0.0", + "final_amount": "75.0", + "url": "https://dashboard.bridge.xyz/transaction/00000000-0000-0000-0000-000000000000/receipt/00000000-0000-0000-0000-000000000000" + }, + "created_at": "2020-01-01T00:00:00.000Z", + "updated_at": "2020-01-02T00:00:00.000Z" + } + }, + "SepaOnrampTransferResponse": { + "summary": "A successful SEPA onramp transfer (SEPA to crypto)", + "value": { + "id": "00000000-0000-0000-0000-000000000003", + "client_reference_id": "client_transfer_id_123", + "state": "pending", + "on_behalf_of": "00000000-0000-0000-0000-000000000001", + "amount": "75.0", + "developer_fee": "0.0", + "source": { + "payment_rail": "sepa", + "currency": "eur", + "external_account_id": null + }, + "destination": { + "payment_rail": "ethereum", + "currency": "usdc", + "to_address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F" + }, + "source_deposit_instructions": { + "payment_rail": "sepa", + "amount": "75.0", + "currency": "eur", + "deposit_message": "BRG7depositmessage", + "bank_name": "Bank name", + "bank_address": "Bank address", + "iban": "123456789", + "bic": "1234567890", + "account_holder_name": "Bank account holder name" + }, + "receipt": { + "initial_amount": "75.0", + "developer_fee": "0.0", + "exchange_fee": "0.0", + "gas_fee": "0.0", + "url": "https://dashboard.bridge.xyz/transaction/00000000-0000-0000-0000-000000000000/receipt/00000000-0000-0000-0000-000000000000" + }, + "created_at": "2020-01-01T00:00:00.000Z", + "updated_at": "2020-01-02T00:00:00.000Z" + } + }, + "WireOfframpTransferResponse": { + "summary": "A successful Wire offramp transfer (crypto to wire)", + "value": { + "id": "00000000-0000-0000-0000-000000000003", + "client_reference_id": "client_transfer_id_123", + "state": "awaiting_funds", + "on_behalf_of": "00000000-0000-0000-0000-000000000001", + "amount": "500.0", + "developer_fee": "0.0", + "source": { + "payment_rail": "ethereum", + "currency": "usdc", + "from_address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F" + }, + "destination": { + "payment_rail": "wire", + "currency": "usd", + "external_account_id": "00000000-0000-0000-0000-000000000002" + }, + "source_deposit_instructions": { + "payment_rail": "ethereum", + "amount": "500.0", + "currency": "usdc", + "from_address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F", + "to_address": "0xb794f5ea0ba39494ce839613fffba74279579268" + }, + "receipt": { + "initial_amount": "500.0", + "developer_fee": "0.0", + "exchange_fee": "0.0", + "subtotal_amount": "500.0", + "gas_fee": "0.0", + "final_amount": "500.0", + "url": "https://dashboard.bridge.xyz/transaction/00000000-0000-0000-0000-000000000000/receipt/00000000-0000-0000-0000-000000000000" + }, + "created_at": "2020-01-01T00:00:00.000Z", + "updated_at": "2020-01-02T00:00:00.000Z" + } + }, + "PixOnrampTransferResponse": { + "summary": "A successful Pix onramp transfer (Pix to crypto)", + "value": { + "id": "00000000-0000-0000-0000-000000000003", + "client_reference_id": "client_transfer_id_123", + "state": "pending", + "on_behalf_of": "00000000-0000-0000-0000-000000000001", + "amount": "75.0", + "developer_fee": "0.0", + "source": { + "payment_rail": "pix", + "currency": "brl", + "external_account_id": null, + "description": "Pix transfer description, if available" + }, + "destination": { + "payment_rail": "ethereum", + "currency": "usdc", + "to_address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F" + }, + "source_deposit_instructions": { + "payment_rail": "pix", + "amount": "75.0", + "currency": "brl", + "deposit_message": "BRG7depositmessage", + "pix_key": "12345678901", + "account_holder_name": "João Silva" + }, + "receipt": { + "initial_amount": "75.0", + "developer_fee": "0.0", + "exchange_fee": "0.0", + "subtotal_amount": "75.0", + "gas_fee": "0.0", + "final_amount": "68.50", + "url": "https://dashboard.bridge.xyz/transaction/00000000-0000-0000-0000-000000000000/receipt/00000000-0000-0000-0000-000000000000" + }, + "created_at": "2020-01-01T00:00:00.000Z", + "updated_at": "2020-01-02T00:00:00.000Z" + } + }, + "PixOfframpTransferResponse": { + "summary": "A successful Pix offramp transfer (crypto to Pix)", + "value": { + "id": "00000000-0000-0000-0000-000000000003", + "client_reference_id": "client_transfer_id_123", + "state": "awaiting_funds", + "on_behalf_of": "00000000-0000-0000-0000-000000000001", + "amount": "75.0", + "developer_fee": "0.0", + "source": { + "payment_rail": "ethereum", + "currency": "usdc", + "from_address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F" + }, + "destination": { + "payment_rail": "pix", + "currency": "brl", + "external_account_id": "00000000-0000-0000-0000-000000000002", + "reference": "Pix payment reference", + "transaction_id": "E12345678202501011230ABCDEFGHIJK", + "sending_institution_name": "Woovi Instituição de Pagamento LTDA" + }, + "source_deposit_instructions": { + "payment_rail": "ethereum", + "amount": "75.0", + "currency": "usdc", + "from_address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F", + "to_address": "0xb794f5ea0ba39494ce839613fffba74279579268" + }, + "receipt": { + "initial_amount": "75.0", + "developer_fee": "0.0", + "exchange_fee": "0.0", + "subtotal_amount": "75.0", + "gas_fee": "0.0", + "final_amount": "68.50", + "url": "https://dashboard.bridge.xyz/transaction/00000000-0000-0000-0000-000000000000/receipt/00000000-0000-0000-0000-000000000000" + }, + "created_at": "2020-01-01T00:00:00.000Z", + "updated_at": "2020-01-02T00:00:00.000Z" + } + }, + "SpeiOfframpTransferResponse": { + "summary": "A successful SPEI offramp transfer (crypto to SPEI)", + "value": { + "id": "00000000-0000-0000-0000-000000000003", + "client_reference_id": "client_transfer_id_123", + "state": "awaiting_funds", + "on_behalf_of": "00000000-0000-0000-0000-000000000001", + "amount": "75.0", + "developer_fee": "0.0", + "source": { + "payment_rail": "ethereum", + "currency": "usdc", + "from_address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F" + }, + "destination": { + "payment_rail": "spei", + "currency": "mxn", + "external_account_id": "00000000-0000-0000-0000-000000000002", + "spei_reference": "SPEI reference", + "tracking_number": "1234567890123456789012345678", + "sending_institution_name": "Sistema de Transferencias y Pagos STP, S.A. de C.V." + }, + "source_deposit_instructions": { + "payment_rail": "ethereum", + "amount": "75.0", + "currency": "usdc", + "from_address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F", + "to_address": "0xb794f5ea0ba39494ce839613fffba74279579268" + }, + "receipt": { + "initial_amount": "75.0", + "developer_fee": "0.0", + "exchange_fee": "0.0", + "subtotal_amount": "75.0", + "gas_fee": "0.0", + "final_amount": "1492.50", + "url": "https://dashboard.bridge.xyz/transaction/00000000-0000-0000-0000-000000000000/receipt/00000000-0000-0000-0000-000000000000" + }, + "created_at": "2020-01-01T00:00:00.000Z", + "updated_at": "2020-01-02T00:00:00.000Z" + } + }, + "BreBOnrampTransferResponse": { + "summary": "A successful Bre-B onramp transfer (COP to crypto)", + "value": { + "id": "00000000-0000-0000-0000-000000000005", + "state": "awaiting_funds", + "on_behalf_of": "00000000-0000-0000-0000-000000000001", + "amount": "5000000.0", + "developer_fee": "0.0", + "source": { + "payment_rail": "bre_b", + "currency": "cop" + }, + "destination": { + "payment_rail": "ethereum", + "currency": "usdc", + "to_address": "0xdeadbeef" + }, + "source_deposit_instructions": { + "payment_rail": "bre_b", + "amount": "5000000.0", + "currency": "cop", + "deposit_message": "COP7depositmessage", + "bre_b_key": "12345678901234567890", + "account_holder_name": "Bridge Developer Name" + }, + "created_at": "2020-01-01T00:00:00.000Z", + "updated_at": "2020-01-02T00:00:00.000Z" + } + }, + "BreBOfframpTransferResponse": { + "summary": "A successful Bre-B offramp transfer (crypto to COP)", + "value": { + "id": "00000000-0000-0000-0000-000000000004", + "client_reference_id": "client_transfer_id_456", + "state": "awaiting_funds", + "on_behalf_of": "00000000-0000-0000-0000-000000000001", + "amount": "100.0", + "developer_fee": "0.0", + "source": { + "payment_rail": "ethereum", + "currency": "usdc", + "from_address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F" + }, + "destination": { + "payment_rail": "bre_b", + "currency": "cop", + "external_account_id": "00000000-0000-0000-0000-000000000002" + }, + "source_deposit_instructions": { + "payment_rail": "ethereum", + "amount": "100.0", + "currency": "usdc", + "from_address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F", + "to_address": "0xb794f5ea0ba39494ce839613fffba74279579268" + }, + "receipt": { + "initial_amount": "100.0", + "developer_fee": "0.0", + "exchange_fee": "0.0", + "subtotal_amount": "100.0", + "gas_fee": "0.0", + "final_amount": "420000.0", + "url": "https://dashboard.bridge.xyz/transaction/00000000-0000-0000-0000-000000000000/receipt/00000000-0000-0000-0000-000000000000" + }, + "created_at": "2020-01-01T00:00:00.000Z", + "updated_at": "2020-01-02T00:00:00.000Z" + } + }, + "CoBankTransferOnrampTransferResponse": { + "summary": "A successful Colombian bank transfer onramp (COP to crypto)", + "value": { + "id": "00000000-0000-0000-0000-000000000006", + "state": "awaiting_funds", + "on_behalf_of": "00000000-0000-0000-0000-000000000001", + "amount": "5000000.0", + "developer_fee": "0.0", + "source": { + "payment_rail": "co_bank_transfer", + "currency": "cop", + "co_bank_transfer": { + "sender_data": { + "full_name": "María López", + "document_type": "cc", + "document_number": "***7890", + "email": "maria@example.com", + "phone_number": "+573001234567" + } + } + }, + "destination": { + "payment_rail": "ethereum", + "currency": "usdc", + "to_address": "0xdeadbeef" + }, + "source_deposit_instructions": { + "payment_rail": "co_bank_transfer", + "amount": "5000000.0", + "currency": "cop", + "start_url": "https://example.com/co-bank-transfer/pay/abc123", + "redirect_url": "https://merchant.example.com/return", + "expires_at": "2026-05-01T00:30:00.000Z", + "account_holder_name": "Bridge Developer Name" + }, + "created_at": "2020-01-01T00:00:00.000Z", + "updated_at": "2020-01-02T00:00:00.000Z" + } + }, + "CoBankTransferOfframpTransferResponse": { + "summary": "A successful Colombian bank transfer offramp (crypto to COP)", + "value": { + "id": "00000000-0000-0000-0000-000000000007", + "state": "awaiting_funds", + "on_behalf_of": "00000000-0000-0000-0000-000000000001", + "amount": "100.0", + "developer_fee": "0.0", + "source": { + "payment_rail": "ethereum", + "currency": "usdc", + "from_address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F" + }, + "destination": { + "payment_rail": "co_bank_transfer", + "currency": "cop", + "external_account_id": "00000000-0000-0000-0000-000000000002" + }, + "source_deposit_instructions": { + "payment_rail": "ethereum", + "amount": "100.0", + "currency": "usdc", + "from_address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F", + "to_address": "0xb794f5ea0ba39494ce839613fffba74279579268" + }, + "receipt": { + "initial_amount": "100.0", + "developer_fee": "0.0", + "exchange_fee": "0.0", + "subtotal_amount": "100.0", + "gas_fee": "0.0", + "final_amount": "420000.0", + "url": "https://dashboard.bridge.xyz/transaction/00000000-0000-0000-0000-000000000000/receipt/00000000-0000-0000-0000-000000000000" + }, + "created_at": "2020-01-01T00:00:00.000Z", + "updated_at": "2020-01-02T00:00:00.000Z" + } + }, + "SpeiOnrampTransferResponse": { + "summary": "A successful SPEI onramp transfer (SPEI to crypto)", + "value": { + "id": "00000000-0000-0000-0000-000000000003", + "client_reference_id": "client_transfer_id_123", + "state": "pending", + "on_behalf_of": "00000000-0000-0000-0000-000000000001", + "amount": "500.0", + "developer_fee": "0.0", + "source": { + "payment_rail": "spei", + "currency": "mxn", + "external_account_id": null, + "clabe": "646180546700000164", + "tracking_number": "1234567890123456789012345678", + "sender_name": "Sender Business Name", + "reference": "Payment reference" + }, + "destination": { + "payment_rail": "ethereum", + "currency": "usdc", + "to_address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F" + }, + "source_deposit_instructions": { + "payment_rail": "spei", + "amount": "500.0", + "currency": "mxn", + "deposit_message": "MXN7depositmessage", + "clabe": "646180115400000007", + "account_holder_name": "Bridge Developer Name", + "bank_name": "STP" + }, + "receipt": { + "initial_amount": "500.0", + "developer_fee": "0.0", + "exchange_fee": "0.0", + "subtotal_amount": "500.0", + "gas_fee": "0.0", + "final_amount": "24.88", + "url": "https://dashboard.bridge.xyz/transaction/00000000-0000-0000-0000-000000000000/receipt/00000000-0000-0000-0000-000000000000" + }, + "created_at": "2020-01-01T00:00:00.000Z", + "updated_at": "2020-01-02T00:00:00.000Z" + } + }, + "ValidTransferRouteResponse": { + "summary": "A valid transfer route response", + "value": { + "state": "valid", + "notes": [ + "This is a valid transfer route" + ] + } + }, + "CreateAchExternalAccountRequest": { + "summary": "Create ACH or Wire External Account (US)", + "value": { + "currency": "usd", + "bank_name": "Wells Fargo", + "account_owner_name": "John Doe", + "account_type": "us", + "account": { + "account_number": "1210002481111", + "routing_number": "121000248", + "checking_or_savings": "checking" + }, + "address": { + "street_line_1": "123 Main St", + "city": "San Francisco", + "state": "CA", + "postal_code": "94102", + "country": "USA" + } + } + }, + "CreateIbanExternalAccountRequest": { + "summary": "Create IBAN External Account", + "value": { + "currency": "eur", + "bank_name": "AAC CAPITAL PARTNERS LIMITED", + "account_owner_name": "John Doe", + "account_type": "iban", + "iban": { + "account_number": "NL91ABNA0417164300", + "bic": "BARBGB2LLEI", + "country": "NLD" + }, + "account_owner_type": "individual", + "first_name": "John", + "last_name": "Doe", + "address": { + "street_line_1": "Dam 1", + "city": "Amsterdam", + "postal_code": "1012 JS", + "country": "NLD" + } + } + }, + "CreateClabeExternalAccountRequest": { + "summary": "Create CLABE External Account (SPEI for MXN)", + "value": { + "currency": "mxn", + "bank_name": "Banco Santander México", + "account_owner_name": "Juan García", + "account_type": "clabe", + "clabe": { + "account_number": "014180655500000007" + }, + "account_owner_type": "individual", + "first_name": "Juan", + "last_name": "García", + "address": { + "street_line_1": "Avenida Paseo de la Reforma 500", + "city": "Ciudad de México", + "postal_code": "06600", + "country": "MEX" + } + } + }, + "CreatePixExternalAccountRequest": { + "summary": "Create Pix External Account with Pix Key (Brazil)", + "value": { + "currency": "brl", + "bank_name": "Banco do Brasil", + "account_owner_name": "João Silva", + "account_type": "pix", + "pix_key": { + "pix_key": "joao.silva@email.com", + "document_number": "12345678901" + }, + "account_owner_type": "individual", + "first_name": "João", + "last_name": "Silva", + "address": { + "street_line_1": "Rua XV de Novembro, 500", + "city": "São Paulo", + "state": "SP", + "postal_code": "01013-001", + "country": "BRA" + } + } + }, + "CreateBrCodeExternalAccountRequest": { + "summary": "Create Pix External Account with BR Code (Brazil)", + "value": { + "currency": "brl", + "bank_name": "Banco do Brasil", + "account_owner_name": "João Silva", + "account_type": "pix", + "br_code": { + "br_code": "00020126580014br.gov.bcb.pix0136a629532e-7693-4846-852d-1bbff6b2f8cd520400005303986540510.005802BR5913Fulano de Tal6008BRASILIA62070503***63041D3D", + "document_number": "12345678901" + }, + "account_owner_type": "individual", + "first_name": "João", + "last_name": "Silva", + "address": { + "street_line_1": "Rua XV de Novembro, 500", + "city": "São Paulo", + "state": "SP", + "postal_code": "01013-001", + "country": "BRA" + } + } + }, + "CreateBreBExternalAccountRequest": { + "summary": "Create Bre-B External Account (COP)", + "value": { + "currency": "cop", + "account_owner_name": "Juan Garcia", + "account_type": "bre_b", + "account": { + "bre_b_key": "1234567890123456" + } + } + }, + "CreateCoBankTransferExternalAccountRequest": { + "summary": "Create CO Bank Transfer External Account (COP)", + "value": { + "currency": "cop", + "account_owner_name": "María López", + "account_type": "co_bank_transfer", + "account": { + "account_number": "12345678901234", + "bank_code": "1007", + "account_type": "savings", + "document_type": "cc", + "document_number": "1234567890", + "phone_number": "+573001234567" + }, + "account_owner_type": "individual", + "first_name": "María", + "last_name": "López" + } + }, + "SuccessfulExternalAccountResponse": { + "summary": "A successful ACH External Account object (US)", + "value": { + "id": "ea_123", + "account_type": "us", + "currency": "usd", + "customer_id": "cust_123", + "account_owner_name": "John Doe", + "bank_name": "Wells Fargo", + "last_4": "1111", + "active": true, + "beneficiary_address_valid": true, + "account": { + "last_4": "1111", + "routing_number": "121000248", + "checking_or_savings": "checking" + }, + "created_at": "2020-01-01T00:00:00.000Z", + "updated_at": "2020-01-02T00:00:00.000Z" + } + }, + "SuccessfulFeeExternalAccountResponse": { + "summary": "A successful Fee External Account object (ACH)", + "value": { + "id": "fea_123", + "account_type": "us", + "currency": "usd", + "account_owner_name": "John Doe", + "bank_name": "Wells Fargo", + "last_4": "1111", + "active": true, + "beneficiary_address_valid": true, + "account": { + "last_4": "1111", + "routing_number": "121000248", + "checking_or_savings": "checking" + }, + "created_at": "2020-01-01T00:00:00.000Z", + "updated_at": "2020-01-02T00:00:00.000Z" + } + }, + "SuccessfulIbanExternalAccountResponse": { + "summary": "A successful IBAN External Account object", + "value": { + "id": "ea_123", + "customer_id": "cust_123", + "account_type": "iban", + "currency": "eur", + "account_owner_name": "John Doe", + "bank_name": "AAC CAPITAL PARTNERS LIMITED", + "active": true, + "iban": { + "last_4": "5981", + "bic": "BARBGB2LLEI", + "country": "NLD" + }, + "account_owner_type": "individual", + "first_name": "John", + "last_name": "Doe", + "account_verification": { + "iban": { + "match_level": "match", + "reason_code": null, + "validated_account_owner_name": "John Doe" + }, + "requested_at": "2020-01-01T00:05:00.000Z", + "completed_at": "2020-01-01T00:05:05.000Z" + }, + "created_at": "2020-01-01T00:00:00.000Z", + "updated_at": "2020-01-02T00:00:00.000Z" + } + }, + "SuccessfulPixKeyExternalAccountResponse": { + "summary": "A successful Pix key External Account object", + "value": { + "id": "ea_123", + "customer_id": "cust_123", + "account_type": "pix", + "currency": "brl", + "account_owner_name": "João Silva", + "bank_name": "Banco do Brasil", + "active": true, + "pix_key": { + "account_preview": "jo****ilva****il.c**", + "document_number_last4": "8901" + }, + "account_validation": { + "validated_account_owner_name": "João Silva", + "validated_bank_name": "Banco do Brasil" + }, + "account_owner_type": "individual", + "first_name": "João", + "last_name": "Silva", + "account_verification": { + "pix": { + "matched": true, + "reason_code": null, + "validated_account_owner_name": "João Silva", + "validated_bank_name": "Banco do Brasil" + }, + "requested_at": "2020-01-01T00:05:00.000Z", + "completed_at": "2020-01-01T00:05:05.000Z" + }, + "created_at": "2020-01-01T00:00:00.000Z", + "updated_at": "2020-01-02T00:00:00.000Z" + } + }, + "SuccessfulBrCodeExternalAccountResponse": { + "summary": "A successful BR Code External Account object", + "value": { + "id": "ea_456", + "customer_id": "cust_456", + "account_type": "pix", + "currency": "brl", + "account_owner_name": "Maria Santos", + "bank_name": "Itaú Unibanco", + "active": true, + "br_code": { + "account_preview": "11****1111****1111****1111", + "document_number_last4": "0131" + }, + "account_validation": { + "validated_account_owner_name": "Maria Santos", + "validated_bank_name": "Itaú Unibanco" + }, + "account_owner_type": "individual", + "first_name": "Maria", + "last_name": "Santos", + "account_verification": { + "pix": { + "matched": true, + "reason_code": null, + "validated_account_owner_name": "Maria Santos", + "validated_bank_name": "Itaú Unibanco" + }, + "requested_at": "2020-01-01T00:05:00.000Z", + "completed_at": "2020-01-01T00:05:05.000Z" + }, + "created_at": "2020-01-01T00:00:00.000Z", + "updated_at": "2020-01-02T00:00:00.000Z" + } + }, + "SuccessfulBreBExternalAccountResponse": { + "summary": "A successful Bre-B External Account object (COP)", + "value": { + "id": "ea_789", + "customer_id": "cust_789", + "account_type": "bre_b", + "currency": "cop", + "account_owner_name": "Juan Garcia", + "bank_name": "Banco de Bogota", + "active": true, + "account": { + "last_4": "0000" + }, + "account_validation": { + "validated_account_owner_name": "Juan Garcia", + "validated_bank_name": "Banco de Bogota", + "validated_document_number_last4": "0000" + }, + "account_owner_type": "individual", + "first_name": "Juan", + "last_name": "Garcia", + "account_verification": { + "bre_b": { + "matched": true, + "reason_code": null, + "validated_account_owner_name": "Juan Garcia", + "validated_bank_name": "Banco de Bogota", + "validated_document_number_last4": "0000" + }, + "requested_at": "2020-01-01T00:05:00.000Z", + "completed_at": "2020-01-01T00:05:05.000Z" + }, + "created_at": "2020-01-01T00:00:00.000Z", + "updated_at": "2020-01-02T00:00:00.000Z" + } + }, + "SuccessfulCoBankTransferExternalAccountResponse": { + "summary": "A successful CO Bank Transfer External Account object (COP)", + "value": { + "id": "ea_012", + "customer_id": "cust_012", + "account_type": "co_bank_transfer", + "currency": "cop", + "account_owner_name": "Maria Lopez", + "bank_name": "Bancolombia", + "active": true, + "account": { + "last_4": "1234", + "routing_number": "1007" + }, + "account_owner_type": "individual", + "first_name": "Maria", + "last_name": "Lopez", + "account_verification": { + "co_bank_transfer": { + "matched": true, + "reason_code": null, + "validated_account_owner_name": "Maria Lopez", + "validated_bank_name": "Bancolombia", + "validated_document_number_last4": "9012" + }, + "requested_at": "2020-01-01T00:05:00.000Z", + "completed_at": "2020-01-01T00:05:05.000Z" + }, + "created_at": "2020-01-01T00:00:00.000Z", + "updated_at": "2020-01-02T00:00:00.000Z" + } + }, + "SuccessfulClabeExternalAccountResponse": { + "summary": "A successful CLABE External Account object (SPEI)", + "value": { + "id": "ea_567", + "customer_id": "cust_567", + "account_type": "clabe", + "currency": "mxn", + "account_owner_name": "Juan García", + "bank_name": "Banco Santander México", + "active": true, + "clabe": { + "last_4": "0007" + }, + "account_validation": { + "validated_account_owner_name": "Juan García", + "validated_bank_name": "Banco Santander México" + }, + "account_owner_type": "individual", + "first_name": "Juan", + "last_name": "García", + "account_verification": { + "clabe": { + "matched": true, + "reason_code": null, + "validated_account_owner_name": "Juan García", + "validated_bank_name": "Banco Santander México" + }, + "requested_at": "2020-01-01T00:05:00.000Z", + "completed_at": "2020-01-01T00:05:05.000Z" + }, + "created_at": "2020-01-01T00:00:00.000Z", + "updated_at": "2020-01-02T00:00:00.000Z" + } + }, + "SuccessfulPrefundedAccountResponse": { + "summary": "A successful Prefunded Account object", + "value": { + "id": "f15972de-4cdd-460c-9da3-34f7321bfa3f", + "currency": "usd", + "available_balance": "134.12", + "name": "my_account", + "created_at": "2020-01-01T00:00:00.000Z", + "updated_at": "2020-01-02T00:00:00.000Z" + } + }, + "SuccessfulPrefundedAccountHistoryResponse": { + "summary": "A successful Prefunded Account history", + "value": { + "count": 1, + "data": [ + { + "id": "abced012-4cdd-460c-9da3-34f7321bfa3f", + "amount": "500.00", + "available_balance": "1300.31", + "currency": "usd", + "name": "my_account", + "type": "funding", + "created_at": "2020-01-01T00:00:00.000Z" + } + ] + } + }, + "VirtualAccountPaymentSubmmittedEventFromAchPush": { + "value": { + "id": "va_event_456", + "customer_id": "cust_alice", + "virtual_account_id": "va_123", + "type": "payment_submitted", + "amount": "120.0", + "currency": "usd", + "developer_fee_amount": "1.25", + "exchange_fee_amount": "2.2", + "subtotal_amount": "120.0", + "gas_fee": "0.0", + "deposit_id": "deposit_123", + "created_at": "2024-01-01T00:00:00.000Z", + "destination_tx_hash": "0xdeadbeef", + "source": { + "payment_rail": "ach_push", + "description": "ACH description", + "sender_name": "The name of the business or individual who initiated the ACH", + "sender_bank_routing_number": "The routing number of the entity that initiated this ACH transaction", + "trace_number": "The unique, a 15-digit number associated with each ACH transaction that is used for tracking and reconciling transactions" + } + } + }, + "VirtualAccountFundsReceivedEventFromAchPush": { + "value": { + "id": "va_event_123", + "customer_id": "cust_alice", + "virtual_account_id": "va_123", + "type": "funds_received", + "amount": "123.45", + "currency": "usd", + "developer_fee_amount": "0.0", + "exchange_fee_amount": "0.0", + "subtotal_amount": "123.45", + "gas_fee": "0.0", + "deposit_id": "deposit_123", + "created_at": "2024-01-01T00:00:00.000Z", + "source": { + "payment_rail": "ach_push", + "description": "ACH description", + "sender_name": "The name of the business or individual who initiated the ACH", + "sender_bank_routing_number": "The routing number of the entity that initiated this ACH transaction", + "trace_number": "The unique, a 15-digit number associated with each ACH transaction that is used for tracking and reconciling transactions" + } + } + }, + "VirtualAccountPaymentProcessedEventFromSpei": { + "value": { + "id": "va_event_789", + "customer_id": "cust_alice", + "virtual_account_id": "va_456", + "type": "payment_processed", + "amount": "123.45", + "currency": "usdc", + "developer_fee_amount": "0.0", + "exchange_fee_amount": "0.0", + "subtotal_amount": "123.45", + "gas_fee": "0.0", + "deposit_id": "deposit_789", + "created_at": "2025-06-01T00:00:00.000Z", + "source": { + "payment_rail": "spei", + "description": "Receiving CLABE | clave de rastreo | SPEI reference", + "tracking_number": "The unique tracking number or clave de rastreo for this SPEI transaction", + "sender_name": "The name of the business or individual who initiated the SPEI credit", + "clabe": "646180546700000164", + "reference": "The reference or concepto de pago for this SPEI transaction" + } + } + }, + "VirtualAccountHistoryExample": { + "summary": "A list of event history across all customers and Virtual Accounts", + "value": { + "count": 3, + "data": [ + { + "id": "va_event_456", + "customer_id": "cust_alice", + "virtual_account_id": "va_123", + "type": "payment_submitted", + "amount": "120.0", + "currency": "usd", + "developer_fee_amount": "1.25", + "exchange_fee_amount": "2.2", + "subtotal_amount": "120.0", + "gas_fee": "0.0", + "deposit_id": "deposit_123", + "created_at": "2024-01-01T00:00:00.000Z", + "destination_tx_hash": "0xdeadbeef", + "source": { + "payment_rail": "ach_push", + "description": "ACH description", + "sender_name": "The name of the business or individual who initiated the ACH", + "sender_bank_routing_number": "The routing number of the entity that initiated this ACH transaction", + "trace_number": "The unique, a 15-digit number associated with each ACH transaction that is used for tracking and reconciling transactions" + } + }, + { + "id": "va_event_123", + "customer_id": "cust_alice", + "virtual_account_id": "va_123", + "type": "funds_received", + "amount": "123.45", + "currency": "usd", + "developer_fee_amount": "0.0", + "exchange_fee_amount": "0.0", + "subtotal_amount": "123.45", + "gas_fee": "0.0", + "deposit_id": "deposit_123", + "created_at": "2024-01-01T00:00:00.000Z", + "source": { + "payment_rail": "ach_push", + "description": "ACH description", + "sender_name": "The name of the business or individual who initiated the ACH", + "sender_bank_routing_number": "The routing number of the entity that initiated this ACH transaction", + "trace_number": "The unique, a 15-digit number associated with each ACH transaction that is used for tracking and reconciling transactions" + } + }, + { + "id": "va_event_789", + "customer_id": "cust_alice", + "virtual_account_id": "va_456", + "type": "payment_processed", + "amount": "123.45", + "currency": "usdc", + "developer_fee_amount": "0.0", + "exchange_fee_amount": "0.0", + "subtotal_amount": "123.45", + "gas_fee": "0.0", + "deposit_id": "deposit_789", + "created_at": "2025-06-01T00:00:00.000Z", + "source": { + "payment_rail": "spei", + "description": "Receiving CLABE | clave de rastreo | SPEI reference", + "tracking_number": "The unique tracking number or clave de rastreo for this SPEI transaction", + "sender_name": "The name of the business or individual who initiated the SPEI credit", + "clabe": "646180546700000164", + "reference": "The reference or concepto de pago for this SPEI transaction" + } + } + ] + } + }, + "StaticMemoHistoryExample": { + "summary": "A list of event history across all customers and Virtual Accounts", + "value": { + "count": 4, + "data": [ + { + "id": "sm_event_456", + "customer_id": "cust_alice", + "virtual_account_id": "sm_123", + "type": "payment_submitted", + "amount": "120.0", + "currency": "usd", + "developer_fee_amount": "1.25", + "exchange_fee_amount": "2.2", + "subtotal_amount": "120.0", + "gas_fee": "0.0", + "deposit_id": "deposit_123", + "created_at": "2020-01-01T00:00:00.000Z", + "destination_tx_hash": "0xdeadbeef", + "source_deposit_instructions": { + "deposit_message": "BVI7depositmessage" + }, + "source": { + "payment_rail": "ach_push", + "description": "ACH description, if available" + } + }, + { + "id": "sm_event_123", + "customer_id": "cust_alice", + "virtual_account_id": "sm_123", + "type": "funds_received", + "amount": "123.45", + "currency": "usd", + "developer_fee_amount": "0.0", + "exchange_fee_amount": "0.0", + "subtotal_amount": "123.45", + "gas_fee": "0.0", + "deposit_id": "deposit_123", + "created_at": "2020-01-01T00:00:00.000Z", + "source_deposit_instructions": { + "deposit_message": "BVI7depositmessage" + }, + "source": { + "payment_rail": "ach_push", + "description": "ACH description, if available" + } + }, + { + "id": "sm_event_457", + "customer_id": "cust_alice", + "virtual_account_id": "sm_123", + "type": "payment_submitted", + "amount": "120.0", + "currency": "usd", + "developer_fee_amount": "1.25", + "exchange_fee_amount": "2.2", + "subtotal_amount": "120.0", + "gas_fee": "0.0", + "deposit_id": "deposit_123", + "created_at": "2020-01-01T00:00:00.000Z", + "destination_tx_hash": "0xdeadbeef", + "source_deposit_instructions": { + "deposit_message": "BVI7depositmessage" + }, + "source": { + "payment_rail": "wire", + "bank_beneficiary_name": "Bank beneficiary", + "bank_beneficiary_address": "Bank beneficiary address", + "originator_name": "Originator Name", + "originator_address": "Originator Address", + "bank_routing_number": "1234567890", + "bank_name": "Bank name", + "imad": "IMAD of incoming wire, if available", + "omad": "OMAD of incoming wire, if available (deprecated)" + } + }, + { + "id": "sm_event_124", + "customer_id": "cust_alice", + "virtual_account_id": "sm_123", + "type": "funds_received", + "amount": "123.45", + "currency": "usd", + "developer_fee_amount": "0.0", + "exchange_fee_amount": "0.0", + "subtotal_amount": "123.45", + "gas_fee": "0.0", + "deposit_id": "deposit_123", + "created_at": "2020-01-01T00:00:00.000Z", + "source_deposit_instructions": { + "deposit_message": "BVI7depositmessage" + }, + "source": { + "payment_rail": "wire", + "bank_beneficiary_name": "Bank beneficiary", + "bank_beneficiary_address": "Bank beneficiary address", + "originator_name": "Originator Name", + "originator_address": "Originator Address", + "bank_routing_number": "1234567890", + "bank_name": "Bank name", + "imad": "IMAD of incoming wire, if available", + "omad": "OMAD of incoming wire, if available (deprecated)" + } + } + ] + } + }, + "CryptoPayinResponse": { + "summary": "A successful payin", + "value": { + "id": "payin_456", + "customer_id": "cust_123", + "payment_rail": "ethereum", + "currency": "usdc", + "amount": "100.88", + "state": "completed", + "transaction_hash": "0xc13d7905be5c989378a945487cd2a1193627ae606009e28e296d48ddaec66162", + "to_address": "0x4d0280da2f2fDA5103914bCc5aad114743152A9c" + } + }, + "WirePayinResponse": { + "summary": "A successful payin", + "value": { + "id": "payin_456", + "customer_id": "cust_123", + "payment_rail": "wire", + "currency": "usd", + "amount": "400.25", + "state": "completed" + } + }, + "WirePayoutResponse": { + "summary": "A successful payout", + "value": { + "id": "payout_789", + "customer_id": "cust_123", + "payment_rail": "wire", + "currency": "usd", + "amount": "9999.99", + "external_account_id": "ea_123", + "state": "completed" + } + }, + "PlaidLinkRequestSuccessResponse": { + "summary": "Successful Plaid Link token creation", + "value": { + "link_token": "plaid_link_token_123", + "link_token_expires_at": "2023-03-23T03:22:34.086Z", + "callback_url": "https://api.bridge.xyz/v0/plaid_exchange_public_token/plaid_link_token_123" + } + }, + "SuccessfulKycLinkCreateResponse": { + "summary": "Successful KYC link creation", + "value": { + "id": "kyc_link_123", + "full_name": "John Doe", + "email": "johndoe@johndoe.com", + "type": "individual", + "kyc_link": "www.kyclink.com/blah", + "tos_link": "www.toslink.com/blah", + "kyc_status": "not_started", + "tos_status": "pending", + "customer_id": "cust_123" + } + }, + "ApprovedKycLinkGetResponse": { + "summary": "Approved KYC link", + "value": { + "id": "kyc_link_123", + "full_name": "John Doe", + "email": "johndoe@johndoe.com", + "type": "individual", + "kyc_link": "www.kyclink.com/blah", + "tos_link": "www.toslink.com/blah", + "kyc_status": "approved", + "rejection_reasons": [], + "tos_status": "approved", + "customer_id": "cust_123" + } + }, + "RejectedKycLinkGetResponse": { + "summary": "Rejected KYC link", + "value": { + "id": "kyc_link_123", + "full_name": "John Doe", + "email": "johndoe@johndoe.com", + "type": "individual", + "kyc_link": "www.kyclink.com/blah", + "tos_link": "www.toslink.com/blah", + "kyc_status": "rejected", + "rejection_reasons": [ + { + "developer_reason": "Missing required ID details.", + "reason": "Cannot validate ID -- upload a clear photo of the full ID", + "created_at": "2020-01-02T00:00:00.000Z" + }, + { + "developer_reason": "Blurry face portrait.", + "reason": "Cannot validate ID -- upload a clear photo of the full ID", + "created_at": "2020-01-02T00:00:00.000Z" + } + ], + "tos_status": "approved", + "customer_id": "cust_123" + } + }, + "KycLinksGetResponse": { + "summary": "A list of KYC links", + "value": { + "count": 2, + "data": [ + { + "id": "kyc_link_123", + "full_name": "John Doe", + "email": "johndoe@johndoe.com", + "type": "individual", + "kyc_link": "www.kyclink.com/blah", + "tos_link": "www.toslink.com/blah", + "kyc_status": "approved", + "rejection_reasons": [], + "tos_status": "approved", + "customer_id": "cust_123" + }, + { + "id": "kyc_link_456", + "full_name": "Jane Doe", + "email": "janedoe@janedoe.com", + "type": "individual", + "kyc_link": "www.kyclink.com/blah", + "tos_link": "www.toslink.com/blah", + "kyc_status": "rejected", + "rejection_reasons": [ + { + "developer_reason": "Missing required ID details.", + "reason": "Cannot validate ID -- upload a clear photo of the full ID", + "created_at": "2020-01-02T00:00:00.000Z" + }, + { + "developer_reason": "Blurry face portrait.", + "reason": "Cannot validate ID -- upload a clear photo of the full ID", + "created_at": "2020-01-02T00:00:00.000Z" + } + ], + "tos_status": "approved", + "customer_id": "cust_456" + } + ] + } + }, + "SuccessfulBridgeWalletCreateResponse": { + "summary": "A successful Bridge Wallet creation response", + "value": { + "id": "bw_123", + "chain": "solana", + "address": "9kV3ZMehKVyxfHKCcaDLye3P9HHw2MP4jtQa2gKBUmCs", + "created_at": "2023-11-22T21:31:30.515Z", + "updated_at": "2023-11-22T21:31:30.515Z" + } + }, + "WithdrawalBridgeWalletEvent": { + "summary": "An outgoing transfer from a bridge wallet initiated by a transfer", + "value": { + "count": 1, + "data": [ + { + "id": "bwe_123", + "bridge_wallet_id": "bw_123", + "amount": "500.000000", + "available_balance": "500.000000", + "currency": "usdc", + "type": "withdrawal", + "source": { + "currency": "usdc", + "payment_rail": "ethereum" + }, + "destination": { + "currency": "usd", + "payment_rail": "ach" + }, + "payment_route": { + "type": "transfer", + "customer_id": "cust_123", + "transfer_id": "transfer_123" + }, + "created_at": "2025-01-01T00:00:00.000Z" + } + ] + } + }, + "DepositDrainBridgeWalletEvent": { + "summary": "A deposit to a bridge wallet via a liquidation address drain", + "value": { + "count": 1, + "data": [ + { + "id": "bwe_123", + "bridge_wallet_id": "bw_123", + "amount": "50.000000", + "available_balance": "1050.000000", + "currency": "usdc", + "type": "deposit", + "source": { + "currency": "usd", + "payment_rail": "ach" + }, + "destination": { + "currency": "usdc", + "payment_rail": "ethereum", + "tx_hash": "0xdeadbeef" + }, + "payment_route": { + "type": "drain", + "customer_id": "cust_123", + "drain_id": "drain_123", + "liquidation_address_id": "la_123" + }, + "created_at": "2025-01-01T00:00:00.000Z" + } + ] + } + }, + "DepositStaticMemoEventBridgeWalletEvent": { + "summary": "A deposit to a bridge wallet via a static memo fiat payment", + "value": { + "count": 1, + "data": [ + { + "id": "bwe_123", + "bridge_wallet_id": "bw_123", + "amount": "200.000000", + "available_balance": "1200.000000", + "currency": "usdc", + "type": "deposit", + "source": { + "currency": "usd", + "payment_rail": "wire" + }, + "destination": { + "currency": "usdc", + "payment_rail": "ethereum", + "tx_hash": "0xdeadbeef" + }, + "payment_route": { + "type": "static_memo_event", + "customer_id": "cust_123", + "deposit_id": "dep_123", + "static_memo_event_id": "sme_123", + "static_memo_id": "sm_123" + }, + "created_at": "2025-01-01T00:00:00.000Z" + } + ] + } + }, + "DepositVirtualAccountEventBridgeWalletEvent": { + "summary": "A deposit to a bridge wallet via a virtual account payment", + "value": { + "count": 1, + "data": [ + { + "id": "bwe_123", + "bridge_wallet_id": "bw_123", + "amount": "75.000000", + "available_balance": "1075.000000", + "currency": "usdc", + "type": "deposit", + "source": { + "currency": "usd", + "payment_rail": "ach" + }, + "destination": { + "currency": "usdc", + "payment_rail": "ethereum", + "tx_hash": "0xdeadbeef" + }, + "payment_route": { + "type": "virtual_account_event", + "customer_id": "cust_123", + "deposit_id": "dep_123", + "virtual_account_event_id": "vae_123", + "virtual_account_id": "va_123" + }, + "created_at": "2025-01-01T00:00:00.000Z" + } + ] + } + }, + "DepositTransferBridgeWalletEvent": { + "summary": "A deposit to a bridge wallet via a transfer payment", + "value": { + "count": 1, + "data": [ + { + "id": "bwe_123", + "bridge_wallet_id": "bw_123", + "amount": "300.000000", + "available_balance": "1300.000000", + "currency": "usdc", + "type": "deposit", + "source": { + "currency": "usd", + "payment_rail": "ach" + }, + "destination": { + "currency": "usdc", + "payment_rail": "ethereum", + "tx_hash": "0xdeadbeef" + }, + "payment_route": { + "type": "transfer", + "customer_id": "cust_123", + "transfer_id": "transfer_123" + }, + "created_at": "2025-01-01T00:00:00.000Z" + } + ] + } + }, + "DirectDepositBridgeWalletEvent": { + "summary": "A deposit to a bridge wallet directly on the blockchain", + "value": { + "count": 1, + "data": [ + { + "id": "bwe_123", + "bridge_wallet_id": "bw_123", + "amount": "25.000000", + "available_balance": "1025.000000", + "currency": "usdc", + "type": "direct_deposit", + "source": { + "currency": "usdc", + "payment_rail": "ethereum", + "from_address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F" + }, + "destination": { + "currency": "usdc", + "payment_rail": "ethereum", + "tx_hash": "0xdeadbeef" + }, + "created_at": "2025-01-01T00:00:00.000Z" + } + ] + } + }, + "ReturnBridgeWalletEvent": { + "summary": "An outgoing transfer from a bridge wallet that was rejected for AML reasons was returned", + "value": { + "count": 1, + "data": [ + { + "id": "bwe_123", + "bridge_wallet_id": "bw_123", + "amount": "150.000000", + "available_balance": "1150.000000", + "currency": "usdc", + "type": "return", + "source": { + "currency": "usd", + "payment_rail": "ach" + }, + "destination": { + "currency": "usdc", + "payment_rail": "ethereum" + }, + "payment_route": { + "type": "transfer", + "customer_id": "cust_123", + "transfer_id": "transfer_123" + }, + "created_at": "2025-01-01T00:00:00.000Z" + } + ] + } + }, + "UndeliverableBridgeWalletEvent": { + "summary": "An outgoing transfer from a bridge wallet that could not be delivered was returned", + "value": { + "count": 1, + "data": [ + { + "id": "bwe_123", + "bridge_wallet_id": "bw_123", + "amount": "80.000000", + "available_balance": "1080.000000", + "currency": "usdc", + "type": "undeliverable", + "source": { + "currency": "usd", + "payment_rail": "ach" + }, + "destination": { + "currency": "usdc", + "payment_rail": "ethereum" + }, + "payment_route": { + "type": "transfer", + "customer_id": "cust_123", + "transfer_id": "transfer_123" + }, + "created_at": "2025-01-01T00:00:00.000Z" + } + ] + } + }, + "CardSpendBridgeWalletEvent": { + "summary": "A card spend debiting the bridge wallet to fund a card authorization", + "value": { + "count": 1, + "data": [ + { + "id": "bwe_123", + "bridge_wallet_id": "bw_123", + "amount": "25.500000", + "available_balance": "974.500000", + "currency": "usdc", + "type": "card_spend", + "source": { + "currency": "usdc", + "from_address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F", + "payment_rail": "base" + }, + "destination": { + "currency": "usdc", + "payment_rail": "card_spend_internal_funding" + }, + "payment_route": { + "type": "card_spend", + "customer_id": "cust_123", + "card_crypto_transaction_id": "cct_123", + "issuing_authorization_id": "iauth_123", + "issuing_transaction_id": "ipi_456" + }, + "created_at": "2025-01-01T00:00:00.000Z" + } + ] + } + }, + "CardRefundBridgeWalletEvent": { + "summary": "A card refund crediting the bridge wallet after a confirmed card spend is returned", + "value": { + "count": 1, + "data": [ + { + "id": "bwe_123", + "bridge_wallet_id": "bw_123", + "amount": "10.450000", + "available_balance": "1010.450000", + "currency": "usdc", + "type": "card_refund", + "source": { + "currency": "usdc", + "from_address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F", + "payment_rail": "base" + }, + "destination": { + "currency": "usdc", + "payment_rail": "card_spend_internal_funding" + }, + "payment_route": { + "type": "card_spend", + "customer_id": "cust_123", + "issuing_authorization_id": "iauth_789", + "issuing_transaction_id": "ipi_012" + }, + "created_at": "2025-01-01T00:00:00.000Z" + } + ] + } + }, + "SuccessfulBridgeWalletGetResponse": { + "summary": "A successful get response for a Bridge Wallet", + "value": { + "id": "bw_123", + "chain": "solana", + "address": "9kV3ZMehKVyxfHKCcaDLye3P9HHw2MP4jtQa2gKBUmCs", + "created_at": "2023-11-22T21:31:30.515Z", + "updated_at": "2023-11-22T21:31:30.515Z", + "balances": [ + { + "balance": "100.25", + "currency": "usdb", + "chain": "solana", + "contract_address": "ENL66PGy8d8j5KNqLtCcg4uidDUac5ibt45wbjH9REzB" + } + ] + } + }, + "SuccessfulBridgeWalletListResponse": { + "summary": "A successful get response for a list of Bridge Wallets", + "value": { + "count": 1, + "data": [ + { + "id": "bw_123", + "chain": "solana", + "address": "9kV3ZMehKVyxfHKCcaDLye3P9HHw2MP4jtQa2gKBUmCs", + "created_at": "2023-11-22T21:31:30.515Z", + "updated_at": "2023-11-22T21:31:30.515Z" + } + ] + } + }, + "SuccessfulLiquidationAddressCreateResponse": { + "summary": "A successful Liquidation Address creation response", + "value": { + "id": "la_123", + "chain": "ethereum", + "customer_id": "cust_123", + "external_account_id": "ext_123", + "address": "0x4d0280da2f2fDA5103914bCc5aad114743152A9c", + "currency": "usdc", + "supported_currencies": { + "ethereum": [ + "usdc" + ] + }, + "state": "active", + "created_at": "2023-11-22T21:31:30.515Z", + "updated_at": "2023-11-22T21:31:30.515Z" + } + }, + "SuccessfulMultiChainLiquidationAddressCreateResponse": { + "summary": "A creation response for a multi-chain, multi-currency Liquidation Address", + "value": { + "id": "la_123", + "chain": "evm", + "customer_id": "cust_123", + "external_account_id": "ext_123", + "address": "0x4d0280da2f2fDA5103914bCc5aad114743152A9c", + "currency": "all_supported", + "supported_currencies": { + "ethereum": [ + "usdc", + "eurc" + ], + "polygon": [ + "usdc" + ], + "base": [ + "usdc", + "eurc" + ] + }, + "state": "active", + "created_at": "2023-11-22T21:31:30.515Z", + "updated_at": "2023-11-22T21:31:30.515Z" + } + }, + "SuccessfulSepaLiquidationAddressCreateResponse": { + "summary": "A creation response using SEPA as the destination rail", + "value": { + "id": "la_123", + "chain": "ethereum", + "customer_id": "cust_123", + "external_account_id": "ext_123", + "address": "0x4d0280da2f2fDA5103914bCc5aad114743152A9c", + "currency": "usdc", + "destination_sepa_reference": "SEPA reference", + "destination_payment_rail": "sepa", + "destination_currency": "eur", + "supported_currencies": { + "ethereum": [ + "usdc" + ] + }, + "state": "active", + "created_at": "2023-11-22T21:31:30.515Z", + "updated_at": "2023-11-22T21:31:30.515Z" + } + }, + "SuccessfulLiquidationAddressGetResponse": { + "summary": "A successful get response for a Liquidation Address", + "value": { + "id": "la_123", + "chain": "ethereum", + "customer_id": "cust_123", + "external_account_id": "ext_123", + "address": "0x4d0280da2f2fDA5103914bCc5aad114743152A9c", + "currency": "usdc", + "destination_payment_rail": "wire", + "destination_currency": "usd", + "destination_wire_message": "a wire message", + "supported_currencies": { + "ethereum": [ + "usdc" + ] + }, + "state": "active", + "created_at": "2023-11-22T21:31:30.515Z", + "updated_at": "2023-11-22T21:31:30.515Z" + } + }, + "SuccessfulSepaLiquidationAddressGetResponse": { + "summary": "A successful get response for a SEPA Liquidation Address", + "value": { + "id": "la_123", + "chain": "ethereum", + "customer_id": "cust_123", + "external_account_id": "ext_123", + "address": "0x4d0280da2f2fDA5103914bCc5aad114743152A9c", + "currency": "usdc", + "destination_payment_rail": "sepa", + "destination_currency": "eur", + "destination_sepa_reference": "a SEPA reference", + "supported_currencies": { + "ethereum": [ + "usdc" + ] + }, + "state": "active", + "created_at": "2023-11-22T21:31:30.515Z", + "updated_at": "2023-11-22T21:31:30.515Z" + } + }, + "SuccessfulGetAllLiquidationAddressResponse": { + "summary": "A successful get request for a list of Liquidation Addresses", + "value": { + "count": 1, + "data": { + "type": "array", + "minItems": 0, + "items": { + "id": "la_123", + "chain": "ethereum", + "customer_id": "cust_123", + "external_account_id": "ext_123", + "address": "0x4d0280da2f2fDA5103914bCc5aad114743152A9c", + "currency": "usdc", + "supported_currencies": { + "ethereum": [ + "usdc" + ] + }, + "state": "active", + "created_at": "2023-11-22T21:31:30.515Z", + "updated_at": "2023-11-22T21:31:30.515Z" + } + } + } + }, + "PlaidExchangePublicTokenSuccessResponse": { + "summary": "Successful Plaid public token exchange", + "value": { + "message": "Successfully exchanged public token for access token" + } + }, + "SuccessfulLiquidationAddressDrainsToCryptoResponse": { + "summary": "A successful get request for a Liquidation Address's drain to crypto", + "value": { + "count": 1, + "data": [ + { + "id": "la_123", + "amount": "100.25", + "customer_id": "cust_123", + "liquidation_address_id": "la_456", + "currency": "usdc", + "state": "funds_received", + "created_at": "2020-01-01T00:00:00.000Z", + "updated_at": "2020-01-01T00:00:00.000Z", + "deposit_tx_hash": "0xc13d7905be5c989378a945487cd2a1193627ae606009e28e296d48ddaec66162", + "destination": { + "payment_rail": "ethereum", + "currency": "usdt", + "to_address": "0xb794f5ea0ba39494ce839613fffba74279579268" + }, + "destination_tx_hash": "0xdeadbeef", + "receipt": { + "initial_amount": "100.25", + "developer_fee": "0.2", + "subtotal_amount": "100.05", + "exchange_rate": "1.000000", + "converted_amount": "100.05", + "outgoing_amount": "100.05", + "destination_currency": "usd", + "url": "https://dashboard.bridge.xyz/transaction/00000000-0000-0000-0000-000000000000/receipt/00000000-0000-0000-0000-000000000000" + } + } + ] + } + }, + "SuccessfulLiquidationAddressDrainsToFiatResponse": { + "summary": "A successful get request for a Liquidation Address's drain to fiat", + "value": { + "count": 1, + "data": [ + { + "id": "la_123", + "amount": "100.25", + "customer_id": "cust_123", + "liquidation_address_id": "la_456", + "currency": "usdc", + "state": "funds_received", + "created_at": "2020-01-01T00:00:00.000Z", + "updated_at": "2020-01-01T00:00:00.000Z", + "deposit_tx_hash": "0xc13d7905be5c989378a945487cd2a1193627ae606009e28e296d48ddaec66162", + "destination": { + "payment_rail": "wire", + "currency": "usd", + "external_account_id": "ext_acct_789", + "wire_message": "a wire message", + "imad": "123456" + }, + "receipt": { + "initial_amount": "100.25", + "developer_fee": "0.2", + "subtotal_amount": "100.05", + "exchange_rate": "1.000000", + "converted_amount": "100.05", + "outgoing_amount": "100.05", + "destination_currency": "usd", + "url": "https://dashboard.bridge.xyz/transaction/00000000-0000-0000-0000-000000000000/receipt/00000000-0000-0000-0000-000000000000" + } + } + ] + } + }, + "SuccessfulLiquidationAddressBalanceResponse": { + "summary": "A successful get request for a Liquidation Address's balance", + "value": { + "active_balance": "0", + "pending_balance": "100.25" + } + }, + "SuccessfulDeveloperFeesShowResponse": { + "summary": "A successful get request for configured fees.", + "value": { + "default_liquidation_address_fee_percent": "1.3" + } + }, + "CreateApiKeyRequest": { + "summary": "Create a scoped API key limited to reading and creating customers.", + "value": { + "name": "Customer service key", + "scopes": [ + "customer:read", + "customer:create" + ] + } + }, + "SuccessfulCreateApiKeyResponse": { + "summary": "A successful create request for a scoped API key.", + "value": { + "id": "5f1f5b3a-8c2b-4e5f-9d88-e0b2a7d3a1e8", + "type": "Private", + "owner_type": "Developer", + "owner_id": "e802b3a4-f453-4da8-8a5b-dd50cede1e4f", + "prefix": "sk-live", + "last_4": "9f2c", + "state": "Active", + "created_at": "2026-04-22T15:04:05Z", + "updated_at": "2026-04-22T15:04:05Z", + "name": "Customer service key", + "scopes": [ + "customer:read", + "customer:create" + ], + "value": "sk-live-0123456789abcdef0123456789ab9f2c" + } + }, + "SuccessfulWhoAmIResponse": { + "summary": "A successful whoami request for a scoped API key.", + "value": { + "id": "5f1f5b3a-8c2b-4e5f-9d88-e0b2a7d3a1e8", + "type": "Private", + "owner_type": "Developer", + "owner_id": "e802b3a4-f453-4da8-8a5b-dd50cede1e4f", + "prefix": "sk-live", + "last_4": "9f2c", + "state": "Active", + "created_at": "2026-04-22T15:04:05Z", + "updated_at": "2026-04-22T15:04:05Z", + "name": "Customer service key", + "scopes": [ + "customer:read", + "customer:create" + ] + } + }, + "SuccessfulTotalBalancesResponse": { + "summary": "A successful get request for total balances", + "value": [ + { + "balance": "100.25", + "currency": "usdb", + "chain": "solana", + "contract_address": "ENL66PGy8d8j5KNqLtCcg4uidDUac5ibt45wbjH9REzB" + } + ] + }, + "WireFundsRequestResponse": { + "summary": "A successful wire funds request", + "value": { + "id": "fr_123", + "deposit_id": "dep_123", + "customer_id": "cust_123", + "amount": "120.0", + "currency": "usd", + "payment_rail": "wire", + "fraud": true, + "notice_date": "2020-02-01", + "imad": "123456", + "created_at": "2020-02-01T00:00:00.000Z", + "deposit_created-at": "2020-01-01T00:00:00.000Z" + } + }, + "AchFundsRequestResponse": { + "summary": "A successful ACH funds request", + "value": { + "id": "fr_123", + "deposit_id": "dep_123", + "customer_id": "cust_123", + "amount": "120.0", + "currency": "usd", + "payment_rail": "ach_push", + "fraud": true, + "notice_date": "2020-02-01", + "trace_number": "123456", + "created_at": "2020-02-01T00:00:00.000Z", + "deposit_created-at": "2020-01-01T00:00:00.000Z" + } + }, + "SepaFundsRequestResponse": { + "summary": "A successful SEPA funds request", + "value": { + "id": "fr_123", + "deposit_id": "dep_123", + "customer_id": "cust_123", + "amount": "120.0", + "currency": "eur", + "payment_rail": "sepa", + "fraud": true, + "notice_date": "2020-02-01", + "bank_transaction_id": "123456", + "created_at": "2020-02-01T00:00:00.000Z", + "deposit_created-at": "2020-01-01T00:00:00.000Z" + } + }, + "FundsRequestsResponse": { + "summary": "A list of funds requests across all customers", + "value": { + "count": 3, + "data": [ + { + "id": "fr_123", + "deposit_id": "dep_123", + "customer_id": "cust_123", + "amount": "120.0", + "currency": "usd", + "payment_rail": "wire", + "fraud": true, + "notice_date": "2020-02-01", + "imad": "123456", + "created_at": "2020-02-01T00:00:00.000Z", + "deposit_created-at": "2020-01-01T00:00:00.000Z" + }, + { + "id": "fr_123", + "deposit_id": "dep_123", + "customer_id": "cust_123", + "amount": "120.0", + "currency": "usd", + "payment_rail": "ach_push", + "fraud": true, + "notice_date": "2020-02-01", + "trace_number": "123456", + "created_at": "2020-02-01T00:00:00.000Z", + "deposit_created-at": "2020-01-01T00:00:00.000Z" + }, + { + "id": "fr_123", + "deposit_id": "dep_123", + "customer_id": "cust_123", + "amount": "120.0", + "currency": "eur", + "payment_rail": "sepa", + "fraud": true, + "notice_date": "2020-02-01", + "bank_transaction_id": "123456", + "created_at": "2020-02-01T00:00:00.000Z", + "deposit_created-at": "2020-01-01T00:00:00.000Z" + } + ] + } + }, + "RfiResponse": { + "summary": "An RFI raised against a transfer, with a structured questions template", + "value": { + "id": "rfi_ah4nyoi9pcbrgl3mnu092l6b", + "state": "on_developer", + "developer_id": "dev_2p6ipnn5b7x7xrpn97fljzt6", + "customer_id": "cust_c6ednm25xanjrx1yzz5s4t8n", + "referent_id": "transfer_hmyt7lyjqr0h39s5g87lo0jn", + "referent_type": "transfer", + "context": { + "amount_display": "$1,000.00", + "currency_display": "USD", + "transaction_date": "2026-08-01", + "sender_name": "Jane Doe" + }, + "bridge_action_taken": null, + "expected_action_on_expiry": "pause_customer", + "deadline": "2026-08-15T00:00:00.000Z", + "requested_items": [ + { + "content": "What is the source of funds for this payment? Please provide supporting documentation (bank or investment statement, pay stub, invoice, receipt or contract)." + } + ], + "dashboard_url": "https://dashboard.bridge.xyz/rfis/rfi_ah4nyoi9pcbrgl3mnu092l6b", + "state_changed_at": "2026-08-01T00:00:00.000Z", + "created_at": "2026-08-01T00:00:00.000Z", + "closed_at": null + } + }, + "RfiListResponse": { + "summary": "A list of RFIs", + "value": { + "count": 1, + "data": [ + { + "id": "rfi_ah4nyoi9pcbrgl3mnu092l6b", + "state": "on_developer", + "developer_id": "dev_2p6ipnn5b7x7xrpn97fljzt6", + "customer_id": "cust_c6ednm25xanjrx1yzz5s4t8n", + "referent_id": "transfer_hmyt7lyjqr0h39s5g87lo0jn", + "referent_type": "transfer", + "context": { + "amount_display": "$1,000.00", + "currency_display": "USD", + "transaction_date": "2026-08-01", + "sender_name": "Jane Doe" + }, + "bridge_action_taken": null, + "expected_action_on_expiry": "pause_customer", + "deadline": "2026-08-15T00:00:00.000Z", + "requested_items": [ + { + "content": "What is the source of funds for this payment? Please provide supporting documentation (bank or investment statement, pay stub, invoice, receipt or contract)." + } + ], + "dashboard_url": "https://dashboard.bridge.xyz/rfis/rfi_ah4nyoi9pcbrgl3mnu092l6b", + "state_changed_at": "2026-08-01T00:00:00.000Z", + "created_at": "2026-08-01T00:00:00.000Z", + "closed_at": null + } + ] + } + }, + "SuccessfulWebhookResponse": { + "summary": "A successful webhook endpoint object.", + "value": { + "id": "wep_123", + "url": "https://my_endpoint.xyz/hooks", + "status": "active", + "public_key": "-----BEGIN PUBLIC KEY-----\\nFAKEhFnaPLmxxG4a5w0BAQEFAAOCAQ8AMIIBCgKCAQEAtYhc6PV2LOs/nqDRHi0B\\nMKTsdMLHtg58a1NDxaYfw4IZJ3hpy1qIFUgt5X0HhCYZE0Y40MyLGIejPyitEjYw\\ni9/aE+9F/PN+btqN7OK6cVuF9s/R9cZCtNc27UdTQXrUO5T8GXNAMmRr0KFh8yPv\\nfIgpoZn5ZhnyRbZpDvrxHzLmcZJFAX8Ca+KZLzgGVybEqJtP6fKAT0zrrUS1z44s\\nRDOLiXl543cRAmBnUyrT6cXiNz/PNbm4zRK5Nx7LGxBFrCWQCao4Yi8hrwWsnHxg\\n0Tcy3UyZhAcgL6ydVJfLD5x58Ri4BN32WPBtgSSO6JxZZwCiX0d1BOgq7+eNgmzN\\nJQIDAQAB\\n-----END PUBLIC KEY-----\\n" + } + }, + "SuccessfulWebhookResponse2": { + "summary": "A successful webhook endpoint object.", + "value": { + "id": "wep_456", + "url": "https://my_endpoint.xyz/hooks", + "status": "active", + "public_key": "-----BEGIN PUBLIC KEY-----\\nFAKEc27UdTQxxG4a5w0BAQEFAAOCAQ8AMIIBCgKCAQEAtYhc6PV2LOs/nqDRHi0B\\nMKTsdMLHtg58a1NDxaYfw4IZJ3hpy1qIFUgt5X0HhCYZE0Y40MyLGIejPyitEjYw\\ni9/aE+9F/PN+btqN7OK6cVuF9s/R9cxG4a5w0BAQEXrUO5T8GXNAMmRr0KFh8yPv\\nfIgpoZn5ZhnyRbZpDvrxHzLmcZJFAX8Ca+KZLzgGVybEqJtP6fKAT0zrrUS1z44s\\nRDOLiXl543cRAmBnUyrT6cXiNz/PNbm4zRK5Nx7LGxBFrCWQCao4Yi8hrwWsnHxg\\n0Tcy3UyZhAcgL6ydVJfLD5x58Ri4BN32WPBtgSSO6JxZZwCiX0d1BOgq7+eNgmzN\\nJQIDAQAB\\n-----END PUBLIC KEY-----\\n" + } + }, + "SuccessfulWebhookCreateResponse": { + "summary": "Successful webhook endpoint creation", + "value": { + "id": "wep_123", + "url": "https://my_endpoint.xyz/hooks", + "status": "disabled", + "public_key": "-----BEGIN PUBLIC KEY-----\\nFJJ3hFnaPLmxxG4a5w0BAQEFAAOCAQ8AMIIBCgKCAQEAtYhc6PV2LOs/nqDRHi0B\\nMKTsdMLHtg58a1NDxaYfw4IZJ3hpy1qIFUgt5X0HhCYZE0Y40MyLGIejPyitEjYw\\ni9/aE+9F/PN+btqN7OK6cVuF9s/R9cZCtNc27UdTQXrUO5T8GXNAMmRr0KFh8yPv\\nfIgpoZn5ZhnyRbZpDvrxHzLmcZJFAX8Ca+KZLzgGVybEqJtP6fKAT0zrrUS1z44s\\nRDOLiXl543cRAmBnUyrT6cXiNz/PNbm4zRK5Nx7LGxBFrCWQCao4Yi8hrwWsnHxg\\n0Tcy3UyZhAcgL6ydVJfLD5x58Ri4BN32WPBtgSSO6JxZZwCiX0d1BOgq7+eNgmzN\\nJQIDAQAB\\n-----END PUBLIC KEY-----\\n", + "event_categories": [ + "customer", + "liquidation_address", + "virtual_account", + "virtual_account.activity", + "card_account", + "card_transaction", + "card_withdrawal", + "posted_card_account_transaction" + ] + } + }, + "SuccessfulWebhookUpdateResponse": { + "summary": "Successful webhook endpoint update", + "value": { + "id": "wep_123", + "url": "https://my_updated_endpoint.xyz/hooks", + "status": "active", + "public_key": "-----BEGIN PUBLIC KEY-----\\nFJJ3hFnaPLmxxG4a5w0BAQEFAAOCAQ8AMIIBCgKCAQEAtYhc6PV2LOs/nqDRHi0B\\nMKTsdMLHtg58a1NDxaYfw4IZJ3hpy1qIFUgt5X0HhCYZE0Y40MyLGIejPyitEjYw\\ni9/aE+9F/PN+btqN7OK6cVuF9s/R9cZCtNc27UdTQXrUO5T8GXNAMmRr0KFh8yPv\\nfIgpoZn5ZhnyRbZpDvrxHzLmcZJFAX8Ca+KZLzgGVybEqJtP6fKAT0zrrUS1z44s\\nRDOLiXl543cRAmBnUyrT6cXiNz/PNbm4zRK5Nx7LGxBFrCWQCao4Yi8hrwWsnHxg\\n0Tcy3UyZhAcgL6ydVJfLD5x58Ri4BN32WPBtgSSO6JxZZwCiX0d1BOgq7+eNgmzN\\nJQIDAQAB\\n-----END PUBLIC KEY-----\\n", + "event_categories": [ + "customer", + "liquidation_address", + "virtual_account", + "virtual_account.activity", + "card_account", + "card_transaction", + "card_withdrawal", + "posted_card_account_transaction" + ] + } + }, + "SuccessfulWebhookDeleteResponse": { + "summary": "Successful webhook endpoint delete", + "value": { + "id": "wep_123", + "url": "https://my_deleted_endpoint.xyz/hooks", + "status": "deleted", + "public_key": "-----BEGIN PUBLIC KEY-----\\nFJJ3hFnaPLmxxG4a5w0BAQEFAAOCAQ8AMIIBCgKCAQEAtYhc6PV2LOs/nqDRHi0B\\nMKTsdMLHtg58a1NDxaYfw4IZJ3hpy1qIFUgt5X0HhCYZE0Y40MyLGIejPyitEjYw\\ni9/aE+9F/PN+btqN7OK6cVuF9s/R9cZCtNc27UdTQXrUO5T8GXNAMmRr0KFh8yPv\\nfIgpoZn5ZhnyRbZpDvrxHzLmcZJFAX8Ca+KZLzgGVybEqJtP6fKAT0zrrUS1z44s\\nRDOLiXl543cRAmBnUyrT6cXiNz/PNbm4zRK5Nx7LGxBFrCWQCao4Yi8hrwWsnHxg\\n0Tcy3UyZhAcgL6ydVJfLD5x58Ri4BN32WPBtgSSO6JxZZwCiX0d1BOgq7+eNgmzN\\nJQIDAQAB\\n-----END PUBLIC KEY-----\\n" + } + }, + "SuccessfulWebhookEventsResponse": { + "summary": "A list of events for the webhook endpoint", + "value": { + "data": { + "type": "array", + "minItems": 0, + "items": [ + { + "api_version": "v0", + "event_id": "wh_tmneA3b1rTv1q4gkvmPU53n", + "event_developer_id": "2d127766-02fa-44b0-9fc8-a67665dbf109", + "event_sequence": 1, + "event_category": "transfer", + "event_type": "transfer.deleted", + "event_object_id": "cc598628-29ab-448e-851f-7aaffb1a1171", + "event_object_status": null, + "event_object": { + "id": "cc598628-29ab-448e-851f-7aaffb1a1171", + "state": "awaiting_funds", + "amount": "50.0", + "source": { + "currency": "usdc", + "from_address": "0xd48f4e51c2fcd1c8489eb1a64588b29b76ad0a3f", + "payment_rail": "ethereum" + }, + "receipt": { + "gas_fee": "0.0", + "exchange_fee": "0.0", + "final_amount": "50.0", + "developer_fee": "0.0", + "initial_amount": "50.0", + "subtotal_amount": "50.0", + "url": "https://dashboard.bridge.xyz/transaction/00000000-0000-0000-0000-000000000000/receipt/00000000-0000-0000-0000-000000000000" + }, + "currency": "usd", + "created_at": "2024-05-02T17:48:19.366Z", + "updated_at": "2024-05-02T17:48:19.366Z", + "destination": { + "currency": "usd", + "payment_rail": "ach", + "external_account_id": "24fd61e9-80b6-464a-b5ee-9f7a521cb1f0" + }, + "on_behalf_of": "474c32b3-f3d6-43e3-92ce-a7d4e07fa0a4", + "developer_fee": "0.0", + "source_deposit_instructions": { + "amount": "50.0", + "currency": "usdc", + "to_address": null, + "from_address": "0xd48f4e51c2fcd1c8489eb1a64588b29b76ad0a3f", + "payment_rail": "ethereum" + } + }, + "event_object_changes": { + "state": [ + "pending", + "canceled" + ], + "updated_at": [ + "2024-05-02T15:14:02.842Z", + "2024-05-02T15:15:07.163Z" + ] + }, + "event_created_at": "2024-05-02T17:48:19.465Z" + } + ] + } + } + }, + "SuccessfulWebhookLogsResponse": { + "summary": "A list of delivery logs for the webhook endpoint", + "value": { + "data": { + "type": "array", + "minItems": 0, + "items": [ + { + "status": 200, + "event_id": "wh_event_id_123", + "response_body": "{\"message\":\"OK\"}", + "created_at": "2024-01-01T00:00:00.000Z" + }, + { + "status": 200, + "event_id": "wh_event_id_456", + "response_body": "{\"message\":\"OK\"}", + "created_at": "2024-01-01T00:00:00.000Z" + } + ] + } + } + }, + "WebhookEventSendSuccessResponse": { + "summary": "Successful webhook event send", + "value": { + "message": "Successfully sent the webhook event. This does not guarantee immediate delivery to the endpoint." + } + }, + "OccupationCodesSuccessResponse": { + "summary": "The list of occupations that can be used during the KYC flow.", + "value": [ + { + "display_name": "Accountant and auditor", + "code": "132011" + }, + { + "display_name": "Actor", + "code": "272011" + }, + { + "display_name": "Acupuncturist", + "code": "291291" + }, + { + "display_name": "Administrative services manager", + "code": "113012" + }, + { + "display_name": "Other", + "code": "other" + } + ] + }, + "CustomerRewardSummary": { + "summary": "A summary of a customer's rewards", + "value": { + "developer_id": "2d127766-02fa-44b0-9fc8-a67665dbf109", + "customer_id": "02513e85-b0f9-4d79-8320-348ce9efaa11", + "currency": "xusd", + "balance": "10000.00", + "rewards": "23.9725", + "updated_at": "2025-01-01T00:00:00.000Z" + } + }, + "DeveloperRewardSummary": { + "summary": "A summary of all rewards for a given stablecoin", + "value": { + "developer_id": "2d127766-02fa-44b0-9fc8-a67665dbf109", + "currency": "xusd", + "balance": "10000.00", + "rewards": "23.9725", + "updated_at": "2025-01-01T00:00:00.000Z" + } + }, + "CustomerRewardHistory": { + "summary": "A history of a customer's rewards", + "value": { + "customer_id": "02513e85-b0f9-4d79-8320-348ce9efaa11", + "rewards": [ + { + "balance": "10000.00", + "amount": "0.958904", + "currency": "xusd", + "date": "2025-01-02" + }, + { + "balance": "10100.00", + "amount": "0.968493", + "currency": "xusd", + "date": "2025-01-01" + } + ] + } + }, + "DeveloperRewardHistory": { + "summary": "Daily reward history for a stablecoin", + "value": { + "currency": "usdb", + "developer_id": "2d127766-02fa-44b0-9fc8-a67665dbf109", + "reserves_currency": "usd", + "data": [ + { + "date": "2026-04-20", + "distributed": false, + "total": { + "aum": "45000000.00", + "developer_rewards": "5390.41", + "net_rewards": "4851.37", + "bridge_fee_bps": "10.0000", + "bridge_fee": "539.04", + "annualized_yield_bps": "436.6667" + }, + "providers": [ + { + "provider": "blackrock", + "aum": "30000000.00", + "developer_rewards": "3561.64", + "annualized_yield_bps": "432.5000" + }, + { + "provider": "superstate", + "aum": "15000000.00", + "developer_rewards": "1828.77", + "annualized_yield_bps": "445.0000" + } + ] + } + ], + "pagination": { + "has_more": true, + "next_cursor": "eyJkYXRlIjoiMjAyNi0wNC0yMCJ9" + } + } + } + }, + "schemas": { + "SimulateKycApprovalResponse": { + "type": "object", + "description": "Response from the simulate KYC approval endpoint", + "required": [ + "success", + "customer_id", + "kyc_status", + "message" + ], + "properties": { + "success": { + "type": "boolean", + "description": "Whether the simulation succeeded" + }, + "customer_id": { + "type": "string", + "description": "The ID of the customer whose KYC was simulated" + }, + "kyc_status": { + "$ref": "#/components/schemas/KycStatus" + }, + "message": { + "type": "string", + "description": "Human-readable description of what was processed" + } + } + }, + "BridgeWalletBalance": { + "description": "The balance of a Bridge Wallet for a given currency", + "type": "object", + "required": [ + "balance", + "currency", + "chain" + ], + "properties": { + "balance": { + "type": "string", + "description": "The balance in the given currency. ex. \"10.95\"", + "readOnly": true + }, + "currency": { + "description": "The currency of the balance", + "$ref": "#/components/schemas/Currency", + "readOnly": true + }, + "chain": { + "description": "The chain of the balance", + "$ref": "#/components/schemas/BridgeWalletChain", + "readOnly": true + }, + "contract_address": { + "description": "The contract address of the currency, or null if it is a native currency", + "type": "string", + "readOnly": true + } + } + }, + "BridgeWalletTotalBalance": { + "description": "The total balance across all Bridge wallets for a given currency", + "type": "object", + "required": [ + "balance", + "currency", + "chain" + ], + "properties": { + "balance": { + "type": "string", + "description": "The total balance of wallets in the given currency ex. \"10.95\"", + "readOnly": true + }, + "currency": { + "description": "The currency of the total balance", + "$ref": "#/components/schemas/Currency", + "readOnly": true + }, + "chain": { + "description": "The chain of the total balance", + "$ref": "#/components/schemas/BridgeWalletChain", + "readOnly": true + }, + "contract_address": { + "description": "The contract address of the currency, or null if it is a native currency", + "type": "string", + "readOnly": true + } + } + }, + "BridgeWallet": { + "required": [ + "chain" + ], + "allOf": [ + { + "$ref": "#/components/schemas/CreateBridgeWallet" + }, + { + "properties": { + "id": { + "$ref": "#/components/schemas/Id", + "readOnly": true + }, + "chain": { + "description": "The chain of the Bridge Wallet", + "$ref": "#/components/schemas/BridgeWalletChain", + "readOnly": true + }, + "address": { + "description": "The blockchain address of the Bridge Wallet", + "type": "string", + "readOnly": true + }, + "initiation_required": { + "readOnly": true, + "type": "boolean", + "description": "When present, transfers sourced from this wallet must include an `initiation` object on the create request. Omitted for wallets that do not require initiation data." + }, + "created_at": { + "readOnly": true, + "type": "string", + "description": "Time of creation of the Bridge Wallet", + "format": "date-time" + }, + "updated_at": { + "readOnly": true, + "type": "string", + "description": "Time of most recent update of the Bridge Wallet", + "format": "date-time" + } + } + } + ] + }, + "BridgeWalletWithBalances": { + "required": [ + "chain" + ], + "allOf": [ + { + "$ref": "#/components/schemas/CreateBridgeWallet" + }, + { + "properties": { + "id": { + "$ref": "#/components/schemas/Id", + "readOnly": true + }, + "chain": { + "description": "The chain of the Bridge Wallet", + "$ref": "#/components/schemas/BridgeWalletChain", + "readOnly": true + }, + "address": { + "description": "The blockchain address of the Bridge Wallet", + "type": "string", + "readOnly": true + }, + "initiation_required": { + "readOnly": true, + "type": "boolean", + "description": "When present, transfers sourced from this wallet must include an `initiation` object on the create request. Omitted for wallets that do not require initiation data." + }, + "created_at": { + "readOnly": true, + "type": "string", + "description": "Time of creation of the Bridge Wallet", + "format": "date-time" + }, + "updated_at": { + "readOnly": true, + "type": "string", + "description": "Time of most recent update of the Bridge Wallet", + "format": "date-time" + }, + "balances": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BridgeWalletBalance" + }, + "readOnly": true + } + } + } + ] + }, + "BridgeWalletsList": { + "type": "object", + "required": [ + "count", + "data" + ], + "properties": { + "count": { + "description": "total number of items in data", + "type": "integer" + }, + "data": { + "type": "array", + "minItems": 0, + "items": { + "$ref": "#/components/schemas/BridgeWallet" + } + } + } + }, + "BridgeWalletEventResponse": { + "description": "Shared fields present on every bridge wallet history event.", + "type": "object", + "required": [ + "id", + "bridge_wallet_id", + "amount", + "available_balance", + "currency", + "source", + "destination", + "type", + "created_at" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/Id" + }, + "bridge_wallet_id": { + "$ref": "#/components/schemas/Id" + }, + "amount": { + "description": "Amount of the transaction, represented as a decimal string. Examples include \"100.250000\", \"0.100000\", \"1.234567\" etc.", + "type": "string" + }, + "available_balance": { + "description": "Available balance of the wallet after this event, represented as a decimal string.", + "type": "string" + }, + "currency": { + "$ref": "#/components/schemas/Currency" + }, + "type": { + "description": "The type of wallet event.", + "type": "string", + "enum": [ + "deposit", + "direct_deposit", + "withdrawal", + "return", + "undeliverable", + "card_spend", + "card_refund" + ] + }, + "source": { + "description": "The source of the transfer, which could be an external bank account, a bridge account, or a crypto wallet address.", + "type": "object", + "properties": { + "currency": { + "$ref": "#/components/schemas/Currency" + }, + "payment_rail": { + "type": "string" + }, + "from_address": { + "type": "string", + "nullable": true + } + } + }, + "destination": { + "description": "The destination of the transfer, which could be an external bank account, a bridge account, or a crypto wallet address.", + "type": "object", + "properties": { + "currency": { + "$ref": "#/components/schemas/Currency" + }, + "payment_rail": { + "type": "string" + }, + "tx_hash": { + "type": "string", + "nullable": true + }, + "from_address": { + "type": "string", + "nullable": true + } + } + }, + "payment_route": { + "description": "Details about the Bridge payment route that initiated this event, such as a transfer, liquidation address drain, virtual account deposit, or card spend. Not present on direct deposits.", + "type": "object", + "nullable": true, + "properties": { + "type": { + "description": "The type of payment route.", + "type": "string", + "enum": [ + "transfer", + "liquidation_address", + "virtual_account", + "card_spend" + ] + }, + "customer_id": { + "$ref": "#/components/schemas/Id" + }, + "transfer_id": { + "type": "string", + "nullable": true + }, + "card_crypto_transaction_id": { + "description": "The ID of the card crypto transaction that initiated this event. Present on card_spend and card_refund events when the event is linked to a specific on-chain card transaction.", + "type": "string", + "nullable": true + }, + "issuing_authorization_id": { + "description": "The Stripe Issuing authorization ID associated with this card event.", + "type": "string", + "nullable": true + }, + "issuing_transaction_id": { + "description": "The Stripe Issuing transaction ID associated with this card event.", + "type": "string", + "nullable": true + } + } + }, + "created_at": { + "type": "string", + "format": "date-time" + } + } + }, + "BridgeWalletHistory": { + "type": "object", + "required": [ + "count", + "data" + ], + "properties": { + "count": { + "description": "total number of items in data", + "type": "integer" + }, + "data": { + "type": "array", + "minItems": 0, + "items": { + "$ref": "#/components/schemas/BridgeWalletEventResponse" + } + } + } + }, + "Id": { + "description": "A UUID that uniquely identifies a resource", + "type": "string", + "pattern": "[a-z0-9]*", + "minLength": 1, + "maxLength": 42 + }, + "client_reference_id": { + "description": "A client-provided reference ID that uniquely identifies a resource in the client's system", + "type": "string", + "minLength": 1, + "maxLength": 256 + }, + "DepositId": { + "description": "A UUID that uniquely identifies a deposit", + "type": "string", + "pattern": "[a-z0-9]*", + "minLength": 1, + "maxLength": 42 + }, + "Omad": { + "description": "(Wire only) The OMAD of a wire transfer, if available", + "type": "string", + "pattern": "[a-z0-9]*", + "minLength": 1, + "maxLength": 40, + "deprecated": true + }, + "Imad": { + "description": "(Wire only) The IMAD of a wire transfer, if available", + "type": "string", + "pattern": "[a-z0-9]*", + "minLength": 1, + "maxLength": 40 + }, + "Uetr": { + "description": "Deprecated: use tracking_number instead. The unique end-to-end transaction reference, for tracing purposes.", + "type": "string", + "readOnly": true, + "deprecated": true + }, + "TraceNumber": { + "description": "The trace number of an ACH transfer", + "type": "string", + "pattern": "[0-9]", + "minLength": 15, + "maxLength": 15 + }, + "EndToEndId": { + "description": "The end-to-end ID of the FedNow transaction, assigned by the sending bank, and is not guaranteed to be unique across payments.", + "type": "string" + }, + "TrackingNumber": { + "description": "The primary tracking identifier for this fiat transaction. Format varies by payment rail (e.g., UETR for SEPA/FPS, clave de rastreo for SPEI, end-to-end ID for PIX).", + "type": "string", + "readOnly": true + }, + "Clabe": { + "description": "The 18-digit CLABE (Clave Bancaria Estandarizada) of the sender who initiated this SPEI transaction", + "type": "string", + "pattern": "^[0-9]+$", + "minLength": 18, + "maxLength": 18 + }, + "TransactionId": { + "description": "Deprecated: use tracking_number instead. The unique transaction identifier for this payment.", + "type": "string", + "deprecated": true + }, + "Reference": { + "description": "A payment reference message for newer payment rails (e.g. Pix, Faster Payments, and FedNow).\n", + "oneOf": [ + { + "$ref": "#/components/schemas/FasterPaymentsReference" + }, + { + "$ref": "#/components/schemas/PixReference" + } + ] + }, + "FasterPaymentsReference": { + "title": "Faster Payments", + "type": "string", + "minLength": 1, + "maxLength": 18 + }, + "PixReference": { + "title": "Pix", + "type": "string", + "minLength": 1, + "maxLength": 100 + }, + "WireMessage": { + "description": "A message to be sent with a wire transfer. It can have up to 140 characters. This message will be validated against 4 lines, each with a max length of 35 characters according to the Fedwire standard.", + "type": "string", + "minLength": 1, + "maxLength": 256 + }, + "SepaReference": { + "description": "A reference message to be sent with a SEPA transaction. We recommend you set a unique value to help you and your customers track payments end to end. It must be from 6 to 140 characters. The allowed characters are `a-z`, `A-Z`, `0-9`, spaces, ampersand (`&`), hyphen (`-`), full stop (`.`), and solidus (`/`). If not populated, the default value is \"Payment via Bridge {unique_token}\".", + "type": "string", + "minLength": 6, + "maxLength": 140 + }, + "SwiftReference": { + "description": "A payment reference message or remittance information to be included in a SWIFT transaction. It can have at most 4 lines (separated by \"\\n\"), each line with a max length of 35 chars. The allowed characters are `a-z`, `A-Z`, `0-9`, special characters (`/` `-` `?` `:` `(` `)` `.` `,` `'` `+`), and space", + "type": "string", + "minLength": 1, + "maxLength": 140 + }, + "SpeiReference": { + "description": "A payment reference message or remittance information to be included in a SPEI transaction. The allowed characters are alphanumeric `a-z`, `A-Z`, `0-9`, and space", + "type": "string", + "minLength": 1, + "maxLength": 40 + }, + "ChargeBearer": { + "description": "Which party bears the SWIFT transaction charges.\n- `our`: the sender (ordering customer) pays all charges.\n- `sha`: charges are shared — the sender pays their own bank's charges; intermediary/beneficiary bank charges are deducted from the transferred amount.\n- `ben`: the receiver (beneficiary) pays all charges, deducted from the transferred amount.\n", + "type": "string", + "enum": [ + "our", + "sha", + "ben" + ] + }, + "AchReference": { + "description": "A reference message to be sent with an ACH transaction. It can be at most 10 characters, A-Z, a-z, 0-9, and spaces.", + "type": "string", + "minLength": 1, + "maxLength": 10 + }, + "Customer": { + "properties": { + "id": { + "$ref": "#/components/schemas/Id", + "readOnly": true + }, + "first_name": { + "type": "string", + "minLength": 1, + "maxLength": 1024 + }, + "middle_name": { + "type": "string", + "nullable": true, + "maxLength": 1024 + }, + "last_name": { + "type": "string", + "minLength": 1, + "maxLength": 1024 + }, + "email": { + "type": "string", + "minLength": 1, + "maxLength": 1024 + }, + "status": { + "type": "string", + "$ref": "#/components/schemas/CustomerStatus" + }, + "capabilities": { + "deprecated": true, + "type": "object", + "properties": { + "payin_crypto": { + "type": "string", + "$ref": "#/components/schemas/CustomerCapabilityState" + }, + "payout_crypto": { + "type": "string", + "$ref": "#/components/schemas/CustomerCapabilityState" + }, + "payin_fiat": { + "type": "string", + "$ref": "#/components/schemas/CustomerCapabilityState" + }, + "payout_fiat": { + "type": "string", + "$ref": "#/components/schemas/CustomerCapabilityState" + } + } + }, + "future_requirements_due": { + "deprecated": true, + "readOnly": true, + "description": "This field is deprecated. See endorsements.missing instead.", + "type": "array", + "minItems": 0, + "items": { + "type": "string", + "enum": [ + "id_verification" + ] + } + }, + "requirements_due": { + "deprecated": true, + "readOnly": true, + "description": "KYC requirements still needed to be completed. Please consult our KYC guide on how to resolve each requirement.", + "type": "array", + "minItems": 0, + "items": { + "type": "string", + "enum": [ + "external_account", + "id_verification" + ] + } + }, + "created_at": { + "readOnly": true, + "type": "string", + "description": "Time of creation of the customer", + "format": "date-time" + }, + "updated_at": { + "readOnly": true, + "type": "string", + "description": "Time of last update of the customer", + "format": "date-time" + }, + "rejection_reasons": { + "deprecated": true, + "readOnly": true, + "description": "Reasons why a customer KYC was rejected", + "type": "array", + "minItems": 0, + "items": { + "$ref": "#/components/schemas/RejectionReason" + } + }, + "has_accepted_terms_of_service": { + "readOnly": true, + "description": "Whether the customer has accepted the terms of service.", + "type": "boolean" + }, + "client_reference_id": { + "description": "Caller-provided identifier used to correlate this customer with your internal records. Returned in API and webhook responses.", + "$ref": "#/components/schemas/client_reference_id" + }, + "endorsements": { + "readOnly": true, + "description": "A summary of whether the customer has received approvals to complete onboarding or use certain products/services offered by Bridge.", + "type": "array", + "minItems": 0, + "items": { + "$ref": "#/components/schemas/Endorsement" + } + } + } + }, + "Endorsement": { + "required": [ + "name", + "status" + ], + "properties": { + "name": { + "description": "The endorsement type.", + "$ref": "#/components/schemas/EndorsementType" + }, + "status": { + "type": "string", + "enum": [ + "incomplete", + "approved", + "revoked" + ] + }, + "additional_requirements": { + "description": "This field is deprecated. See endorsements.missing instead.", + "type": "array", + "minItems": 0, + "items": { + "$ref": "#/components/schemas/EndorsementRequirementEnum" + } + }, + "requirements": { + "description": "This object aims to replace the `additional_requirements` attribute as it gives a more comprehensive view into what items are already `complete` or `pending` and which are `missing` or have `issues`.\n", + "type": "object", + "required": [ + "complete", + "pending", + "missing", + "issues" + ], + "properties": { + "complete": { + "type": "array", + "description": "an array of requirements that have already been completed for this endorsement.", + "minItems": 0, + "items": { + "type": "string" + } + }, + "pending": { + "type": "array", + "description": "an array of requirements that are pending review for this endorsement.", + "minItems": 0, + "items": { + "type": "string" + } + }, + "missing": { + "type": "object", + "description": "an object that will specify an indepth breakdown of what items are missing for this endorsement." + }, + "issues": { + "type": "array", + "description": "An array of issues preventing this endorsement from being approved. Values in this array can be either a string such as `endorsement_not_available_in_customers_region` or an object that correlates the issue to a particular field such as `{ id_front_photo: \"id_expired\" }`\n", + "minItems": 0, + "items": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "object" + } + ] + } + } + } + }, + "future_requirements": { + "description": "An array of upcoming requirements that will become active on their effective_date.\nEach entry has the same structure as the current requirements object, plus an\neffective_date indicating when the requirement takes effect.\n", + "type": "array", + "minItems": 0, + "items": { + "type": "object", + "required": [ + "effective_date", + "verification_stage", + "pending", + "missing", + "issues" + ], + "properties": { + "effective_date": { + "type": "string", + "format": "date" + }, + "verification_stage": { + "type": "string", + "description": "The verification stage this future requirement is currently at.", + "enum": [ + "automatic_review", + "manual_review", + "post_review", + "complete", + "not_applicable" + ] + }, + "pending": { + "type": "array", + "items": { + "type": "string" + } + }, + "missing": { + "type": "object", + "nullable": true + }, + "issues": { + "type": "array", + "items": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "object" + } + ] + } + } + } + } + } + } + }, + "EndorsementRequirementEnum": { + "type": "string", + "enum": [ + "kyc_approval", + "tos_acceptance", + "kyc_with_proof_of_address", + "tos_v2_acceptance" + ] + }, + "EndorsementType": { + "description": "The type of endorsement. Note: `pix_onramp` (BRL deposits via PIX) and `pix_offramp` (BRL withdrawals via PIX) can be requested individually for granular access. Requesting `pix` grants both directional endorsements. `pix_onramp` is not supported for non-BR individuals; if requested (or requested via `pix`) it will remain in an `endorsement_not_available_in_customers_region` state and no action is required.\n", + "type": "string", + "enum": [ + "base", + "cards", + "cop", + "faster_payments", + "pix", + "pix_onramp", + "pix_offramp", + "sepa", + "spei" + ] + }, + "Address": { + "required": [ + "street_line_1", + "country", + "city" + ], + "properties": { + "street_line_1": { + "type": "string", + "minLength": 4 + }, + "street_line_2": { + "type": "string", + "minLength": 1 + }, + "city": { + "type": "string", + "minLength": 1 + }, + "state": { + "type": "string", + "description": "ISO 3166-2 subdivision code. Must be supplied for US addresses.", + "minLength": 1, + "maxLength": 3 + }, + "postal_code": { + "type": "string", + "description": "Must be supplied for countries that use postal codes.", + "minLength": 1 + }, + "country": { + "description": "Three-letter alpha-3 country code as defined in the ISO 3166-1 spec.", + "type": "string", + "minLength": 3, + "maxLength": 3 + } + } + }, + "TravelRuleAddress": { + "type": "object", + "description": "Address for travel rule submissions. All fields are optional to support partial address data (e.g. country-only).", + "properties": { + "street_line_1": { + "type": "string" + }, + "street_line_2": { + "type": "string" + }, + "city": { + "type": "string" + }, + "state": { + "type": "string", + "description": "ISO 3166-2 subdivision code." + }, + "postal_code": { + "type": "string" + }, + "country": { + "description": "Three-letter alpha-3 country code as defined in the ISO 3166-1 spec.", + "type": "string", + "minLength": 3, + "maxLength": 3 + } + } + }, + "TravelRuleWalletType": { + "type": "string", + "description": "Indicates the custody model for the wallet. Use `self_custodied` for customer-owned wallets (customer controls private keys), `hosted` for wallets managed by a developer or regulated entity on behalf of the customer, or `external` for wallets belonging to external exchanges or smart contracts.", + "enum": [ + "hosted", + "external", + "self_custodied" + ] + }, + "TravelRuleIsSelf": { + "type": "boolean", + "description": "Set to `true` when this party is the same person or business as the Bridge customer on the resource. When `true`, Bridge uses the customer's name and address on file instead of relying on `name` and `address` in this payload." + }, + "TravelRuleName": { + "type": "string", + "description": "Legal name of the originator or beneficiary. Usually omitted when `is_self` is `true`." + }, + "TravelRuleWalletAttestedOwnershipAt": { + "type": "string", + "format": "date-time", + "description": "Required when `wallet_type` is `self-custodied` or `hosted`. Must be a timestamp in the past indicating when wallet ownership was attested." + }, + "TravelRuleOriginator": { + "type": "object", + "description": "Travel Rule details for originator crypto movement.", + "properties": { + "is_self": { + "$ref": "#/components/schemas/TravelRuleIsSelf" + }, + "name": { + "$ref": "#/components/schemas/TravelRuleName" + }, + "address": { + "description": "Mailing or legal address of the originator. Usually omitted when `is_self` is `true`.", + "allOf": [ + { + "$ref": "#/components/schemas/TravelRuleAddress" + } + ] + }, + "wallet_type": { + "$ref": "#/components/schemas/TravelRuleWalletType" + }, + "wallet_attested_ownership_at": { + "$ref": "#/components/schemas/TravelRuleWalletAttestedOwnershipAt" + }, + "identifying_information": { + "allOf": [ + { + "$ref": "#/components/schemas/IdentifyingInformation" + } + ], + "description": "List of identification objects for the originator. Do **not** include `image_front` or `image_back` fields in this context; those are not accepted in Travel Rule submissions.\n" + }, + "birth_date": { + "type": "string", + "description": "Date of birth in format yyyy-mm-dd.", + "minLength": 10, + "maxLength": 10 + }, + "place_of_birth": { + "$ref": "#/components/schemas/PlaceOfBirthInput" + }, + "legal_entity_identifier": { + "type": "string", + "description": "The Legal Entity Identifier (LEI) or equivalent (e.g. VAT number) of the originator. Provide this when the originator is a legal entity rather than an individual." + } + } + }, + "TravelRuleBeneficiary": { + "type": "object", + "description": "Travel Rule details for beneficiary crypto movement.", + "properties": { + "is_self": { + "$ref": "#/components/schemas/TravelRuleIsSelf" + }, + "name": { + "$ref": "#/components/schemas/TravelRuleName" + }, + "address": { + "description": "Mailing or legal address of the beneficiary. Usually omitted when `is_self` is `true`.", + "allOf": [ + { + "$ref": "#/components/schemas/TravelRuleAddress" + } + ] + }, + "wallet_type": { + "$ref": "#/components/schemas/TravelRuleWalletType" + }, + "wallet_attested_ownership_at": { + "$ref": "#/components/schemas/TravelRuleWalletAttestedOwnershipAt" + }, + "legal_entity_identifier": { + "type": "string", + "description": "The Legal Entity Identifier (LEI) or equivalent (e.g. VAT number) of the beneficiary. Provide this when the beneficiary is a legal entity rather than an individual." + } + } + }, + "TravelRuleData": { + "type": "object", + "description": "Travel Rule data for a crypto movement. Send this on create or update when the same counterparty should apply to every future use of a reusable resource, or send the same payload with `POST /travel_rule_data/{id}` when it belongs to one specific movement.", + "properties": { + "originator": { + "description": "The party sending the crypto.", + "allOf": [ + { + "$ref": "#/components/schemas/TravelRuleOriginator" + } + ] + }, + "beneficiary": { + "description": "The party receiving the crypto.", + "allOf": [ + { + "$ref": "#/components/schemas/TravelRuleBeneficiary" + } + ] + } + }, + "example": { + "originator": { + "name": "Jane Smith", + "address": { + "street_line_1": "123 Market St", + "street_line_2": null, + "city": "San Francisco", + "state": "CA", + "postal_code": "94105", + "country": "USA" + }, + "identifying_information": { + "type": "national_id", + "number": "1234567890", + "issuing_country": "USA" + }, + "birth_date": "2000-01-31", + "place_of_birth": { + "city": "San Francisco", + "country": "USA" + }, + "wallet_type": "self_custodied", + "wallet_attested_ownership_at": "2026-04-01T12:00:00Z" + }, + "beneficiary": { + "is_self": true, + "wallet_type": "external" + } + } + }, + "ExternalAccountAddress": { + "required": [ + "street_line_1", + "country", + "city" + ], + "properties": { + "street_line_1": { + "type": "string", + "minLength": 4, + "maxLength": 35 + }, + "street_line_2": { + "type": "string", + "maxLength": 35 + }, + "city": { + "type": "string", + "minLength": 1 + }, + "state": { + "type": "string", + "description": "ISO 3166-2 subdivision code. Must be supplied for US addresses.", + "minLength": 1 + }, + "postal_code": { + "type": "string", + "description": "Must be supplied for countries that use postal codes.", + "minLength": 1 + }, + "country": { + "description": "Three-letter alpha-3 country code as defined in the ISO 3166-1 spec.", + "type": "string", + "minLength": 3, + "maxLength": 3 + } + } + }, + "Address2025WinterRefresh": { + "required": [ + "street_line_1", + "country", + "city" + ], + "properties": { + "street_line_1": { + "type": "string", + "minLength": 4 + }, + "street_line_2": { + "type": "string", + "minLength": 1 + }, + "city": { + "type": "string", + "minLength": 1 + }, + "subdivision": { + "type": "string", + "description": "ISO 3166-2 subdivision code. Must be supplied for US addresses.", + "minLength": 1, + "maxLength": 3 + }, + "postal_code": { + "type": "string", + "description": "Must be supplied for countries that use postal codes.", + "minLength": 1 + }, + "country": { + "description": "Three-letter alpha-3 country code as defined in the ISO 3166-1 spec.", + "type": "string", + "minLength": 3, + "maxLength": 3 + } + } + }, + "PlaceOfBirthInput": { + "type": "object", + "description": "Country (and optionally city) of birth. **EEA / BBSA in-scope customers:** supply when onboarding individuals or associated persons under the [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#country-of-birth-and-city-of-birth). This is a sparse address — no street address. At least `country` should be present when the object is sent; `city` is recommended and will be required by EU law in 2027.\n", + "properties": { + "country": { + "type": "string", + "minLength": 3, + "maxLength": 3, + "description": "ISO 3166-1 alpha-3 country code for the place of birth." + }, + "city": { + "type": "string", + "minLength": 1, + "description": "City of birth (recommended for EEA)." + } + } + }, + "Country": { + "required": [ + "name", + "alpha3", + "subdivisions" + ], + "properties": { + "name": { + "description": "The name of the country", + "type": "string", + "minLength": 1 + }, + "alpha3": { + "description": "The three-letter alpha-3 country code as defined in the ISO 3166-1 spec, used in Bridge APIs", + "type": "string", + "minLength": 3, + "maxLength": 3 + }, + "postal_code_format": { + "description": "A [Ruby-formatted regular expression](https://ruby-doc.org/3.4.2/Regexp.html) that matches valid postal codes for the country, or null if the country does not use postal codes.", + "type": "string", + "minLength": 1 + }, + "subdivisions": { + "description": "A list of subdivisions for the country", + "type": "array", + "minItems": 0, + "items": { + "$ref": "#/components/schemas/Subdivision" + } + } + } + }, + "Subdivision": { + "required": [ + "name", + "code" + ], + "properties": { + "name": { + "description": "The name of the subdivision", + "type": "string", + "minLength": 1 + }, + "code": { + "description": "The subdivision code, which can be used in place of the name when interacting with Bridge via API", + "type": "string", + "minLength": 2 + } + } + }, + "IbanBankAccount": { + "required": [ + "account_number", + "country", + "last_4" + ], + "properties": { + "account_number": { + "type": "string", + "description": "The International Bank Account Number (IBAN) that will be used to send the funds", + "minLength": 1, + "writeOnly": true + }, + "bic": { + "type": "string", + "description": "The Bank Identifier Code (BIC/SWIFT code) associated with the beneficiary bank.\nWhile not strictly required for IBAN-based payments, providing the BIC may improve\npayment success rates.\n", + "minLength": 8, + "maxLength": 11, + "pattern": "^[A-Za-z]{4}[A-Za-z]{2}[A-Za-z0-9]{2}([A-Za-z0-9]{3})?$" + }, + "country": { + "description": "Country in which the bank account is located. It's a three-letter alpha-3 country code as defined in the ISO 3166-1 spec.", + "type": "string", + "minLength": 3, + "maxLength": 3 + }, + "last_4": { + "description": "Last 4 digits of the bank account number", + "minLength": 1, + "type": "string", + "readOnly": true + } + } + }, + "BreBBankAccount": { + "title": "bre_b", + "required": [ + "bre_b_key", + "last_4" + ], + "properties": { + "bre_b_key": { + "type": "string", + "description": "The Bre-B key of the Colombian bank account", + "writeOnly": true + }, + "last_4": { + "description": "Last 4 digits of the Bre-B key", + "minLength": 4, + "maxLength": 4, + "type": "string", + "readOnly": true + } + } + }, + "ColombianBankCode": { + "type": "string", + "description": "The Colombian bank code identifying the customer's bank.\n\n| Code | Bank |\n|------|------|\n| `1001` | Banco de Bogotá |\n| `1002` | Banco Popular |\n| `1006` | Itaú |\n| `1007` | Bancolombia |\n| `1009` | Citibank |\n| `1012` | Banco GNB Sudameris |\n| `1013` | BBVA Colombia |\n| `1019` | Scotiabank Colpatria |\n| `1023` | Banco de Occidente |\n| `1032` | Banco Caja Social |\n| `1040` | Banco Agrario |\n| `1047` | Banco Mundo Mujer |\n| `1051` | Banco Davivienda |\n| `1052` | Banco AV Villas |\n| `1053` | Banco W |\n| `1059` | Bancamía |\n| `1060` | Banco Pichincha |\n| `1061` | Bancoomeva |\n| `1062` | Banco Falabella |\n| `1063` | Banco Finandina |\n| `1065` | Banco Santander |\n| `1066` | Banco Cooperativo Coopcentral |\n| `1067` | MiBanco |\n| `1069` | Banco Serfinanza |\n| `1070` | Lulo Bank |\n| `1071` | Banco J.P. Morgan Colombia |\n| `1097` | Dale |\n| `1121` | Financiera Juriscoop |\n| `1283` | Cooperativa Financiera de Antioquia |\n| `1286` | JFK Cooperativa Financiera |\n| `1289` | Cootrafa Cooperativa Financiera |\n| `1292` | Confiar Cooperativa Financiera |\n| `1303` | Banco Unión |\n| `1370` | Coltefinanciera |\n| `1507` | Nequi |\n| `1551` | Daviplata |\n| `1558` | Ban100 |\n| `1637` | Iris |\n| `1801` | Movii |\n| `1802` | Ding Tecnipagos |\n| `1803` | Powwi |\n| `1804` | Ualá |\n| `1805` | Banco BTG Pactual |\n| `1808` | Bold CF |\n| `1809` | Nu Colombia |\n| `1811` | Rappipay |\n| `1812` | Coink |\n| `1814` | Global66 |\n| `1815` | Alianza Fiduciaria |\n| `1816` | Crezcamos |\n", + "enum": [ + "1001", + "1002", + "1006", + "1007", + "1009", + "1012", + "1013", + "1019", + "1023", + "1032", + "1040", + "1047", + "1051", + "1052", + "1053", + "1059", + "1060", + "1061", + "1062", + "1063", + "1065", + "1066", + "1067", + "1069", + "1070", + "1071", + "1097", + "1121", + "1283", + "1286", + "1289", + "1292", + "1303", + "1370", + "1507", + "1551", + "1558", + "1637", + "1801", + "1802", + "1803", + "1804", + "1805", + "1808", + "1809", + "1811", + "1812", + "1814", + "1815", + "1816" + ] + }, + "CoBankTransferBankAccount": { + "title": "co_bank_transfer", + "description": "Colombian CO bank transfer account for COP transfers", + "required": [ + "account_number", + "bank_code", + "account_type", + "document_type", + "document_number", + "phone_number" + ], + "properties": { + "account_number": { + "type": "string", + "description": "The CO bank account number", + "writeOnly": true + }, + "bank_code": { + "$ref": "#/components/schemas/ColombianBankCode" + }, + "account_type": { + "type": "string", + "description": "The type of bank account", + "enum": [ + "checking", + "savings", + "electronic_deposit" + ] + }, + "document_type": { + "$ref": "#/components/schemas/CoBankTransferDocumentType" + }, + "document_number": { + "type": "string", + "description": "The document number of the account holder" + }, + "phone_number": { + "type": "string", + "description": "Phone number of the account holder in E.164 format (e.g. +573001234567)" + }, + "last_4": { + "description": "Last 4 digits of the account number", + "minLength": 4, + "maxLength": 4, + "type": "string", + "readOnly": true + }, + "routing_number": { + "description": "The bank code of the account", + "type": "string", + "readOnly": true + } + } + }, + "ClabeBankAccount": { + "required": [ + "account_number", + "last_4" + ], + "properties": { + "account_number": { + "type": "string", + "description": "The CLABE account number of the bank account", + "minLength": 18, + "maxLength": 18, + "writeOnly": true + }, + "last_4": { + "description": "Last 4 digits of the CLABE", + "minLength": 4, + "maxLength": 4, + "type": "string", + "readOnly": true + } + } + }, + "PixKeyBankAccount": { + "title": "pix_key", + "required": [ + "pix_key", + "account_preview" + ], + "properties": { + "pix_key": { + "type": "string", + "description": "The Pix key for the Brazilian bank account. Must be one of the following formats:\n- **EVP (Virtual Payment Address)**: Random UUID generated by Banco Central do Brasil (e.g., `550e8400-e29b-41d4-a716-446655440000`)\n- **CPF (Tax ID)**: 11-digit individual tax number (e.g., `12345678901`)\n- **CNPJ (Business Tax ID)**: 14-digit business tax number (e.g., `12345678000195`)\n- **Phone**: Brazilian mobile phone in format +55 followed by 11 digits (e.g., `+5511987654321`)\n- **Email**: Valid email address (e.g., `joao.silva@email.com`)\n", + "minLength": 1, + "writeOnly": true + }, + "document_number": { + "type": "string", + "description": "Optional document number (CPF/CNPJ) associated with the Pix key. Must be all numerals (no punctuation) if provided.", + "writeOnly": true + }, + "account_preview": { + "description": "Masked preview of the Pix key", + "type": "string", + "readOnly": true + }, + "document_number_last4": { + "description": "Last 4 digits of the document number (CPF/CNPJ) when available", + "type": "string", + "readOnly": true + } + } + }, + "BrCodeBankAccount": { + "title": "br_code", + "required": [ + "br_code", + "account_preview" + ], + "properties": { + "br_code": { + "type": "string", + "description": "The Copie e cola code for Pix transactions", + "minLength": 1, + "writeOnly": true + }, + "document_number": { + "type": "string", + "description": "Optional document number (CPF/CNPJ) associated with the Pix key. Must be all numerals (no punctuation) if provided.", + "writeOnly": true + }, + "account_preview": { + "description": "Masked preview of the BR Code", + "type": "string", + "readOnly": true + }, + "document_number_last4": { + "description": "Last 4 digits of the document number (CPF/CNPJ) when available", + "type": "string", + "readOnly": true + } + } + }, + "GbBankAccount": { + "title": "gb", + "type": "object", + "required": [ + "account_number", + "last_4", + "sort_code" + ], + "properties": { + "account_number": { + "type": "string", + "description": "The bank account number", + "minLength": 8, + "maxLength": 8, + "example": 12345678, + "writeOnly": true + }, + "last_4": { + "description": "Last 4 digits of the bank account number", + "minLength": 1, + "type": "string", + "readOnly": true + }, + "sort_code": { + "type": "string", + "description": "The sort code, without hyphens", + "minLength": 6, + "maxLength": 6, + "example": 123456 + } + } + }, + "GbBankAccountVirtualAccount": { + "title": "gb", + "type": "object", + "required": [ + "account_number", + "sort_code" + ], + "properties": { + "account_number": { + "type": "string", + "description": "The bank account number", + "minLength": 8, + "maxLength": 8, + "example": 12345678 + }, + "sort_code": { + "type": "string", + "description": "The sort code, without hyphens", + "minLength": 6, + "maxLength": 6, + "example": 123456 + } + } + }, + "UsBankAccount": { + "title": "us", + "required": [ + "account_number", + "routing_number", + "last_4" + ], + "properties": { + "account_number": { + "type": "string", + "description": "The bank account number", + "minLength": 1, + "writeOnly": true + }, + "routing_number": { + "type": "string", + "description": "The bank routing number", + "minLength": 9, + "maxLength": 9 + }, + "last_4": { + "description": "Last 4 digits of the bank account number", + "minLength": 1, + "type": "string", + "readOnly": true + }, + "checking_or_savings": { + "$ref": "#/components/schemas/CheckingOrSavingsType" + } + } + }, + "UsBankAccountUpdate": { + "properties": { + "checking_or_savings": { + "$ref": "#/components/schemas/CheckingOrSavingsType" + }, + "routing_number": { + "type": "string", + "description": "The bank routing number", + "minLength": 9, + "maxLength": 9 + } + } + }, + "CreateIndividualCustomerPayload": { + "allOf": [ + { + "$ref": "#/components/schemas/UpdateIndividualCustomerPayload" + }, + { + "title": "Individual Customer" + }, + { + "required": [ + "type" + ] + } + ] + }, + "UpdateIndividualCustomerPayload": { + "title": "Individual Customer", + "properties": { + "type": { + "description": "Type of the customer (individual vs. business).", + "type": "string", + "minLength": 1, + "enum": [ + "individual" + ] + }, + "first_name": { + "type": "string", + "minLength": 2, + "maxLength": 1024, + "description": "The first name of the individual." + }, + "middle_name": { + "type": "string", + "minLength": 1, + "maxLength": 1024, + "description": "The middle name of the individual." + }, + "last_name": { + "type": "string", + "minLength": 2, + "maxLength": 1024, + "description": "The last name of the individual." + }, + "transliterated_first_name": { + "type": "string", + "description": "Required when the `first_name` includes any non Latin-1 characters. Acceptable characters - Latin-1 Unicode Character Range: À-ÖØ-ßà-öø-ÿ; Standard Unicode Character Range: -~", + "minLength": 1, + "maxLength": 256 + }, + "transliterated_middle_name": { + "type": "string", + "description": "Required when the `middle_name` includes any non Latin-1 characters. Acceptable characters - Latin-1 Unicode Character Range: À-ÖØ-ßà-öø-ÿ; Standard Unicode Character Range: -~", + "minLength": 1, + "maxLength": 256 + }, + "transliterated_last_name": { + "type": "string", + "description": "Required when the `last_name` includes any non Latin-1 characters. Acceptable characters - Latin-1 Unicode Character Range: À-ÖØ-ßà-öø-ÿ; Standard Unicode Character Range: -~", + "minLength": 1, + "maxLength": 256 + }, + "email": { + "type": "string", + "minLength": 1, + "maxLength": 1024, + "description": "The individuals primary email address" + }, + "phone": { + "type": "string", + "minLength": 1, + "maxLength": 1024, + "description": "The individuals primary phone number in format \"+12223334444\"" + }, + "residential_address": { + "writeOnly": true, + "$ref": "#/components/schemas/Address2025WinterRefresh", + "description": "The residential address of the individual. This must be a physical address, not a PO Box." + }, + "transliterated_residential_address": { + "writeOnly": true, + "$ref": "#/components/schemas/Address2025WinterRefresh", + "description": "Required when any part of the `residential_address` includes any non Latin-1 characters. Acceptable characters - Latin-1 Unicode Character Range: À-ÖØ-ßà-öø-ÿ; Standard Unicode Character Range: -~" + }, + "birth_date": { + "type": "string", + "description": "Date of birth in format yyyy-mm-dd. Must be at least 18 years old.", + "minLength": 10, + "maxLength": 10 + }, + "signed_agreement_id": { + "writeOnly": true, + "type": "string", + "description": "The ID of the signed agreement that the customer completed. You can get a signed agreement id for a _new_ customer by following this guide [here](https://apidocs.bridge.xyz/docs/terms-of-service#tos-acceptance-for-a-new-customer).\n", + "minLength": 1, + "maxLength": 1024 + }, + "endorsements": { + "writeOnly": true, + "type": "array", + "description": "List of endorsements to request for this customer. If omitted, we'll attempt to grant `base` and `sepa`.\n", + "items": { + "$ref": "#/components/schemas/EndorsementType" + } + }, + "account_purpose": { + "type": "string", + "description": "What is the primary purpose of the customer's account?\n\n_Required for high risk customers. More information found [here](https://apidocs.bridge.xyz/docs/individuals)._\n\n**EEA / BBSA in-scope individuals:** also required under program rules (not for associated persons). See [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#account-purpose-and-employment-status).\n", + "enum": [ + "charitable_donations", + "ecommerce_retail_payments", + "investment_purposes", + "operating_a_company", + "other", + "payments_to_friends_or_family_abroad", + "personal_or_living_expenses", + "protect_wealth", + "purchase_goods_and_services", + "receive_payment_for_freelancing", + "receive_salary" + ] + }, + "account_purpose_other": { + "type": "string", + "description": "A supplemental description of the `account_purpose`.\n\n_Required if the `account_purpose` is `other`._\n" + }, + "employment_status": { + "type": "string", + "description": "What is the customer's current employment status?\n\n_Required for high risk customers. More information found [here](https://apidocs.bridge.xyz/docs/individuals)._\n\n**EEA / BBSA in-scope individuals:** also required under program rules (not for associated persons). See [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#account-purpose-and-employment-status).\n", + "enum": [ + "employed", + "homemaker", + "retired", + "self_employed", + "student", + "unemployed" + ] + }, + "expected_monthly_payments_usd": { + "type": "string", + "description": "What is the expected monthly volume of payments the customer will be sending or receiving?\n\n_Required for high risk customers. More information found [here](https://apidocs.bridge.xyz/docs/individuals)_\n", + "enum": [ + "0_4999", + "5000_9999", + "10000_49999", + "50000_plus" + ] + }, + "acting_as_intermediary": { + "type": "boolean", + "description": "Is the customer acting as an intermediary for a third party?\n\n_Required for high risk customers. More information found [here](https://apidocs.bridge.xyz/docs/individuals)_\n" + }, + "most_recent_occupation": { + "type": "string", + "description": "What is the customer's most recent occupation? Specify the relevant alphanumeric occupation code. See the [list of occupations](https://apidocs.bridge.xyz/page/sof-eu-most-recent-occupation-list) for the complete list of valid occupations and codes. _Required for Restricted countries._\n\n_Required for high risk customers. More information found [here](https://apidocs.bridge.xyz/docs/individuals)_\n" + }, + "source_of_funds": { + "type": "string", + "description": "The individuals source of funds, e.g. government_benefits, investments_loans, salary, etc.\n\n_Required for high risk customers. More information found [here](https://apidocs.bridge.xyz/docs/individuals)_\n", + "enum": [ + "company_funds", + "ecommerce_reseller", + "gambling_proceeds", + "gifts", + "government_benefits", + "inheritance", + "investments_loans", + "pension_retirement", + "salary", + "sale_of_assets_real_estate", + "savings", + "someone_elses_funds" + ] + }, + "nationality": { + "type": "string", + "description": "Legacy single nationality as ISO 3166-1 alpha-3. Prefer `nationalities` to send **all** nationalities. During migration Bridge honors either field; `nationality` will be deprecated after migration. **EEA / BBSA program:** see [Nationalities](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#nationalities).\n", + "writeOnly": true + }, + "nationalities": { + "type": "array", + "writeOnly": true, + "description": "All nationalities held by the customer (ISO 3166-1 alpha-3 codes). **EEA / BBSA in-scope individuals:** required. See [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#nationalities).\n", + "items": { + "type": "string", + "minLength": 3, + "maxLength": 3 + } + }, + "place_of_birth": { + "writeOnly": true, + "$ref": "#/components/schemas/PlaceOfBirthInput" + }, + "verified_database_at": { + "type": "string", + "format": "date-time", + "description": "Write-only ISO 8601 timestamp. For **EEA in-scope** customers on **reliance** (`TWO_FORMS_OF_ID_RELIANCE` in `eea_requirements.rb`), may stand in for a database identity check together with `verified_govid_at`. See [EEA updated requirements — identity](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements).\n", + "writeOnly": true + }, + "verified_govid_at": { + "type": "string", + "format": "date-time", + "description": "Write-only ISO 8601 timestamp. For **EEA in-scope** customers on **reliance**, use with a second factor (`verified_selfie_at` or `verified_database_at`) per `TWO_FORMS_OF_ID_RELIANCE`. See [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements).\n", + "writeOnly": true + }, + "verified_selfie_at": { + "type": "string", + "format": "date-time", + "description": "Write-only ISO 8601 timestamp. For **EEA in-scope** customers on **reliance**, pairs with `verified_govid_at` or `verified_database_at` under `TWO_FORMS_OF_ID_RELIANCE`.\n", + "writeOnly": true + }, + "liveness_check_selfies": { + "type": "array", + "writeOnly": true, + "description": "Selfie images to submit for Bridge's liveness verification. Use this when you are collecting the customer's selfie on behalf of Bridge.\n\n**EEA in-scope** customers: selfies submitted via this field are not sufficient. The selfie must be collected through the Persona hosted flow (via a KYC link). See [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements).\n", + "items": { + "type": "object", + "required": [ + "image" + ], + "properties": { + "image": { + "type": "string", + "description": "Base64 encoded image* of the selfie, following the data-uri scheme i.e. data:image/[type];base64,[base_64_encoded_file_contents], with a minimum size of 200px x 200px \n\n*Maximum File Size: 15MB\n\n*Valid file types: .jpeg, .jpg, .png, .heic, .heif, .tif, .tiff" + } + } + } + }, + "identifying_information": { + "$ref": "#/components/schemas/IdentifyingInformation" + }, + "documents": { + "$ref": "#/components/schemas/IndividualDocuments" + }, + "client_reference_id": { + "description": "Caller-provided identifier used to correlate this customer with your internal records. Returned in API and webhook responses.", + "$ref": "#/components/schemas/client_reference_id" + } + } + }, + "IdentifyingInformation": { + "writeOnly": true, + "type": "array", + "title": "Identification Information", + "items": { + "type": "object", + "required": [ + "issuing_country", + "type" + ], + "properties": { + "type": { + "type": "string", + "description": "Tax identification number type or government-issued ID document type (see enum). Country-specific tax and national ID lists: [Individuals](https://apidocs.bridge.xyz/docs/individual-tax-identification-numbers-by-country), [Businesses](https://apidocs.bridge.xyz/docs/business-tax-identification-numbers-by-country).\n\n**EEA / BBSA (policy in `eea_requirements.rb`):** In-scope individuals and UBOs need **both** a valid national-ID-type entry and a valid TIN per [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements). In-scope businesses need business registration **and** business tax ID types per country tables there. **TIN issuing country** must match residence (individuals) or incorporation (businesses). **Foreign tax** outside the incorporation country: set `has_foreign_tax_registration` on the business customer and add TIN objects per jurisdiction ([foreign tax / tax residency](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#tax-residency-status-foreign-tax-registry)).\n", + "enum": [ + "drivers_license", + "matriculate_id", + "military_id", + "national_id", + "passport", + "permanent_residency_id", + "state_or_provincial_id", + "visa", + "abn", + "acn", + "ahv", + "ak", + "aom", + "arbn", + "avs", + "bc", + "bce", + "bin", + "bir", + "bp", + "brn", + "bsn", + "bvn", + "cc", + "cdi", + "cedula_juridica", + "cf", + "cif", + "cin", + "cipc", + "cn", + "cnp", + "cnpj", + "cpf", + "cpr", + "crc", + "crib", + "crn", + "cro", + "cui", + "cuil", + "curp", + "cuit", + "cvr", + "edrpou", + "ein", + "embg", + "emirates_id", + "en", + "fin", + "fn", + "gstin", + "gui", + "hetu", + "hkid", + "hn", + "ic", + "ico", + "id", + "id_broj", + "idno", + "idnp", + "idnr", + "if", + "iin", + "ik", + "inn", + "ird", + "itin", + "itr", + "iva", + "jmbg", + "kbo", + "kvk", + "matricule", + "mf", + "mn", + "ms", + "mst", + "nic", + "nicn", + "nie", + "nif", + "nin", + "nino", + "nip", + "nipc", + "nipt", + "nit", + "npwp", + "nric", + "nrn", + "nrt", + "ntn", + "nuit", + "nzbn", + "oib", + "orgnr", + "other", + "pan", + "partita_iva", + "pesel", + "pib", + "pin", + "pk", + "ppsn", + "qid", + "rc", + "regon", + "rfc", + "ricn", + "rif", + "rn", + "rnc", + "rnokpp", + "rp", + "rrn", + "rtn", + "ruc", + "rut", + "si", + "sin", + "siren", + "siret", + "spi", + "ssm", + "ssn", + "steuer_id", + "strn", + "tckn", + "tfn", + "tin", + "tpin", + "trn", + "ucn", + "uen", + "uic", + "uid", + "usc", + "ust_idnr", + "utr", + "vat", + "vkn", + "voen", + "y_tunnus" + ] + }, + "issuing_country": { + "type": "string", + "description": "The ISO 3166-1 (three-character) country code that issued the provided document." + }, + "number": { + "type": "string", + "description": "The unique identifier of the document. Required if this document is being used as a tax identification number (e.g., you are providing a passport or national_id with no other identification)." + }, + "description": { + "type": "string", + "description": "A description describing the provided document. This field is required when `other` is selected." + }, + "expiration": { + "type": "string", + "description": "The expiration date of the given document in yyyy-mm-dd format." + }, + "image_front": { + "type": "string", + "description": "This field is optionally accepted for tax_id types, but required for government_id types. Base64 encoded image* of the front side of the provided document, following the data-uri scheme i.e. data:image/[type];base64,[base_64_encoded_file_contents], with a minimum size of 200px x 200px \\n\\n*Maximum File Size: 15MB\\n\\n*Valid file types: .pdf, .jpeg, .jpg, .png, .heic, .tif\n\n_Note: When combined with an `image_back`, the combined size of both images must not exceed 24MB._\n" + }, + "image_back": { + "type": "string", + "description": "Base64 encoded image* of the back side of the provided document, following the data-uri scheme i.e. data:image/[type];base64,[base_64_encoded_file_contents], with a minimum size of 200px x 200px \\n\\n*Maximum File Size: 15MB\\n\\n*Valid file types: .pdf, .jpeg, .jpg, .png, .heic, .tif\n\n_Note: When combined with an `image_front`, the combined size of both images must not exceed 24MB._\n" + } + } + } + }, + "IndividualDocuments": { + "writeOnly": true, + "type": "array", + "title": "Documents", + "description": "Please click \"ADD OBJECT\" for more information.", + "items": { + "type": "object", + "required": [ + "purposes", + "file" + ], + "properties": { + "purposes": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "proof_of_account_purpose", + "proof_of_address", + "proof_of_individual_name_change", + "proof_of_relationship", + "proof_of_source_of_funds", + "proof_of_source_of_wealth", + "proof_of_tax_identification", + "other" + ] + }, + "description": "A list of purposes that the given document serves. Click \"ADD STRING\" to see common document purposes for individuals, or view the full list of possible values [here](https://apidocs.bridge.xyz/docs/supported-documents)." + }, + "file": { + "type": "string", + "description": "Base64 encoded image* of the provided document, following the data-uri scheme i.e. data:image/[type];base64,[base_64_encoded_file_contents], with a minimum size of 200px x 200px \n\n*Maximum File Size: 24MB\n\n*Valid file types: .pdf, .jpeg, .jpg, .png, .heic, .tif" + }, + "description": { + "type": "string", + "description": "A description describing the provided document. This field is required when `other` is provided as one of the purposes." + } + } + } + }, + "BusinessDocuments": { + "writeOnly": true, + "type": "array", + "title": "Documents", + "description": "Please click \"ADD OBJECT\" for more information.", + "items": { + "type": "object", + "required": [ + "purposes", + "file" + ], + "properties": { + "purposes": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "aml_comfort_letter", + "business_formation", + "directors_registry", + "e_signature_certificate", + "evidence_of_good_standing", + "flow_of_funds", + "marketing_materials", + "ownership_chart", + "ownership_information", + "proof_of_account_purpose", + "proof_of_address", + "proof_of_entity_name_change", + "proof_of_nature_of_business", + "proof_of_signatory_authority", + "proof_of_source_of_funds", + "proof_of_source_of_wealth", + "proof_of_tax_identification", + "shareholder_register", + "other" + ] + }, + "description": "**EEA / BBSA (business KYB):** purposes used in [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements) include `business_formation`, `evidence_of_good_standing`, `ownership_information`, and `proof_of_signatory_authority` (letter of authorization). See supported-documents for the full enum [here](https://apidocs.bridge.xyz/docs/supported-documents).\n\nFor **non-reliance** EEA in-scope businesses, `business_formation`, `evidence_of_good_standing`, and `ownership_information` are evaluated **independently** in CPU policy: each may be satisfied by an uploaded/Persona-backed document **or**, when Stripe business-registry verification passes with the required checks and provider metadata, by that verification alone for that document slot (see `BUSINESS_REGISTRY_CHECK` and `BUSINESS_OWNERSHIP` in `eea_requirements.rb`).\n" + }, + "file": { + "type": "string", + "description": "Base64 encoded image of the provided document, following the data-uri scheme i.e. data:image/[type];base64,[base_64_encoded_file_contents], with a minimum size of 200px x 200px \n\n*Maximum File Size: 24MB\n\n*Valid file types: .pdf, .jpeg, .jpg, .png, .heic, .tif" + }, + "description": { + "type": "string", + "description": "A description describing the provided document. This field is required when `other` is provided as one of the purposes." + } + } + } + }, + "CreateBusinessCustomerPayload": { + "allOf": [ + { + "$ref": "#/components/schemas/UpdateBusinessCustomerPayload" + }, + { + "title": "Business Customer" + } + ] + }, + "UpdateBusinessCustomerPayload": { + "title": "Business Customer", + "properties": { + "type": { + "description": "Type of the customer (individual vs. business)", + "type": "string", + "minLength": 1, + "enum": [ + "business" + ] + }, + "business_legal_name": { + "type": "string", + "minLength": 1, + "maxLength": 1024, + "description": "The official registered name of the business as documented with government authorities." + }, + "transliterated_business_legal_name": { + "type": "string", + "description": "Required if `business_legal_name` includes any non Latin-1 characters. Acceptable characters - Latin-1 Unicode Character Range: À-ÖØ-ßà-öø-ÿ; Standard Unicode Character Range: -~", + "minLength": 1, + "maxLength": 1024 + }, + "business_trade_name": { + "type": "string", + "minLength": 1, + "maxLength": 1024, + "description": "The trading name or DBA (Doing Business As) name under which the business operates publicly." + }, + "transliterated_business_trade_name": { + "type": "string", + "description": "Required if `business_trade` includes any non Latin-1 characters. Acceptable characters - Latin-1 Unicode Character Range: À-ÖØ-ßà-öø-ÿ; Standard Unicode Character Range: -~", + "minLength": 1, + "maxLength": 1024 + }, + "business_description": { + "type": "string", + "minLength": 1, + "maxLength": 1024, + "description": "A brief summary of the business" + }, + "has_foreign_tax_registration": { + "type": "boolean", + "description": "Whether the business is registered for tax in any jurisdiction **outside** its country of incorporation. When `true`, provide additional tax identifiers in `identifying_information` whose `issuing_country` reflects each foreign registration, per [EEA tax residency](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#tax-residency-status-foreign-tax-registry).\n" + }, + "email": { + "type": "string", + "minLength": 1, + "maxLength": 1024, + "description": "The business's primary email address" + }, + "phone": { + "type": "string", + "minLength": 1, + "maxLength": 1024, + "description": "The business's primary phone number in format \"+12223334444\"" + }, + "business_type": { + "description": "How the business is legally registered", + "type": "string", + "minLength": 1, + "enum": [ + "cooperative", + "corporation", + "llc", + "other", + "partnership", + "sole_prop", + "trust" + ] + }, + "primary_website": { + "type": "string", + "minLength": 1, + "maxLength": 1024, + "description": "The business's primary website/web presence. A document with purpose 'proof_of_nature_of_business' is required if this is not provided" + }, + "other_websites": { + "type": "array", + "items": { + "type": "string" + }, + "minLength": 1, + "maxLength": 1024, + "description": "The business's other websites and social media handles" + }, + "registered_address": { + "writeOnly": true, + "$ref": "#/components/schemas/Address2025WinterRefresh", + "description": "The official registered address of the business." + }, + "transliterated_registered_address": { + "writeOnly": true, + "$ref": "#/components/schemas/Address2025WinterRefresh", + "description": "Required if any part of the `registered_address` includes any non Latin-1 characters. Acceptable characters - Latin-1 Unicode Character Range: À-ÖØ-ßà-öø-ÿ; Standard Unicode Character Range: -~" + }, + "physical_address": { + "writeOnly": true, + "$ref": "#/components/schemas/Address2025WinterRefresh", + "description": "The physical address for the primary place of business. This must be a physical address and cannot be a PO Box." + }, + "transliterated_physical_address": { + "writeOnly": true, + "$ref": "#/components/schemas/Address2025WinterRefresh", + "description": "Required if any part of the `physical_address` includes any non Latin-1 characters. Acceptable characters - Latin-1 Unicode Character Range: À-ÖØ-ßà-öø-ÿ; Standard Unicode Character Range: -~" + }, + "signed_agreement_id": { + "writeOnly": true, + "type": "string", + "description": "The ID of the signed agreement that the customer completed. You can get a signed agreement id for a _new_ customer by following [this guide](https://apidocs.bridge.xyz/docs/terms-of-service#tos-acceptance-for-a-new-customer).\n", + "minLength": 1, + "maxLength": 1024 + }, + "is_dao": { + "type": "boolean", + "description": "Whether the business is a DAO (Decentralized Autonomous Organization)" + }, + "compliance_screening_explanation": { + "type": "string", + "description": "Required if `conducts_money_services` is true. A detailed description of the business's compliance and anti-money laundering controls and practices.", + "minLength": 1, + "maxLength": 1024 + }, + "associated_persons": { + "type": "array", + "description": "List of notable people associated with the business such as UBOs.", + "items": { + "$ref": "#/components/schemas/AssociatedPerson" + } + }, + "endorsements": { + "writeOnly": true, + "type": "array", + "description": "List of endorsements to request for this customer. If omitted, we'll attempt to grant `base` and `sepa`.\n", + "items": { + "$ref": "#/components/schemas/EndorsementType" + } + }, + "business_industry": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The industry in which this business operates. Click [here](https://apidocs.bridge.xyz/page/business-industry-list-updated-2022-naics-codes) for the complete list of valid industries and codes." + }, + "publicly_traded_listings": { + "writeOnly": true, + "type": "array", + "description": "A list of public exchanges that the company is traded on if applicable.", + "items": { + "type": "object", + "required": [ + "market_identifier_code", + "stock_number", + "ticker" + ], + "properties": { + "market_identifier_code": { + "type": "string", + "description": "The 4-digit Market Identifier Code (MIC) (ISO 10383) for the venue where the business is publicly listed and traded." + }, + "stock_number": { + "type": "string", + "description": "The 12-digit International Securities Identification Number (ISIN) of the company without dashes (-)." + }, + "ticker": { + "type": "string", + "description": "The ticker for the business's publicly traded listing." + } + } + } + }, + "ownership_threshold": { + "type": "integer", + "description": "The applicable beneficial ownership threshold for the submitted `associated_persons` information. Valid values are between 5 to 25. Default value is 25." + }, + "has_material_intermediary_ownership": { + "type": "boolean", + "description": "The business has at least one intermediate legal entity owner with 25% or more ownership" + }, + "estimated_annual_revenue_usd": { + "type": "string", + "description": "Estimated annual revenue in USD\n\n_Required for high risk customers. More information found [here](https://apidocs.bridge.xyz/docs/business-accounts)_\n", + "enum": [ + "0_99999", + "100000_999999", + "1000000_9999999", + "10000000_49999999", + "50000000_249999999", + "250000000_plus" + ] + }, + "expected_monthly_payments_usd": { + "type": "integer", + "description": "Expected monthly payments in USD\n\n_Required for high risk customers. More information found [here](https://apidocs.bridge.xyz/docs/business-accounts)_\n" + }, + "expected_monthly_swift_transaction_volume": { + "type": "integer", + "deprecated": true, + "description": "Expected monthly SWIFT transaction volume in USD.\n\n_Deprecated: no longer required for the SWIFT endorsement._\n" + }, + "operates_in_prohibited_countries": { + "type": "boolean", + "description": "Does the business operate in any prohibited countries?\n\n_Required for high risk customers. More information found [here](https://apidocs.bridge.xyz/docs/business-accounts)_\n" + }, + "account_purpose": { + "type": "string", + "description": "What is the primary purpose of the business account?", + "enum": [ + "charitable_donations", + "ecommerce_retail_payments", + "investment_purposes", + "other", + "payments_to_friends_or_family_abroad", + "payroll", + "personal_or_living_expenses", + "protect_wealth", + "purchase_goods_and_services", + "receive_payments_for_goods_and_services", + "tax_optimization", + "third_party_money_transmission", + "treasury_management" + ] + }, + "account_purpose_other": { + "type": "string", + "description": "Required if the primary purpose is 'other'." + }, + "high_risk_activities_explanation": { + "type": "string", + "description": "An explanation of the high risk activities that the business performs. \n\n_Required if `high_risk_activities` contains entries other than `none_of_the_above`_\n" + }, + "high_risk_activities": { + "type": "array", + "description": "List of high-risk activities the business is involved in.\n\n_Required for high risk customers. More information found [here](https://apidocs.bridge.xyz/docs/business-accounts)_\n", + "items": { + "type": "string", + "enum": [ + "adult_entertainment", + "gambling", + "hold_client_funds", + "investment_services", + "lending_banking", + "marijuana_or_related_services", + "money_services", + "nicotine_tobacco_or_related_services", + "operate_foreign_exchange_virtual_currencies_brokerage_otc", + "pharmaceuticals", + "precious_metals_precious_stones_jewelry", + "safe_deposit_box_rentals", + "third_party_payment_processing", + "weapons_firearms_and_explosives", + "none_of_the_above" + ] + } + }, + "source_of_funds": { + "type": "string", + "description": "The source of funds for the business, e.g. profits, income, venture capital, etc.", + "enum": [ + "business_loans", + "grants", + "inter_company_funds", + "investment_proceeds", + "legal_settlement", + "owners_capital", + "pension_retirement", + "sale_of_assets", + "sales_of_goods_and_services", + "third_party_funds", + "treasury_reserves" + ] + }, + "source_of_funds_description": { + "type": "string", + "description": "Description of the source of funds for the business' account.\n\n_Required for high risk customers. More information found [here](https://apidocs.bridge.xyz/docs/business-accounts)_\n" + }, + "conducts_money_services": { + "type": "boolean", + "description": "The business offers money services, investment products, and/or other financial services.\n\n_Required for high risk customers. More information found [here](https://apidocs.bridge.xyz/docs/business-accounts)_\n" + }, + "conducts_money_services_using_bridge": { + "type": "boolean", + "description": "The business plans to conduct money services, investment products, and/or other financial services using its Bridge account. A document with purpose 'flow_of_funds' is required if this is true.\n\n_Required if `conducts_money_services` is true_\n" + }, + "conducts_money_services_description": { + "type": "string", + "description": "Description of the money services offered by the business.\n\n_Required if `conducts_money_services` is true_\n" + }, + "identifying_information": { + "$ref": "#/components/schemas/IdentifyingInformation" + }, + "documents": { + "$ref": "#/components/schemas/BusinessDocuments" + }, + "incorporation_date": { + "type": "string", + "format": "date", + "description": "The date the business was incorporated, in ISO 8601 format (YYYY-MM-DD)." + }, + "verified_business_formation_at": { + "type": "string", + "format": "date-time", + "description": "Write-only ISO 8601 timestamp. For **EEA in-scope** businesses on **reliance**, may satisfy `BUSINESS_REGISTRY_CHECK_RELIANCE` together with good-standing/registry evidence (or use document purpose `business_formation`). See [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#evidence-of-good-standing).\n", + "writeOnly": true + }, + "verified_business_registry_at": { + "type": "string", + "format": "date-time", + "description": "Write-only ISO 8601 timestamp. For **EEA in-scope** businesses on **reliance**, registry-side evidence for `BUSINESS_REGISTRY_CHECK_RELIANCE`. Use `verified_evidence_of_good_standing_at` when the artifact maps to purpose `evidence_of_good_standing`.\n", + "writeOnly": true + }, + "verified_evidence_of_good_standing_at": { + "type": "string", + "format": "date-time", + "description": "Write-only ISO 8601 timestamp. For **EEA in-scope** businesses on **reliance**, evidence-of-good-standing path (`evidence_of_good_standing`) under `BUSINESS_REGISTRY_CHECK_RELIANCE`.\n", + "writeOnly": true + }, + "verified_ownership_at": { + "type": "string", + "format": "date-time", + "description": "Write-only ISO 8601 timestamp. For **EEA in-scope** businesses on **reliance**, may satisfy `BUSINESS_OWNERSHIP_RELIANCE` (ownership / cap-table documentation). See [EEA updated requirements — ownership document](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#ownership-document-always-required).\n", + "writeOnly": true + }, + "regulated_activity": { + "type": "object", + "required": [ + "regulated_activities_description", + "primary_regulatory_authority_country", + "primary_regulatory_authority_name", + "license_number" + ], + "properties": { + "regulated_activities_description": { + "type": "string", + "description": "A detailed description of the regulated activities the business is licensed to conduct." + }, + "primary_regulatory_authority_country": { + "type": "string", + "description": "The ISO 3166-1 (three-character) country code." + }, + "primary_regulatory_authority_name": { + "type": "string", + "description": "The name of the primary regulatory authority that oversees the business's regulated activities." + }, + "license_number": { + "type": "string", + "description": "The license number or registration number assigned by the business's primary regulator." + } + } + }, + "acting_as_intermediary": { + "type": "boolean", + "description": "Is the customer acting as an intermediary for a third party?\n\n_Required for high risk customers. More information found [here](https://apidocs.bridge.xyz/docs/business-accounts)_\n" + }, + "client_reference_id": { + "description": "Caller-provided identifier used to correlate this customer with your internal records. Returned in API and webhook responses.", + "$ref": "#/components/schemas/client_reference_id" + } + } + }, + "AssociatedPersonResponse": { + "type": "object", + "required": [ + "id", + "created_at", + "updated_at" + ], + "properties": { + "id": { + "type": "string", + "description": "Unique identifier for the associated person" + }, + "email": { + "type": "string", + "description": "The email address of the associated person" + }, + "first_name": { + "type": "string", + "minLength": 2, + "maxLength": 1024, + "description": "The first name of the associated person" + }, + "last_name": { + "type": "string", + "minLength": 2, + "maxLength": 1024, + "description": "The last name of the associated person" + }, + "has_ownership": { + "type": "boolean", + "description": "True if this person has at least 25% ownership of the business." + }, + "has_control": { + "type": "boolean", + "description": "True if this is the control person of the company, having significant responsibility to control, manage or influence the activities of the business entity." + }, + "is_signer": { + "type": "boolean", + "description": "True if this person is able to authorize transactions on behalf of the business." + }, + "title": { + "type": "string", + "description": "The title of this associated person at the company, e.g. CEO, CFO, etc." + }, + "attested_ownership_structure_at": { + "type": "string", + "description": "When this individual attested to the correctness of the ownership structure provided to Bridge. If provided by at least one control person, ownership documents for the business are not required." + }, + "relationship_established_at": { + "type": "string", + "description": "When the associated person relationship was established in format yyyy-mm-dd." + }, + "created_at": { + "type": "integer", + "description": "Created timestamp in milliseconds since Unix epoch" + }, + "updated_at": { + "type": "integer", + "description": "Last updated timestamp in milliseconds since Unix epoch" + } + } + }, + "AssociatedPerson": { + "required": [ + "first_name", + "last_name", + "email", + "residential_address", + "identifying_information", + "birth_date", + "has_ownership", + "has_control", + "is_signer" + ], + "properties": { + "first_name": { + "type": "string", + "minLength": 1, + "maxLength": 1024, + "description": "The first name of the associated person" + }, + "middle_name": { + "type": "string", + "minLength": 1, + "maxLength": 1024, + "description": "The middle name of the associated person" + }, + "last_name": { + "type": "string", + "minLength": 2, + "maxLength": 1024, + "description": "The last name of the associated person" + }, + "transliterated_first_name": { + "type": "string", + "description": "Required when the `first_name` includes any non Latin-1 characters. Acceptable characters - Latin-1 Unicode Character Range: À-ÖØ-ßà-öø-ÿ; Standard Unicode Character Range: -~", + "minLength": 1, + "maxLength": 256 + }, + "transliterated_middle_name": { + "type": "string", + "description": "Required when the `middle_name` includes any non Latin-1 characters. Acceptable characters - Latin-1 Unicode Character Range: À-ÖØ-ßà-öø-ÿ; Standard Unicode Character Range: -~", + "minLength": 1, + "maxLength": 256 + }, + "transliterated_last_name": { + "type": "string", + "description": "Required when the `last_name` includes any non Latin-1 characters. Acceptable characters - Latin-1 Unicode Character Range: À-ÖØ-ßà-öø-ÿ; Standard Unicode Character Range: -~", + "minLength": 1, + "maxLength": 256 + }, + "email": { + "type": "string", + "minLength": 1, + "maxLength": 1024, + "description": "The persons primary email address" + }, + "phone": { + "description": "The persons phone in format \"+12223334444\"", + "type": "string", + "minLength": 1, + "maxLength": 1024 + }, + "residential_address": { + "writeOnly": true, + "$ref": "#/components/schemas/Address2025WinterRefresh", + "description": "The residential address of the associated person. This must be a physical address and cannot be a PO Box." + }, + "transliterated_residential_address": { + "writeOnly": true, + "$ref": "#/components/schemas/Address2025WinterRefresh", + "description": "Required when any part of the `residential_address` includes any non Latin-1 characters. Acceptable characters - Latin-1 Unicode Character Range: À-ÖØ-ßà-öø-ÿ; Standard Unicode Character Range: -~" + }, + "birth_date": { + "type": "string", + "description": "Date of birth in format yyyy-mm-dd. Must be at least 18 years old.", + "minLength": 10, + "maxLength": 10 + }, + "nationality": { + "type": "string", + "writeOnly": true, + "description": "Legacy single nationality (ISO 3166-1 alpha-3). Prefer `nationalities` for all nationalities. See individual customer `nationality` / `nationalities` and [EEA nationalities](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#nationalities).\n" + }, + "nationalities": { + "type": "array", + "writeOnly": true, + "description": "All nationalities for this associated person (ISO 3166-1 alpha-3). **EEA / BBSA in-scope businesses:** required on each UBO / associated person where policy applies.\n", + "items": { + "type": "string", + "minLength": 3, + "maxLength": 3 + } + }, + "place_of_birth": { + "writeOnly": true, + "$ref": "#/components/schemas/PlaceOfBirthInput" + }, + "verified_database_at": { + "type": "string", + "format": "date-time", + "writeOnly": true, + "description": "Write-only ISO 8601 timestamp. For **EEA in-scope** associated persons on **reliance**, second factor with `verified_govid_at` under `TWO_FORMS_OF_ID_RELIANCE`.\n" + }, + "has_ownership": { + "type": "boolean", + "description": "True if this person has at least 25% ownership of the business." + }, + "has_control": { + "type": "boolean", + "description": "True if this is the control person of the company, having significant responsibility to control, manage or influence the activities of the business entity. At least one control person must be specified. " + }, + "is_signer": { + "type": "boolean", + "description": "True if this person is able to authorize transactions on behalf of the business. At least one signer must be specified." + }, + "is_director": { + "type": "boolean", + "description": "True if this person is an appointed director of the company. **EEA / BBSA in-scope businesses:** must be set for every associated person (complete director list). See [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#complete-director-list)." + }, + "title": { + "type": "string", + "description": "The title of this associated person at the company, e.g. CEO, CFO, etc. Required if has_control is true.", + "minLength": 1, + "maxLength": 1024 + }, + "ownership_percentage": { + "type": "integer", + "description": "Ultimate ownership percentage of the business. **EEA / BBSA in-scope businesses:** required when `has_ownership` is true for UBOs at or above the configured threshold (default 25%). See [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#ownership-percentage-per-ubo).\n", + "writeOnly": true + }, + "attested_ownership_structure_at": { + "type": "string", + "description": "The date or timestamp when this individual attested to the correctness of the ownership structure provided to Bridge. If provided by at least one control person, ownership documents for the business are not required.", + "writeOnly": true + }, + "verified_account_authorization_at": { + "type": "string", + "format": "date-time", + "description": "Write-only ISO 8601 timestamp. For **EEA in-scope** businesses on **reliance**, may satisfy signatory authority for signers who are not owner, director, or control person (`signature_authority_requirement(for_reliance: true)`); alternative is `documents` with purpose `proof_of_signatory_authority`. See [EEA updated requirements — LOA](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#letter-of-authority-loa).\n", + "writeOnly": true + }, + "relationship_established_at": { + "type": "string", + "description": "The date or timestamp when the associated person relationship was established in format yyyy-mm-dd." + }, + "verified_govid_at": { + "type": "string", + "format": "date-time", + "description": "Write-only ISO 8601 timestamp. For **EEA in-scope** associated persons on **reliance**, use with `verified_selfie_at` or `verified_database_at` under `TWO_FORMS_OF_ID_RELIANCE`.\n", + "writeOnly": true + }, + "verified_selfie_at": { + "type": "string", + "format": "date-time", + "description": "Write-only ISO 8601 timestamp. For **EEA in-scope** associated persons on **reliance**, pairs with `verified_govid_at` or `verified_database_at` under `TWO_FORMS_OF_ID_RELIANCE`.\n", + "writeOnly": true + }, + "identifying_information": { + "$ref": "#/components/schemas/IdentifyingInformation" + }, + "documents": { + "$ref": "#/components/schemas/IndividualDocuments" + } + } + }, + "FiatPayoutConfiguration": { + "type": "object", + "description": "A nested hash structure representing the fiat payout configuration. The top-level keys are currency codes. \nEach currency maps to a hash where keys are payment rail codes and values are payout names.\n", + "properties": { + "usd": { + "type": "object", + "description": "Payment rail configuration for USD", + "properties": { + "wire": { + "type": "string", + "enum": [ + "developer", + "customer" + ], + "description": "The payout method to use for USD wire transfers" + }, + "ach": { + "type": "string", + "enum": [ + "bridge" + ], + "description": "The payout method to use for USD ACH transfers" + } + } + }, + "eur": { + "type": "object", + "description": "Payment rail configuration for EUR", + "properties": { + "sepa": { + "type": "string", + "enum": [ + "bridge" + ], + "description": "The payout method to use for EUR SEPA transfers" + } + } + }, + "brl": { + "type": "object", + "description": "Payment rail configuration for BRL", + "properties": { + "pix": { + "type": "string", + "enum": [ + "payment_provider" + ], + "description": "The payout method to use for BRL PIX transfers" + } + } + }, + "mxn": { + "type": "object", + "description": "Payment rail configuration for MXN", + "properties": { + "spei": { + "type": "string", + "enum": [ + "payment_provider" + ], + "description": "The payout method to use for MXN SPEI transfers" + } + } + } + }, + "example": { + "usd": { + "wire": "developer", + "ach": "bridge" + }, + "eur": { + "sepa": "bridge" + }, + "brl": { + "pix": "payment_provider" + }, + "mxn": { + "spei": "payment_provider" + } + } + }, + "PatchFiatPayoutConfigurationInput": { + "type": "object", + "required": [ + "fiat_payout_configuration" + ], + "properties": { + "fiat_payout_configuration": { + "$ref": "#/components/schemas/FiatPayoutConfiguration" + } + }, + "description": "Input payload for updating a customer's fiat payout configuration", + "example": { + "fiat_payout_configuration": { + "usd": { + "wire": "customer" + } + } + } + }, + "FiatPayoutConfigurationResponse": { + "type": "object", + "required": [ + "fiat_payout_configuration" + ], + "properties": { + "fiat_payout_configuration": { + "$ref": "#/components/schemas/FiatPayoutConfiguration" + } + } + }, + "Payin": { + "required": [ + "customer_id", + "payment_rail", + "currency", + "amount", + "state" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/Id", + "readOnly": true + }, + "customer_id": { + "$ref": "#/components/schemas/Id" + }, + "payment_rail": { + "$ref": "#/components/schemas/PaymentRail" + }, + "currency": { + "$ref": "#/components/schemas/Currency" + }, + "amount": { + "description": "Amount of the payin, represented as a dollar denominated string. Examples include \"100.25\", \"0.1\", \"1.234567\" etc.", + "type": "string" + }, + "state": { + "description": "current state of the payin (more info to come!)", + "type": "string", + "readOnly": true + }, + "transaction_hash": { + "description": "The hash of the depositing transaction, for crypto payins", + "type": "string", + "readOnly": true + }, + "to_address": { + "description": "The destination address of the transaction, for crypto payins", + "type": "string", + "readOnly": true + } + } + }, + "FakePayin": { + "required": [ + "customer_id", + "payment_rail", + "currency", + "amount", + "state" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/Id", + "readOnly": true + }, + "customer_id": { + "$ref": "#/components/schemas/Id" + }, + "payment_rail": { + "$ref": "#/components/schemas/PaymentRail" + }, + "currency": { + "$ref": "#/components/schemas/Currency" + }, + "amount": { + "description": "Amount of the payin, represented as a dollar denominated string. Examples include \"100.25\", \"0.1\", \"1.234567\", \"1.01\" etc.", + "type": "string" + }, + "state": { + "description": "current state of the payin (more info to come!)", + "type": "string", + "readOnly": true + }, + "transaction_hash": { + "description": "The hash of the depositing transaction, for crypto payins only", + "type": "string" + }, + "to_address": { + "description": "The destination address of the transaction, for crypto payins only", + "type": "string" + } + } + }, + "Payout": { + "required": [ + "customer_id", + "payment_rail", + "currency", + "amount", + "external_account_id", + "state" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/Id", + "readOnly": true + }, + "customer_id": { + "$ref": "#/components/schemas/Id" + }, + "payment_rail": { + "$ref": "#/components/schemas/PaymentRail" + }, + "currency": { + "$ref": "#/components/schemas/Currency" + }, + "amount": { + "description": "Amount of the payout, represented as a dollar denominated string. Examples include \"100.25\", \"0.1\", \"1.234567\", \"1.01\" etc.", + "type": "string" + }, + "external_account_id": { + "$ref": "#/components/schemas/Id" + }, + "state": { + "description": "current state of the payout (more info to come!)", + "type": "string", + "readOnly": true + } + } + }, + "ReturnInstructions": { + "description": "Optional instructions for where to send funds if the transfer is returned (e.g. refund). Only supported when the source payment rail is crypto. Memo is required when the source payment rail is Stellar.", + "type": "object", + "required": [ + "address" + ], + "properties": { + "address": { + "description": "The crypto wallet address to send returned funds to. Must be valid for the source payment rail's chain.", + "type": "string" + }, + "memo": { + "description": "Memo to include with the return transaction. Required when the source payment rail is Stellar; optional for other memo-capable chains.", + "type": "string" + } + } + }, + "TransferInitiationAuthFactor": { + "type": "object", + "required": [ + "category", + "authenticated_at", + "reference" + ], + "properties": { + "category": { + "description": "The type of authentication factor used. Must be one of: `knowledge` (something only the user knows, e.g. a PIN or password), `possession` (something only the user has, e.g. a phone receiving an OTP or a hardware token), or `inherence` (something the user is, e.g. a fingerprint or face scan). When `outcome` is `sca_used`, the two factors in `auth_factors` must belong to two different categories.", + "type": "string", + "enum": [ + "knowledge", + "possession", + "inherence" + ] + }, + "authenticated_at": { + "description": "The ISO 8601 timestamp when this factor was authenticated.", + "type": "string", + "format": "date-time" + }, + "reference": { + "description": "Your internal identifier for this authentication event (e.g. a session ID, transaction ID, or audit log reference). Used for reconciliation; Bridge does not validate its format.", + "type": "string" + } + } + }, + "TransferInitiationSca": { + "type": "object", + "required": [ + "outcome" + ], + "properties": { + "outcome": { + "description": "Whether Strong Customer Authentication (SCA) was applied or which regulatory exemption or non-applicability reason covers this payment. Use `sca_used` when the user authenticated with SCA. Otherwise, choose the value that applies: `payment_to_self` — payer and payee are the same person (remote only); `trusted_beneficiaries` — payee is on the user's pre-approved list; `recurring_transaction` — amount and payee match a previously SCA-authorized recurring series; `contactless_low_value` — contactless card payment below the low-value threshold (non-remote only); `unattended_terminal_for_transport` — automated terminal for transport fares or parking (non-remote only); `low_value` — remote payment below the low-value threshold (remote only); `secure_corporate_payment` — dedicated corporate payment process with controls equivalent to SCA (remote only); `transaction_risk_analysis` — PSP has performed real-time risk analysis and the transaction falls within permitted thresholds (remote only); `merchant_initiated_transaction` — payment triggered by the merchant without the payer present, on a pre-authorized mandate (remote only); `not_applicable` — this flow requires initiation context but SCA and SCA exemptions do not apply; `other` — another recognized exemption not listed above.", + "type": "string", + "enum": [ + "sca_used", + "payment_to_self", + "trusted_beneficiaries", + "recurring_transaction", + "contactless_low_value", + "unattended_terminal_for_transport", + "low_value", + "secure_corporate_payment", + "transaction_risk_analysis", + "merchant_initiated_transaction", + "not_applicable", + "other" + ] + }, + "auth_factors": { + "description": "Authentication factor metadata. Optional when `outcome` is `sca_used`; if provided, it must contain at least two entries from different `category` values (e.g. one `possession` factor and one `knowledge` factor). Omit this field for any other outcome.", + "type": "array", + "minItems": 2, + "items": { + "$ref": "#/components/schemas/TransferInitiationAuthFactor" + } + } + } + }, + "TransferInitiationAttestations": { + "type": "object", + "required": [ + "sca" + ], + "properties": { + "sca": { + "$ref": "#/components/schemas/TransferInitiationSca" + } + } + }, + "TransferInitiation": { + "type": "object", + "description": "Payment initiation context required for transfers sourced from wallets where `initiation_required: true`. Captures how the payment was initiated (channel and subchannel) and whether Strong Customer Authentication was applied or which SCA exemption was used. This object is accepted on create only and is not returned in transfer responses.", + "required": [ + "channel", + "subchannel", + "attestations" + ], + "properties": { + "channel": { + "description": "How the payment was initiated. Use `p2p_mobile_payment` for peer-to-peer transfers initiated on a mobile device; `other_mobile_payment` for non-P2P mobile-initiated payments (e.g. a merchant payment via a mobile app); `other` for payments not relying on a mobile device.", + "type": "string", + "enum": [ + "p2p_mobile_payment", + "other_mobile_payment", + "other" + ] + }, + "subchannel": { + "description": "Whether the payment was made remotely or in person. Use `remote` for payments initiated from a distance (mobile app, online banking, or e-commerce checkout); `non_remote` for payments made in person (physical card, payment terminal, or contactless tap).", + "type": "string", + "enum": [ + "remote", + "non_remote" + ] + }, + "attestations": { + "$ref": "#/components/schemas/TransferInitiationAttestations" + } + } + }, + "TransferRequest": { + "required": [ + "on_behalf_of", + "source", + "destination" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/Id", + "readOnly": true + }, + "client_reference_id": { + "$ref": "#/components/schemas/client_reference_id" + }, + "amount": { + "description": "Amount of the transfer, expressed as a decimal string. Examples include \"100.25\", \"0.1\", \"1.234567\", \"1.01\" etc.\n\nIt is denominated in the source currency if that is a fiat currency, or in the fiat currency to which the source currency is pegged.", + "type": "string" + }, + "on_behalf_of": { + "description": "The id of the Bridge customer that you are moving funds on behalf of.", + "type": "string" + }, + "developer_fee": { + "description": "The fee, expressed as a decimal string, represents the amount you wish to reserve for your own account. This fee is the final amount deducted from what your customer ultimately receives, rather than a percentage.\n\nIt is denominated in the source currency if that is a fiat currency, or in the fiat currency to which the source currency is pegged.", + "type": "string" + }, + "developer_fee_percent": { + "description": "The fee percent, expressed as a decimal string from `0.0` to `100.0`, represents the percentage of the transfer you wish to reserve for your own account.\n\nThis field must be set instead of `developer_fee` when using [Flexible Amounts](https://apidocs.bridge.xyz/platform/orchestration/fees-and-mins/devfees#transfers-with-fixed-amounts).", + "type": "string" + }, + "dry_run": { + "description": "Whether to validate the transfer route without creating a transfer. If set to true, a valid transfer will return a `TransferRouteResponse` indicating the transfer would have been valid. The same error response will be returned for an invalid transfer as in the non-dry-run case.", + "type": "boolean" + }, + "source": { + "description": "The source of the transfer, which could be an external bank account, a bridge account, or a crypto wallet address.", + "allOf": [ + { + "$ref": "#/components/schemas/TransferSource" + }, + { + "properties": { + "from_address": { + "description": "The crypto wallet address that the customer will send funds from, in order to kick off this transfer.", + "type": "string" + } + } + } + ] + }, + "destination": { + "description": "The destination of the transfer, which could be an external bank account, a bridge account, or a crypto wallet address.", + "allOf": [ + { + "$ref": "#/components/schemas/TransferDestination" + }, + { + "properties": { + "amount": { + "description": "Specify the destination amount for the recipient to receive. Learn more at [Fixed Outputs Integration Guide](https://apidocs.bridge.xyz/get-started/guides/move-money/fixed_outputs_integration_guide).\n\nDenominated in the destination currency.\n\nExpressed as a decimal string. Examples include \"100.25\", \"0.1\", \"1.234567\", \"1.01\" etc.", + "type": "string" + }, + "to_address": { + "description": "The crypto wallet address that the customer wishes to ultimately receive funds at, in order to complete this transfer", + "type": "string" + }, + "wire_message": { + "type": "string" + } + } + } + ] + }, + "features": { + "description": "Features that should be enabled for this transfer. See [Transfer Features](https://apidocs.bridge.xyz/platform/orchestration/transfers/transfer-features) for more details.", + "type": "object", + "properties": { + "flexible_amount": { + "type": "boolean", + "description": "Allows for variable amounts to be accepted. When true, omit `amount` from the request body. Required to be `true` when the source payment rail is `swift`." + }, + "static_template": { + "type": "boolean" + }, + "allow_any_from_address": { + "type": "boolean" + } + } + }, + "return_instructions": { + "description": "Optional instructions for where to send funds if the transfer is returned (e.g. refund). Only supported when the source payment rail is crypto. When the source is Stellar, `memo` is required.", + "$ref": "#/components/schemas/ReturnInstructions" + }, + "initiation": { + "description": "Payment initiation context. Required when the source Bridge Wallet's GET response includes `initiation_required: true`. Omit for wallets that do not return that field. Not returned in transfer responses.", + "writeOnly": true, + "allOf": [ + { + "$ref": "#/components/schemas/TransferInitiation" + } + ] + }, + "travel_rule_data": { + "description": "Travel Rule data for this transfer. Use this when the same originator or beneficiary should apply to this transfer's movement. If the payload is only known after the transfer exists or is specific to a single movement, you can also submit the same object with `POST /travel_rule_data/{id}`.", + "allOf": [ + { + "$ref": "#/components/schemas/TravelRuleData" + } + ] + } + } + }, + "TransferUpdateRequest": { + "properties": { + "amount": { + "description": "Amount of the transfer, expressed as a decimal string. Examples include \"100.25\", \"0.1\", \"1.234567\", \"1.01\" etc.\n\nIt is denominated in the source currency if that is a fiat currency, or in the fiat currency to which the source currency is pegged.", + "type": "string" + }, + "developer_fee": { + "description": "The fee, expressed as a decimal string, represents the amount you wish to reserve for your own account. This fee is the final amount deducted from what your customer ultimately receives, rather than a percentage.\n\nIt is denominated in the source currency if that is a fiat currency, or in the fiat currency to which the source currency is pegged.", + "type": "string" + }, + "developer_fee_percent": { + "description": "The fee percent, expressed as a decimal string from `0.0` to `100.0`, represents the percentage of the transfer you wish to reserve for your own account.\n\nThis field must be set instead of `developer_fee` when using [Flexible Amounts](https://apidocs.bridge.xyz/platform/orchestration/fees-and-mins/devfees#transfers-with-fixed-amounts).", + "type": "string" + }, + "return_instructions": { + "description": "Optional instructions for where to send funds if the transfer is returned (e.g. refund). Only supported when the source payment rail is crypto. When the source is Stellar, `memo` is required.", + "$ref": "#/components/schemas/ReturnInstructions" + } + } + }, + "TransferRouteResponse": { + "required": [ + "state", + "notes" + ], + "properties": { + "state": { + "type": "string", + "enum": [ + "valid", + "invalid" + ] + }, + "notes": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "TransferResponse": { + "required": [ + "id", + "amount", + "developer_fee", + "currency", + "on_behalf_of", + "source", + "destination", + "state", + "receipt", + "created_at", + "updated_at" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/Id", + "readOnly": true + }, + "client_reference_id": { + "$ref": "#/components/schemas/client_reference_id" + }, + "amount": { + "description": "Amount of the transfer, expressed as a decimal string. Examples include \"100.25\", \"0.1\", \"1.234567\", \"1.01\" etc.\n\nIt is denominated in the source currency if that is a fiat currency, or in the fiat currency to which the source currency is pegged.", + "type": "string" + }, + "currency": { + "description": "Fiat currency for the transfer amount and developer fee. It's the source currency if that is a fiat currency or the fiat currency to which the source currency is pegged.", + "$ref": "#/components/schemas/EuroInclusiveFiatCurrency" + }, + "on_behalf_of": { + "description": "The id of the Bridge customer that you are moving funds on behalf of.", + "type": "string" + }, + "developer_fee": { + "description": "The fee, expressed as a decimal string, represents the amount you wish to reserve for your own account. This fee is the final amount deducted from what your customer ultimately receives, rather than a percentage.\n\nIt is denominated in the source currency if that is a fiat currency, or in the fiat currency to which the source currency is pegged.", + "type": "string" + }, + "developer_fee_percent": { + "description": "The fee percent, expressed as a decimal string from `0.0` to `100.0`, represents the percentage of the transfer you wish to reserve for your own account.\n\nThis field must be set instead of `developer_fee` when using [Flexible Amounts](https://apidocs.bridge.xyz/platform/orchestration/fees-and-mins/devfees#transfers-with-fixed-amounts).", + "type": "string" + }, + "source": { + "description": "The source of the transfer, which could be an external bank account, a bridge account, or a crypto wallet address", + "allOf": [ + { + "$ref": "#/components/schemas/TransferSource" + }, + { + "properties": { + "currency": { + "description": "The source currency", + "$ref": "#/components/schemas/EuroInclusiveCurrency" + }, + "payment_rail": { + "description": "The intended source payment rail", + "$ref": "#/components/schemas/TransferSourcePaymentRail" + }, + "payment_received_rail": { + "description": "The rail on which the payment was actually received. Set once the funds have been onramped.", + "$ref": "#/components/schemas/TransferSourcePaymentRail", + "readOnly": true + }, + "from_address": { + "description": "The crypto wallet address that the customer will send funds from, in order to kick off this transfer", + "type": "string" + } + } + } + ] + }, + "destination": { + "description": "The destination of the transfer, which could be an external bank account, a bridge account, or a crypto wallet address", + "allOf": [ + { + "$ref": "#/components/schemas/TransferDestination" + }, + { + "properties": { + "amount": { + "description": "The destination amount for the recipient to receive. Present when the transfer was created with a destination amount (Fixed Outputs).\n\nDenominated in the destination currency.\n\nExpressed as a decimal string. Examples include \"100.25\", \"0.1\", \"1.234567\", \"1.01\" etc.", + "type": "string", + "readOnly": true + }, + "currency": { + "description": "The destination currency", + "$ref": "#/components/schemas/EuroInclusiveCurrency" + }, + "payment_rail": { + "description": "The destination payment rail", + "$ref": "#/components/schemas/SepaSwiftInclusivePaymentRail" + }, + "to_address": { + "description": "The crypto wallet address that the customer wishes to ultimately receive funds at, in order to complete this transfer", + "type": "string" + }, + "wire_message": { + "description": "A message to be sent with a wire transfer, only allowed when the payment rail is a wire. This message will be validated against 4 lines, each with a max length of 35 char according to the Fedwire standard.", + "type": "string" + }, + "blockchain_memo": { + "description": "A message to be sent with a crypto transaction, only allowed when the payment rail supports memo, e.g. Stellar.", + "type": "string" + } + } + } + ] + }, + "state": { + "description": "Status of the transfer. See [Transfer States](https://apidocs.bridge.xyz/platform/orchestration/transfers/transfer-states) for more details.", + "readOnly": true, + "$ref": "#/components/schemas/TransferState" + }, + "source_deposit_instructions": { + "readOnly": true, + "description": "Some transfers require a deposit to be made by the customer before Bridge can start the process. Instructions for how to kick off the transfer will be included here. The deposit must match these instructions exactly, or the transfer will fail.", + "allOf": [ + { + "$ref": "#/components/schemas/DepositInstructions" + }, + { + "properties": { + "currency": { + "description": "The source currency", + "$ref": "#/components/schemas/EuroInclusiveCurrency" + }, + "payment_rail": { + "description": "The source payment rail", + "$ref": "#/components/schemas/SepaSwiftInclusivePaymentRail" + }, + "amount": { + "description": "Amount of the deposit, expressed as a decimal string. It's denominated in the source currency if that is a fiat currency, or in the fiat currency to which the source currency is pegged. Examples include \"100.25\", \"0.1\", \"1.234567\", \"1.01\" etc.", + "type": "string" + }, + "deposit_message": { + "description": "The message that the customer MUST include in their `wire memo/message`, `ach push description`, or `sepa reference`.", + "type": "string" + }, + "blockchain_memo": { + "description": "If present, the message that the customer MUST include in their on chain transfer. Only used for memo-based blockchains such as Stellar and Tron", + "type": "string" + } + } + } + ] + }, + "receipt": { + "description": "Receipt information of a transfer", + "$ref": "#/components/schemas/Receipt" + }, + "return_details": { + "readOnly": true, + "description": "Return information, if the transfer has been returned.", + "$ref": "#/components/schemas/TransferReturnDetails" + }, + "return_instructions": { + "readOnly": true, + "description": "Optional return instructions configured when creating or updating the transfer.", + "$ref": "#/components/schemas/ReturnInstructions" + }, + "exchange_details": { + "readOnly": true, + "description": "Exchange details for the associated trade, if applicable.", + "$ref": "#/components/schemas/ExchangeDetails" + }, + "created_at": { + "readOnly": true, + "type": "string", + "description": "Time of creation of the transfer", + "format": "date-time" + }, + "updated_at": { + "readOnly": true, + "type": "string", + "description": "Time of update of the transfer", + "format": "date-time" + }, + "template_id": { + "readOnly": true, + "description": "The ID of the static template transfer from which this transfer was instantiated. Only present for transfers created from a template.", + "$ref": "#/components/schemas/Id" + }, + "first_confirmed_at": { + "readOnly": true, + "type": "string", + "description": "Time when the withdrawal transaction received its first on-chain confirmation. Only present for crypto withdrawal transfers where this feature is enabled for the developer.", + "format": "date-time" + } + } + }, + "TransferReturnDetails": { + "properties": { + "reason": { + "description": "The reason for the return, as given by the returning financial institution.", + "type": "string" + }, + "refund_reference_id": { + "description": "A unique identifier (such as transaction hash) for the refund transaction.", + "type": "string" + }, + "risk_rejection_reason": { + "description": "If the return is due to a risk rejection, this field will be populated with the reason for the risk rejection.", + "type": "string" + } + } + }, + "Receipt": { + "required": [ + "initial_amount", + "developer_fee", + "exchange_fee", + "subtotal_amount" + ], + "properties": { + "initial_amount": { + "description": "The initial amount of the transfer from the source, represented as a decimal string. Examples include \"100.25\", \"0.1\", \"1.234567\", \"1.01\" etc.", + "type": "string" + }, + "developer_fee": { + "description": "The fee, expressed as a decimal string, represents the amount of the transfer reserved for your own account. This fee is the final amount deducted from what your customer ultimately receives, rather than a percentage.", + "type": "string" + }, + "exchange_fee": { + "description": "The fee, expressed as a decimal string, represents the amount Bridge charges for facilitating the transfer. This is the final amount deducted from what your customer ultimately receives, rather than a percentage. It can be deducted from the initial amount/currency or the converted amount/currency. ", + "type": "string" + }, + "developer_exchange_fee": { + "description": "For FixedOutput trades, the amount, expressed as a decimal string, of the traded money that was not necessary to deliver the fixed output, returned to the developer.", + "type": "object", + "properties": { + "amount": { + "description": "Amount of the fee", + "type": "string" + }, + "currency": { + "description": "Currency of the fee", + "type": "string" + } + } + }, + "pre_conversion_subtotal_amount": { + "description": "On transfers with a variable trade, the amount of money, expressed as a decimal string, that is passed into the trade itself. Equal to the initial amount less any fees applied on the input side of the trade", + "type": "string" + }, + "mid_market_rate": { + "description": "If the transfer includes a market rate trade, this is the mid-market rate used to calculate the output of the trade. It is expressed as a decimal string.", + "type": "string" + }, + "converted_amount": { + "description": "If the transfer includes a variable trade, the amount of money, expressed as a decimal string, received after the trade, before any final fees are deducted.", + "type": "string" + }, + "subtotal_amount": { + "description": "The amount, expressed as a decimal string, remaining from the converted amount after any remaining non-gas fees have been deducted. ", + "type": "string" + }, + "remaining_prefunded_balance": { + "description": "For Prefunded Accounts, this value will represent the remaining account balance after the transfer.", + "type": "string" + }, + "gas_fee": { + "description": "The fee, expressed as a decimal string. It's deducted from the withdrawn amount to pay for gas. Only nonzero to crypto withdrawals that cost gas (e.g. USDT), and only known when the transaction is confirmed on-chain. Will be missing if not yet known.\n\nIt's denominated in the fiat currency to which the destination currency is pegged.", + "type": "string" + }, + "final_amount": { + "description": "The final amount of the transfer, expressed as a decimal string, equal to the subtotal_amount minus any gas fees. If the gas fee is not known, this field will be missing. Examples include \"100.25\", \"0.1\", \"1.234567\", \"1.01\" etc.\n\nIt's denominated in the destination currency if that is a fiat currency or the fiat currency to which the destination currency is pegged.", + "type": "string" + }, + "source_tx_hash": { + "description": "The hash of the on-chain deposit to the source address, where applicable" + }, + "destination_tx_hash": { + "description": "The hash of the on-chain transfer to the destination address, where applicable" + }, + "exchange_rate": { + "description": "The effective exchange rate can be calculated by dividing the converted amount by the amount available for conversion after deducting the developer fee. This rate includes a currency conversion spread and is subject to a rounding precision loss during the calculation. Currently it's populated for SEPA onramp/offramp transfers only." + }, + "url": { + "description": "The URL of a user-facing copy of the receipt.", + "type": "string" + }, + "bank_details": { + "description": "Bank-lookup details for fiat offramp receipts, to help the recipient's bank locate the payment. Present for enabled developers once the offramp's bank leg exists; individual fields may be null until they become available (e.g. the ACH trace ID before submission to the Fed).", + "type": "object", + "properties": { + "sending_routing_number": { + "description": "Routing number of the bank Bridge sent the payment from.", + "type": "string" + }, + "ach_description": { + "description": "Statement descriptor on the outgoing ACH credit.", + "type": "string" + }, + "ach_trace_id": { + "description": "ACH trace number, populated after submission to the Fed.", + "type": "string" + }, + "wire_message": { + "description": "Message sent with the outgoing wire (beneficiary, FI-to-FI, or receiving-FI message).", + "type": "string" + }, + "imad": { + "description": "IMAD (Input Message Accountability Data) of the outgoing wire, populated after posting.", + "type": "string" + }, + "recipient_name": { + "description": "Name on the receiving external account.", + "type": "string" + }, + "sending_bic": { + "description": "BIC of the bank Bridge sent the SEPA payment from.", + "type": "string" + }, + "sepa_reference": { + "description": "SEPA payment reference.", + "type": "string" + }, + "uetr": { + "description": "Unique End-to-end Transaction Reference (UETR) of the SEPA payment.", + "type": "string" + }, + "receiving_account_last_four": { + "description": "Last four digits of the receiving IBAN.", + "type": "string" + }, + "receiving_bic": { + "description": "BIC of the receiving bank.", + "type": "string" + } + } + } + } + }, + "ExchangeDetails": { + "description": "Exchange information for a currency conversion.", + "properties": { + "fixed_rate": { + "description": "The target exchange rate.", + "type": "string" + }, + "estimated_market_rate": { + "description": "The estimated achievable rate based on current market conditions.", + "type": "string" + }, + "traded_market_rate": { + "description": "The actual effective exchange rate achieved.", + "type": "string" + }, + "trade_at_market": { + "description": "Whether market-rate execution has been applied to this trade.", + "type": "boolean" + }, + "updated_at": { + "description": "Timestamp of the last exchange details update.", + "type": "string", + "format": "date-time" + } + } + }, + "DrainReceipt": { + "required": [ + "initial_amount", + "developer_fee", + "exchange_rate", + "subtotal_amount", + "converted_amount", + "outgoing_amount", + "destination_currency" + ], + "properties": { + "initial_amount": { + "description": "The initial amount of the drain, denominated in the fiat currency to which the currency of the Liquidation Address is pegged. Examples include \"100.25\", \"0.1\", \"1.234567\", \"1.000000000000000001\" etc.", + "type": "string" + }, + "developer_fee": { + "description": "The developer fee, denominated in the fiat currency to which the currency of the Liquidation Address is pegged. This fee is a specific amount deducted from the initial total before conversion, rather than a percentage.", + "type": "string" + }, + "subtotal_amount": { + "description": "The initial amount of the drain less the `developer_fee`, denominated in the fiat currency to which the Liquidation Address currency is pegged. Examples include \"100.25\", \"0.1\", \"1.234567\", \"1.000000000000000001\" etc.", + "type": "string" + }, + "gas_fee": { + "description": "The fee that is deducted from the withdrawn amount to pay for gas. Only included for crypto withdrawals that cost gas (e.g. USDT). It's denominated in the fiat currency to which the destination currency is pegged.", + "type": "string" + }, + "converted_amount": { + "description": "The converted amount of the drain. It's denominated in the destination currency or its pegged fiat currency.", + "type": "string" + }, + "exchange_rate": { + "description": "The effective exchange rate that can be calculated by dividing the converted amount by the amount available for conversion after deducting the developer fee." + }, + "outgoing_amount": { + "description": "The final amount of the drain, equal to the `converted_amount` minus any gas fees. It's denominated in the destination currency or its pegged fiat currency.", + "type": "string" + }, + "destination_currency": { + "$ref": "#/components/schemas/Currency", + "description": "The currency of the fund sent to the customer." + }, + "url": { + "description": "The URL of a user-facing copy of the receipt.", + "type": "string" + } + } + }, + "PutWebhookPayload": { + "properties": { + "url": { + "description": "The new HTTPS URL that Bridge will send events to.", + "type": "string", + "minLength": 1 + }, + "status": { + "description": "The new status of the webhook endpoint. If set to \"active\", the webhook will be enabled and will send requests to the new URL. If set to \"disabled\", the webhook will be disabled and will not send requests to the URL.", + "type": "string", + "enum": [ + "active", + "disabled" + ] + }, + "event_categories": { + "type": "array", + "description": "The list of event categories that the webhook endpoint will receive. Note that if modified, the webhook endpoint will receive events for new categories only from the current point onwards.", + "minItems": 0, + "items": { + "$ref": "#/components/schemas/WebhookEventCategory" + } + } + } + }, + "SendWebhookPayload": { + "properties": { + "event_id": { + "description": "The ID of the event that will be delivered to your endpoint", + "type": "string", + "minLength": 1 + } + } + }, + "TransferSource": { + "required": [ + "currency", + "payment_rail" + ], + "properties": { + "currency": { + "description": "When `eur` is specified as the source currency:\n 1. the source rail must be `sepa`;\n 2. only `usdc` or `eurc` are supported as the destination currency", + "$ref": "#/components/schemas/EuroInclusiveCurrency" + }, + "payment_rail": { + "description": "When `sepa` is specified as the source rail:\n 1. the source currency must be `eur`;\n 2. only `usdc` or `eurc` are supported as the destination currency \n\n **Note: This is the intended payment rail, and may differ from the actual payment rail used to onramp the funds.**", + "$ref": "#/components/schemas/TransferSourcePaymentRail" + }, + "payment_scheme": { + "description": "(SEPA only) The payment scheme used for this transaction, such as SEPA Credit Transfer or SEPA Instant", + "readOnly": true, + "$ref": "#/components/schemas/PaymentScheme" + }, + "omad": { + "$ref": "#/components/schemas/Omad", + "readOnly": true + }, + "imad": { + "$ref": "#/components/schemas/Imad", + "readOnly": true + }, + "trace_number": { + "$ref": "#/components/schemas/TraceNumber", + "readOnly": true + }, + "bank_beneficiary_name": { + "description": "(Wire only) The name of the beneficiary of the bank account that the customer sent the deposit to", + "type": "string", + "readOnly": true + }, + "bank_beneficiary_address": { + "description": "(Wire only) The address of the beneficiary of the bank account that the customer sent the deposit to", + "type": "string", + "readOnly": true + }, + "bank_routing_number": { + "description": "(Wire only) The routing number of the bank that the customer sent the deposit to", + "type": "string", + "readOnly": true + }, + "bank_name": { + "description": "(Wire and SPEI only) The name of the bank that the customer sent the deposit from.", + "type": "string", + "readOnly": true + }, + "originator_name": { + "description": "(Wire only) The originator name of this wire", + "type": "string", + "readOnly": true + }, + "originator_address": { + "description": "(Wire only) The originator address of this wire", + "type": "string", + "readOnly": true + }, + "wire_message": { + "description": "(Wire only) The memo for this wire", + "type": "string", + "readOnly": true + }, + "bridge_wallet_id": { + "description": "(Bridge Wallet only) The ID of the Bridge Wallet to draw funds from", + "$ref": "#/components/schemas/Id" + }, + "sender_name": { + "description": "(ACH and FedNow only) The name of the business or individual who initiated the transaction", + "type": "string", + "readOnly": true + }, + "sender_bank_routing_number": { + "description": "(ACH and FedNow only) The routing number of the entity that initiated this transaction", + "type": "string", + "readOnly": true + }, + "end_to_end_id": { + "$ref": "#/components/schemas/EndToEndId", + "readOnly": true + }, + "description": { + "description": "(ACH only) The description of the deposit that the customer sent", + "type": "string", + "readOnly": true + }, + "tracking_number": { + "$ref": "#/components/schemas/TrackingNumber", + "readOnly": true + }, + "clabe": { + "description": "(SPEI only) The 18-digit CLABE of the sender who initiated this SPEI transaction", + "$ref": "#/components/schemas/Clabe", + "readOnly": true + }, + "bank_code": { + "description": "(SPEI only) The bank code of the sender's bank that initiated this SPEI transaction.", + "type": "string", + "readOnly": true + }, + "transaction_id": { + "$ref": "#/components/schemas/TransactionId", + "readOnly": true + }, + "co_bank_transfer": { + "description": "(co_bank_transfer only) Details for Colombian bank transfers.", + "type": "object", + "required": [ + "redirect_url" + ], + "properties": { + "redirect_url": { + "description": "URL to redirect the customer to after completing the bank transfer", + "type": "string", + "writeOnly": true + }, + "expiry_date": { + "description": "Optional ISO 8601 expiry timestamp for the payment session. Defaults to 24 hours from creation.", + "type": "string", + "writeOnly": true + }, + "sender_data": { + "description": "Sender information for the CO bank transfer. If omitted, the payer must manually provide this information via the payment link. If provided, fields will be pre-populated for the payer. Sensitive fields are masked in responses (e.g. document_number shows `***3456`).", + "type": "object", + "required": [ + "full_name", + "document_type", + "document_number", + "email", + "phone_number" + ], + "properties": { + "full_name": { + "description": "Full name of the sender", + "type": "string" + }, + "document_type": { + "$ref": "#/components/schemas/CoBankTransferDocumentType" + }, + "document_number": { + "description": "Document number of the sender. Masked in responses (e.g. ***3456).", + "type": "string" + }, + "email": { + "description": "Email address of the sender", + "type": "string" + }, + "phone_number": { + "description": "Phone number of the sender in E.164 format (e.g. +573001234567)", + "type": "string" + } + } + } + } + } + } + }, + "TransferDestination": { + "required": [ + "currency", + "payment_rail" + ], + "properties": { + "currency": { + "description": "When `eur` is specified as the destination currency, the destination rail must be `sepa`.", + "$ref": "#/components/schemas/EuroInclusiveCurrency" + }, + "payment_rail": { + "description": "When `sepa` is specified as the destination payment rail, the destination currency must be `eur`; when `swift` is specified as the destination payment rail, the destination currency must be `usd`.", + "$ref": "#/components/schemas/SepaSwiftInclusiveOfframpPaymentRail" + }, + "external_account_id": { + "description": "External bank account Bridge should send the funds to. The currency associated with the External Account must match the destination currency.", + "$ref": "#/components/schemas/Id" + }, + "bridge_wallet_id": { + "description": "The Bridge Wallet to which Bridge will send the funds. The chain associated with the Bridge Wallet must match the destination payment rail.", + "$ref": "#/components/schemas/Id" + }, + "omad": { + "$ref": "#/components/schemas/Omad", + "readOnly": true + }, + "imad": { + "$ref": "#/components/schemas/Imad", + "readOnly": true + }, + "trace_number": { + "$ref": "#/components/schemas/TraceNumber", + "readOnly": true + }, + "end_to_end_id": { + "$ref": "#/components/schemas/EndToEndId", + "readOnly": true + }, + "wire_message": { + "$ref": "#/components/schemas/WireMessage" + }, + "sepa_reference": { + "$ref": "#/components/schemas/SepaReference" + }, + "swift_reference": { + "$ref": "#/components/schemas/SwiftReference" + }, + "spei_reference": { + "$ref": "#/components/schemas/SpeiReference" + }, + "reference": { + "$ref": "#/components/schemas/Reference" + }, + "charge_bearer": { + "description": "Which party bears the charges for the SWIFT transaction. Defaults to `sha` when not specified. Accepted on both request and response.", + "$ref": "#/components/schemas/ChargeBearer" + }, + "ach_reference": { + "$ref": "#/components/schemas/AchReference" + }, + "uetr": { + "$ref": "#/components/schemas/Uetr" + }, + "blockchain_memo": { + "type": "string", + "description": "The memo to include when sending funds on chain. Only allowed for blockchains that support memos such as Stellar" + }, + "deposit_id": { + "$ref": "#/components/schemas/DepositId" + }, + "tracking_number": { + "$ref": "#/components/schemas/TrackingNumber", + "readOnly": true + }, + "transaction_id": { + "$ref": "#/components/schemas/TransactionId", + "readOnly": true + }, + "sending_institution_name": { + "description": "The name of the institution sending the funds", + "type": "string", + "readOnly": true + } + } + }, + "DrainDestination": { + "required": [ + "payment_rail", + "currency" + ], + "properties": { + "payment_rail": { + "$ref": "#/components/schemas/PaymentRail" + }, + "currency": { + "$ref": "#/components/schemas/Currency" + }, + "to_address": { + "description": "The crypto wallet address that the customer will ultimately receive funds at", + "type": "string" + }, + "blockchain_memo": { + "description": "The memo to include in the transaction, for blockchains that support memos only", + "type": "string" + }, + "external_account_id": { + "description": "External bank account to which Bridge will send the funds.", + "$ref": "#/components/schemas/Id" + }, + "wire_message": { + "description": "A message to be sent with a wire transfer.", + "$ref": "#/components/schemas/WireMessage" + }, + "sepa_reference": { + "$ref": "#/components/schemas/SepaReference" + }, + "swift_reference": { + "$ref": "#/components/schemas/SwiftReference" + }, + "spei_reference": { + "$ref": "#/components/schemas/SpeiReference" + }, + "reference": { + "$ref": "#/components/schemas/Reference" + }, + "ach_reference": { + "$ref": "#/components/schemas/AchReference" + }, + "imad": { + "$ref": "#/components/schemas/Imad" + }, + "trace_number": { + "$ref": "#/components/schemas/TraceNumber", + "readOnly": true + }, + "tracking_number": { + "$ref": "#/components/schemas/TrackingNumber", + "readOnly": true + }, + "transaction_id": { + "$ref": "#/components/schemas/TransactionId", + "readOnly": true + }, + "sending_institution_name": { + "description": "The name of the institution sending the funds", + "type": "string", + "readOnly": true + }, + "uetr": { + "$ref": "#/components/schemas/Uetr" + } + } + }, + "DrainReturnDetails": { + "properties": { + "reason": { + "description": "The reason for the return, as given by the returning financial institution.", + "type": "string" + }, + "risk_rejection_reason": { + "description": "If the return is due to a risk rejection, this field will be populated with the reason for the risk rejection.", + "type": "string" + } + } + }, + "DepositInstructions": { + "readOnly": true, + "required": [ + "payment_rail", + "amount", + "currency" + ], + "properties": { + "payment_rail": { + "description": "The payment rail that Bridge is expecting funds to arrive on. For a crypto based source on the transfer, this is the chain, i.e. ethereum or polygon", + "$ref": "#/components/schemas/PaymentRail" + }, + "amount": { + "description": "Amount of the deposit, represented as a dollar denominated string. Examples include \"100.25\", \"0.1\", \"1.234567\", \"1.01\" etc.", + "type": "string" + }, + "currency": { + "$ref": "#/components/schemas/Currency" + }, + "from_address": { + "description": "The crypto wallet address that the customer will send funds from, in order to kick off this transfer", + "type": "string" + }, + "to_address": { + "description": "The crypto wallet address the customer will send funds to in order to initiate the payment processing", + "type": "string", + "nullable": true + }, + "memoless_to_address": { + "description": "An alternative crypto wallet address that encodes the memo, allowing the customer to send funds without needing to include a separate memo. Currently only available for Stellar deposits.", + "type": "string" + }, + "deposit_message": { + "description": "The message that the customer MUST include in their wire memo/message or ach push description", + "type": "string" + }, + "bank_name": { + "description": "The name of the bank that the customer should send the deposit to", + "type": "string" + }, + "bank_address": { + "description": "The address of the bank that the customer should send the deposit to. For SEPA, the country in this address should be used for sending the deposit", + "type": "string" + }, + "bank_routing_number": { + "description": "The routing number of the bank that the customer should send the deposit to", + "type": "string" + }, + "bank_account_number": { + "description": "The account number of the bank that the customer should send the deposit to", + "type": "string" + }, + "bank_beneficiary_name": { + "description": "The name of the beneficiary of the bank account that the customer should send the deposit to", + "type": "string" + }, + "bank_beneficiary_address": { + "description": "The address of the beneficiary of the bank account that the customer should send the deposit to", + "type": "string" + }, + "intermediary_bank_name": { + "description": "For USD SWIFT, the name of the intermediary correspondent bank that the originating bank should route the payment through.", + "type": "string" + }, + "intermediary_bank_bic": { + "description": "For USD SWIFT, the SWIFT/BIC of the intermediary correspondent bank", + "type": "string" + }, + "intermediary_bank_routing_number": { + "description": "For USD SWIFT, the ABA routing number of the intermediary correspondent bank", + "type": "string" + }, + "iban": { + "description": "For SEPA, the International Bank Account Number (IBAN) that the customer should use to send the deposit", + "type": "string" + }, + "bic": { + "description": "For SEPA, the Bank Identifier Code (BIC) that the customer should use to send the deposit", + "type": "string" + }, + "clabe": { + "description": "For SPEI, the CLABE (account number) that the customer should use to send the deposit", + "type": "string" + }, + "account_holder_name": { + "description": "For SEPA, the name of the bank account holder that the customer should use to send the deposit", + "type": "string" + }, + "bre_b_key": { + "description": "For Bre-B (Colombia), the Bre-B key that the customer should use to send the COP deposit", + "type": "string" + }, + "start_url": { + "description": "For co_bank_transfer (Colombia), the URL the customer should be redirected to in order to complete the bank transfer payment", + "type": "string" + }, + "redirect_url": { + "description": "For co_bank_transfer (Colombia), the merchant redirect URL provided when the transfer was created", + "type": "string" + }, + "expires_at": { + "description": "For Pix (Brazil) and co_bank_transfer (Colombia), the ISO 8601 timestamp when the payment session expires", + "type": "string" + } + } + }, + "PrefundedAccount": { + "required": [ + "id", + "available_balance", + "currency", + "name" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/Id", + "readOnly": true + }, + "available_balance": { + "description": "Amount available for spending, represented as a dollar denominated string. Examples include \"100.25\", \"0.1\", \"1.234567\", \"1.01\" etc.", + "type": "string", + "readOnly": true + }, + "currency": { + "description": "currency associated with the bank account.", + "$ref": "#/components/schemas/FiatCurrency", + "readOnly": true + }, + "name": { + "description": "Serialized name of the account which identifies the counterparty.", + "type": "string", + "readOnly": true + } + } + }, + "PrefundedAccountHistory": { + "required": [ + "id", + "amount", + "available_balance", + "currency", + "name", + "type", + "created_at" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/Id", + "readOnly": true + }, + "amount": { + "description": "Amount of the transaction, represented as a dollar denominated string. Examples include \"100.25\", \"0.1\", \"1.234567\", \"1.01\" etc.", + "type": "string", + "readOnly": true + }, + "available_balance": { + "description": "Amount available for spending, represented as a dollar denominated string. Examples include \"100.25\", \"0.1\", \"1.234567\", \"1.01\" etc.", + "type": "string", + "readOnly": true + }, + "currency": { + "description": "currency associated with the bank account.", + "$ref": "#/components/schemas/FiatCurrency", + "readOnly": true + }, + "name": { + "description": "Serialized name of the account.", + "type": "string", + "readOnly": true + }, + "type": { + "description": "The type of the transaction.", + "type": "string", + "enum": [ + "funding", + "refunded transfer" + ], + "readOnly": true + }, + "created_at": { + "readOnly": true, + "type": "string", + "description": "Time of creation of the External Account", + "format": "date-time" + }, + "withdrawal_id": { + "readOnly": true, + "type": "string", + "description": "The ID of the transfer which created this event. Exclusive with deposit_id." + }, + "deposit_id": { + "readOnly": true, + "type": "string", + "description": "The ID of the transfer which created this event. Exclusive with withdrawal_id." + } + } + }, + "ExternalAccountBaseWithOwnerInfo": { + "description": "Properties shared by all external account types", + "properties": { + "id": { + "$ref": "#/components/schemas/Id", + "readOnly": true + }, + "customer_id": { + "description": "The id of the Bridge customer that this External Account belongs to", + "type": "string", + "minLength": 1, + "readOnly": true + }, + "bank_name": { + "description": "Bank name of the account (e.g. \"Chase\")", + "type": "string", + "minLength": 1, + "maxLength": 256 + }, + "account_owner_name": { + "description": "Owner of the account Bank Account (e.g. \"John Doe\"). For ach, wire, and iban accounts, this field must be at least 3 characters, at most 35 characters, and follow the regex pattern for the given account type:\n- ach: `^(?!\\s*$)[\\x20-\\x7E]*$`\n- wire: ```^[ \\w!\"#$%&'()+,\\-./:;<=>?@\\\\_`~]*$```\n- iban: `^(?![:\\- ]*$)[a-zA-Z0-9\\/\\-?:().,'+ _]+$`\n", + "type": "string", + "minLength": 1, + "maxLength": 256 + }, + "created_at": { + "readOnly": true, + "type": "string", + "description": "Time of creation of the External Account", + "format": "date-time" + }, + "updated_at": { + "readOnly": true, + "type": "string", + "description": "Time of last update of the External Account", + "format": "date-time" + }, + "active": { + "readOnly": true, + "type": "boolean", + "description": "Whether or not this External Account is active" + }, + "account_owner_type": { + "description": "The type of the account ownership. Required when the `account_type` is `iban`. For `individual` ownership, `first_name` and `last_name` are required. For `business` ownership, `business_name` is required.", + "$ref": "#/components/schemas/BankAccountOwnerType" + }, + "first_name": { + "type": "string", + "description": "First name of the individual account holder. Required when the `account_owner_type` is `individual`" + }, + "last_name": { + "type": "string", + "description": "Last name of the individual account holder. Required when the `account_owner_type` is `individual`" + }, + "business_name": { + "type": "string", + "description": "Business name of the business account holder. Required when the `account_owner_type` is `business`" + }, + "address": { + "description": "Address of the beneficiary of this account. Please ensure the address is valid (Google Maps is good for this). US addresses used to receive wires must include a street number.", + "$ref": "#/components/schemas/ExternalAccountAddress" + }, + "account_owner_country": { + "readOnly": true, + "type": "string", + "minLength": 3, + "maxLength": 3, + "description": "Three-letter alpha-3 country of residence of the account owner (ISO 3166-1)." + }, + "deactivation_reason": { + "readOnly": true, + "description": "Reason for deactivation when this External Account is inactive", + "$ref": "#/components/schemas/ExternalAccountDeactivationReason" + }, + "deactivation_details": { + "readOnly": true, + "type": "string", + "description": "Additional details about the deactivation when this External Account is inactive" + } + } + }, + "ExternalAccountDeactivationReason": { + "description": "Reason for deactivating an External Account", + "type": "string", + "enum": [ + "plaid_item_error", + "deactivated_due_to_bounceback", + "deleted_by_developer", + "requested_by_developer", + "invalid_account_number", + "invalid_bank_validation", + "rejected_by_bank_provider" + ] + }, + "ExternalAccountUs": { + "title": "ACH/Wire", + "description": "US bank account using account and routing numbers for ACH or Wire transfers", + "allOf": [ + { + "$ref": "#/components/schemas/ExternalAccountBaseWithOwnerInfo" + }, + { + "type": "object", + "required": [ + "account_type", + "account", + "currency", + "account_owner_name" + ], + "properties": { + "account_type": { + "type": "string", + "enum": [ + "us" + ], + "description": "Type of the bank account." + }, + "currency": { + "description": "Currency associated with the bank account. Must be `usd` for US accounts.", + "type": "string", + "enum": [ + "usd" + ] + }, + "account": { + "$ref": "#/components/schemas/UsBankAccount" + }, + "beneficiary_address_valid": { + "readOnly": true, + "type": "boolean", + "description": "Whether the beneficiary address is valid. A valid beneficiary address is required for all US External Accounts" + }, + "last_4": { + "description": "Last 4 digits of the bank account number. This field is getting deprecated in favor of the `account.last_4` field", + "type": "string", + "minLength": 1, + "readOnly": true, + "deprecated": true + }, + "account_number": { + "writeOnly": true, + "description": "Account number of your bank account. This field is getting deprecated in favor of the `account.account_number` field for US accounts.", + "type": "string", + "minLength": 12, + "deprecated": true + }, + "routing_number": { + "writeOnly": true, + "description": "Routing number of your bank account. This field is getting deprecated in favor of the `account.routing_number` field for US accounts.", + "type": "string", + "minLength": 9, + "deprecated": true + } + } + } + ] + }, + "ExternalAccountIban": { + "title": "IBAN", + "description": "IBAN bank account for European and international transfers (SEPA transfers use IBAN)", + "allOf": [ + { + "$ref": "#/components/schemas/ExternalAccountBaseWithOwnerInfo" + }, + { + "type": "object", + "required": [ + "account_type", + "currency", + "iban", + "account_owner_name" + ], + "properties": { + "account_type": { + "type": "string", + "enum": [ + "iban" + ], + "description": "Type of the bank account." + }, + "currency": { + "description": "Currency associated with the bank account. Must be `eur` for IBAN accounts.", + "type": "string", + "enum": [ + "eur" + ] + }, + "iban": { + "$ref": "#/components/schemas/IbanBankAccount" + }, + "account_verification": { + "readOnly": true, + "nullable": true, + "description": "Present for accounts with a holder verification check; contains the verification result.", + "$ref": "#/components/schemas/AccountVerificationIban" + } + } + } + ] + }, + "ExternalAccountClabe": { + "title": "CLABE", + "description": "Mexican CLABE account for SPEI transfers", + "allOf": [ + { + "$ref": "#/components/schemas/ExternalAccountBaseWithOwnerInfo" + }, + { + "type": "object", + "required": [ + "account_type", + "currency", + "clabe", + "account_owner_name" + ], + "properties": { + "account_type": { + "type": "string", + "enum": [ + "clabe" + ], + "description": "Type of the bank account." + }, + "currency": { + "description": "Currency associated with the bank account. Must be `mxn` for CLABE (SPEI) accounts.", + "type": "string", + "enum": [ + "mxn" + ] + }, + "clabe": { + "$ref": "#/components/schemas/ClabeBankAccount" + }, + "account_validation": { + "readOnly": true, + "nullable": true, + "description": "Present for CLABE accounts with a successful validation; contains validated owner and bank name.", + "$ref": "#/components/schemas/AccountValidation" + }, + "account_verification": { + "readOnly": true, + "nullable": true, + "description": "Present for accounts with a holder verification check; contains the verification result.", + "$ref": "#/components/schemas/AccountVerificationClabe" + } + } + } + ] + }, + "ExternalAccountPix": { + "title": "Pix", + "description": "Brazilian Pix instant payment system", + "allOf": [ + { + "$ref": "#/components/schemas/ExternalAccountBaseWithOwnerInfo" + }, + { + "type": "object", + "required": [ + "account_type", + "currency" + ], + "properties": { + "currency": { + "description": "Currency associated with the bank account. Must be `brl` for Pix accounts.", + "type": "string", + "enum": [ + "brl" + ] + }, + "account_type": { + "type": "string", + "enum": [ + "pix" + ], + "description": "Type of the bank account." + }, + "pix_key": { + "readOnly": true, + "description": "Pix key display info. Returned in GET responses when the account uses a Pix key.", + "$ref": "#/components/schemas/PixKeyBankAccount" + }, + "br_code": { + "readOnly": true, + "description": "BR Code display info. Returned in GET responses when the account uses a BR Code.", + "$ref": "#/components/schemas/BrCodeBankAccount" + }, + "account_validation": { + "readOnly": true, + "nullable": true, + "description": "Present for Pix accounts with a successful validation; contains validated owner and bank name.", + "$ref": "#/components/schemas/AccountValidation" + }, + "account_verification": { + "readOnly": true, + "nullable": true, + "description": "Present for accounts with a holder verification check; contains the verification result.", + "$ref": "#/components/schemas/AccountVerificationPix" + } + } + } + ] + }, + "ExternalAccountGb": { + "title": "GB", + "description": "UK bank account using account number and sort code for Faster Payments payment rail", + "allOf": [ + { + "$ref": "#/components/schemas/ExternalAccountBaseWithOwnerInfo" + }, + { + "type": "object", + "required": [ + "account_type", + "currency", + "account", + "account_owner_name" + ], + "properties": { + "account_type": { + "type": "string", + "enum": [ + "gb" + ], + "description": "Type of the bank account." + }, + "currency": { + "description": "Currency associated with the bank account. Must be `gbp` for GB accounts.", + "type": "string", + "enum": [ + "gbp" + ] + }, + "account": { + "$ref": "#/components/schemas/GbBankAccount" + }, + "account_verification": { + "readOnly": true, + "nullable": true, + "description": "Present for accounts with a holder verification check; contains the verification result.", + "$ref": "#/components/schemas/AccountVerificationGb" + } + } + } + ] + }, + "ExternalAccountBreB": { + "title": "Bre-B", + "description": "Colombian Bre-B account for COP transfers via the Bre-B payment rail. Requires `cop` endorsement. Virtual account numbers are not accepted.", + "allOf": [ + { + "$ref": "#/components/schemas/ExternalAccountBaseWithOwnerInfo" + }, + { + "type": "object", + "required": [ + "account_type", + "currency", + "account" + ], + "properties": { + "account_type": { + "type": "string", + "enum": [ + "bre_b" + ], + "description": "Type of the bank account." + }, + "currency": { + "description": "Currency associated with the bank account. Must be `cop` for Bre-B accounts.", + "type": "string", + "enum": [ + "cop" + ] + }, + "account": { + "$ref": "#/components/schemas/BreBBankAccount" + }, + "account_validation": { + "readOnly": true, + "nullable": true, + "description": "Present for Bre-B accounts with a successful validation; contains validated owner and bank name.", + "$ref": "#/components/schemas/AccountValidation" + }, + "account_verification": { + "readOnly": true, + "nullable": true, + "description": "Present for accounts with a holder verification check; contains the verification result.", + "$ref": "#/components/schemas/AccountVerificationBreB" + } + } + } + ] + }, + "ExternalAccountCoBankTransfer": { + "title": "CO Bank Transfer", + "description": "Colombian bank account for COP transfers via CO bank transfer.", + "allOf": [ + { + "$ref": "#/components/schemas/ExternalAccountBaseWithOwnerInfo" + }, + { + "type": "object", + "required": [ + "account_type", + "currency", + "account" + ], + "properties": { + "account_type": { + "type": "string", + "enum": [ + "co_bank_transfer" + ], + "description": "Type of the bank account." + }, + "currency": { + "description": "Currency associated with the bank account. Must be `cop` for CO bank transfer accounts.", + "type": "string", + "enum": [ + "cop" + ] + }, + "account": { + "description": "CO bank transfer account display information. Returned in GET responses.", + "type": "object", + "properties": { + "last_4": { + "description": "Last 4 digits of the account number", + "type": "string", + "readOnly": true + }, + "routing_number": { + "description": "The bank code of the account", + "type": "string", + "readOnly": true + } + } + }, + "account_verification": { + "readOnly": true, + "nullable": true, + "description": "Present for accounts with a holder verification check; contains the verification result.", + "$ref": "#/components/schemas/AccountVerificationCoBankTransfer" + } + } + } + ] + }, + "ExternalAccount": { + "oneOf": [ + { + "$ref": "#/components/schemas/ExternalAccountUs" + }, + { + "$ref": "#/components/schemas/ExternalAccountIban" + }, + { + "$ref": "#/components/schemas/ExternalAccountClabe" + }, + { + "$ref": "#/components/schemas/ExternalAccountPix" + }, + { + "$ref": "#/components/schemas/ExternalAccountGb" + }, + { + "$ref": "#/components/schemas/ExternalAccountBreB" + }, + { + "$ref": "#/components/schemas/ExternalAccountCoBankTransfer" + } + ] + }, + "AccountVerification": { + "description": "The current state of a holder verification check, keyed by account type.", + "nullable": true, + "oneOf": [ + { + "$ref": "#/components/schemas/AccountVerificationIban" + }, + { + "$ref": "#/components/schemas/AccountVerificationGb" + }, + { + "$ref": "#/components/schemas/AccountVerificationPix" + }, + { + "$ref": "#/components/schemas/AccountVerificationClabe" + }, + { + "$ref": "#/components/schemas/AccountVerificationBreB" + }, + { + "$ref": "#/components/schemas/AccountVerificationCoBankTransfer" + } + ] + }, + "AccountVerificationIban": { + "title": "IBAN", + "description": "Present when verifying an IBAN account.", + "type": "object", + "properties": { + "iban": { + "type": "object", + "properties": { + "match_level": { + "type": "string", + "enum": [ + "pending", + "match", + "close_match", + "no_match", + "error" + ], + "description": "The result of the name match check." + }, + "reason_code": { + "type": "string", + "nullable": true, + "description": "Additional context from the receiving bank when the result is not a full match." + }, + "validated_account_owner_name": { + "type": "string", + "nullable": true, + "description": "Account owner name as returned by the validation provider." + } + } + }, + "requested_at": { + "type": "string", + "format": "date-time", + "description": "When the verification was requested." + }, + "completed_at": { + "type": "string", + "format": "date-time", + "nullable": true, + "description": "When the verification completed. Null while pending." + } + } + }, + "AccountVerificationGb": { + "title": "GB", + "description": "Present when verifying a GB account.", + "type": "object", + "properties": { + "gb": { + "type": "object", + "properties": { + "match_level": { + "type": "string", + "enum": [ + "pending", + "match", + "close_match", + "no_match", + "error" + ], + "description": "The result of the name match check." + }, + "reason_code": { + "type": "string", + "nullable": true, + "description": "Additional context from the receiving bank when the result is not a full match." + }, + "validated_account_owner_name": { + "type": "string", + "nullable": true, + "description": "Account owner name as returned by the validation provider." + } + } + }, + "requested_at": { + "type": "string", + "format": "date-time", + "description": "When the verification was requested." + }, + "completed_at": { + "type": "string", + "format": "date-time", + "nullable": true, + "description": "When the verification completed. Null while pending." + } + } + }, + "AccountVerificationPix": { + "title": "Pix", + "description": "Present when verifying a Pix account.", + "type": "object", + "properties": { + "pix": { + "type": "object", + "properties": { + "matched": { + "type": "boolean", + "nullable": true, + "description": "Match result as returned by the validation provider." + }, + "reason_code": { + "type": "string", + "nullable": true, + "description": "Additional context from the validation provider." + }, + "validated_account_owner_name": { + "type": "string", + "nullable": true, + "description": "Account owner name as returned by the validation provider." + }, + "validated_bank_name": { + "type": "string", + "nullable": true, + "description": "Bank name as returned by the validation provider." + } + } + }, + "requested_at": { + "type": "string", + "format": "date-time", + "description": "When the verification was requested." + }, + "completed_at": { + "type": "string", + "format": "date-time", + "nullable": true, + "description": "When the verification completed. Null while pending." + } + } + }, + "AccountVerificationClabe": { + "title": "CLABE", + "description": "Present when verifying a CLABE account.", + "type": "object", + "properties": { + "clabe": { + "type": "object", + "properties": { + "matched": { + "type": "boolean", + "nullable": true, + "description": "Match result as returned by the validation provider." + }, + "reason_code": { + "type": "string", + "nullable": true, + "description": "Additional context from the validation provider." + }, + "validated_account_owner_name": { + "type": "string", + "nullable": true, + "description": "Account owner name as returned by the validation provider." + }, + "validated_bank_name": { + "type": "string", + "nullable": true, + "description": "Bank name as returned by the validation provider." + } + } + }, + "requested_at": { + "type": "string", + "format": "date-time", + "description": "When the verification was requested." + }, + "completed_at": { + "type": "string", + "format": "date-time", + "nullable": true, + "description": "When the verification completed. Null while pending." + } + } + }, + "AccountVerificationBreB": { + "title": "Bre-B", + "description": "Present when verifying a Bre-B account.", + "type": "object", + "properties": { + "bre_b": { + "type": "object", + "properties": { + "matched": { + "type": "boolean", + "nullable": true, + "description": "Match result as returned by the validation provider." + }, + "reason_code": { + "type": "string", + "nullable": true, + "description": "Additional context from the validation provider." + }, + "validated_account_owner_name": { + "type": "string", + "nullable": true, + "description": "Account owner name as returned by the validation provider." + }, + "validated_bank_name": { + "type": "string", + "nullable": true, + "description": "Bank name as returned by the validation provider." + }, + "validated_document_number_last4": { + "type": "string", + "nullable": true, + "readOnly": true, + "description": "Last 4 characters of the account owner's document number, as returned by the validation provider. Present only for Bre-B (Colombian) accounts." + } + } + }, + "requested_at": { + "type": "string", + "format": "date-time", + "description": "When the verification was requested." + }, + "completed_at": { + "type": "string", + "format": "date-time", + "nullable": true, + "description": "When the verification completed. Null while pending." + } + } + }, + "AccountVerificationCoBankTransfer": { + "title": "CO Bank Transfer", + "description": "Present when verifying a PSE account.", + "type": "object", + "properties": { + "co_bank_transfer": { + "type": "object", + "properties": { + "matched": { + "type": "boolean", + "nullable": true, + "description": "Match result as returned by the validation provider." + }, + "reason_code": { + "type": "string", + "nullable": true, + "description": "Additional context from the validation provider." + }, + "validated_account_owner_name": { + "type": "string", + "nullable": true, + "description": "Account owner name as returned by the validation provider." + }, + "validated_bank_name": { + "type": "string", + "nullable": true, + "description": "Bank name as returned by the validation provider." + }, + "validated_document_number_last4": { + "type": "string", + "nullable": true, + "readOnly": true, + "description": "Last 4 characters of the account owner's document number, as returned by the validation provider. Present only for Bre-B (Colombian) accounts." + } + } + }, + "requested_at": { + "type": "string", + "format": "date-time", + "description": "When the verification was requested." + }, + "completed_at": { + "type": "string", + "format": "date-time", + "nullable": true, + "description": "When the verification completed. Null while pending." + } + } + }, + "AccountValidation": { + "description": "Validated account owner and bank name from successful Infinia validation. Present only for Pix, SPEI/CLABE, and Bre-B accounts that have been successfully validated.", + "type": "object", + "properties": { + "validated_account_owner_name": { + "type": "string", + "nullable": true, + "description": "Account owner name as returned by the validation provider." + }, + "validated_bank_name": { + "type": "string", + "nullable": true, + "description": "Bank name as returned by the validation provider." + }, + "validated_document_number_last4": { + "type": "string", + "nullable": true, + "readOnly": true, + "description": "Last 4 characters of the account owner's document number, as returned by the validation provider. Present only for Bre-B (Colombian) accounts." + } + } + }, + "ExternalAccountResponse": { + "required": [ + "id", + "customer_id", + "created_at", + "updated_at", + "account_owner_name", + "currency", + "account_type", + "active" + ], + "allOf": [ + { + "$ref": "#/components/schemas/ExternalAccount" + } + ] + }, + "UpdateExternalAccountInput": { + "properties": { + "address": { + "writeOnly": true, + "description": "Address of the beneficiary of this account.", + "$ref": "#/components/schemas/Address" + }, + "account": { + "description": "US bank account information. Required when the `account_type` is `us`.", + "$ref": "#/components/schemas/UsBankAccountUpdate" + } + } + }, + "FeeExternalAccount": { + "required": [ + "id", + "customer_id", + "created_at", + "updated_at", + "account_owner_name", + "account_name", + "currency", + "account_type", + "active" + ], + "allOf": [ + { + "$ref": "#/components/schemas/ExternalAccountUs" + } + ] + }, + "ExternalAccountBaseWithoutOwnerInfo": { + "description": "Shared writable properties for creating an external account (without account owner info bundle)", + "properties": { + "id": { + "$ref": "#/components/schemas/Id", + "readOnly": true + }, + "customer_id": { + "description": "The id of the Bridge customer that this External Account belongs to", + "type": "string", + "minLength": 1, + "readOnly": true + }, + "bank_name": { + "description": "Bank name of the account", + "type": "string", + "minLength": 1, + "maxLength": 256 + }, + "account_owner_name": { + "description": "Owner of the bank account", + "type": "string", + "minLength": 1, + "maxLength": 256 + }, + "created_at": { + "readOnly": true, + "type": "string", + "description": "Time of creation of the External Account", + "format": "date-time" + }, + "updated_at": { + "readOnly": true, + "type": "string", + "description": "Time of last update of the External Account", + "format": "date-time" + }, + "active": { + "readOnly": true, + "type": "boolean", + "description": "Whether or not this External Account is active" + }, + "address": { + "writeOnly": true, + "description": "Address of the beneficiary of this account.", + "$ref": "#/components/schemas/ExternalAccountAddress" + }, + "deactivation_reason": { + "readOnly": true, + "description": "Reason for deactivation when this External Account is inactive", + "$ref": "#/components/schemas/ExternalAccountDeactivationReason" + }, + "deactivation_details": { + "readOnly": true, + "type": "string", + "description": "Additional details about the deactivation when this External Account is inactive" + } + } + }, + "CreateExternalAccountPixKeyInput": { + "title": "Pix (Pix Key)", + "description": "Brazilian Pix instant payment system using a Pix key", + "allOf": [ + { + "$ref": "#/components/schemas/ExternalAccountBaseWithoutOwnerInfo" + }, + { + "type": "object", + "required": [ + "account_type", + "currency", + "pix_key", + "account_owner_name" + ], + "properties": { + "currency": { + "description": "Currency associated with the bank account. Must be `brl` for Pix accounts.", + "type": "string", + "enum": [ + "brl" + ] + }, + "account_type": { + "type": "string", + "enum": [ + "pix" + ], + "description": "Type of the bank account." + }, + "pix_key": { + "writeOnly": true, + "description": "Brazilian Pix key bank account information. Required when account type is `pix` and using a Pix key.", + "$ref": "#/components/schemas/PixKeyBankAccount" + } + } + } + ] + }, + "CreateExternalAccountBrCodeInput": { + "title": "Pix (BR Code)", + "description": "Brazilian Pix instant payment system using a BR Code (Copie e cola)", + "allOf": [ + { + "$ref": "#/components/schemas/ExternalAccountBaseWithoutOwnerInfo" + }, + { + "type": "object", + "required": [ + "account_type", + "currency", + "br_code", + "account_owner_name" + ], + "properties": { + "currency": { + "description": "Currency associated with the bank account. Must be `brl` for Pix accounts.", + "type": "string", + "enum": [ + "brl" + ] + }, + "account_type": { + "type": "string", + "enum": [ + "pix" + ], + "description": "Type of the bank account." + }, + "br_code": { + "writeOnly": true, + "description": "Brazilian BR Code (Copie e cola) bank account information. Required when account type is `pix` and using a BR Code.", + "$ref": "#/components/schemas/BrCodeBankAccount" + } + } + } + ] + }, + "CreateExternalAccountIbanInput": { + "title": "IBAN", + "description": "IBAN bank account for European and international transfers (SEPA transfers use IBAN)", + "allOf": [ + { + "$ref": "#/components/schemas/ExternalAccountBaseWithOwnerInfo" + }, + { + "type": "object", + "required": [ + "account_type", + "currency", + "iban", + "account_owner_name" + ], + "properties": { + "account_type": { + "type": "string", + "enum": [ + "iban" + ], + "description": "Type of the bank account." + }, + "currency": { + "description": "Currency associated with the bank account. Must be `eur` for IBAN accounts.", + "type": "string", + "enum": [ + "eur" + ] + }, + "iban": { + "$ref": "#/components/schemas/IbanBankAccount" + } + } + } + ] + }, + "CreateExternalAccountFPSInput": { + "title": "FPS", + "description": "UK bank account information for the Faster Payments payment rail", + "allOf": [ + { + "$ref": "#/components/schemas/ExternalAccountBaseWithOwnerInfo" + }, + { + "type": "object", + "required": [ + "account_type", + "currency", + "account", + "account_owner_name" + ], + "properties": { + "account_type": { + "type": "string", + "enum": [ + "gb" + ], + "description": "Type of the bank account." + }, + "currency": { + "description": "Currency associated with the bank account. Must be `gbp` for GB accounts.", + "type": "string", + "enum": [ + "gbp" + ] + }, + "account": { + "$ref": "#/components/schemas/GbBankAccount" + } + } + } + ] + }, + "CreateExternalAccountBreBInput": { + "title": "Bre-B", + "description": "Colombian Bre-B account for COP transfers. Requires `cop` endorsement. Virtual account numbers are not accepted as Bre-B keys.\n", + "allOf": [ + { + "$ref": "#/components/schemas/ExternalAccountBaseWithoutOwnerInfo" + }, + { + "type": "object", + "required": [ + "account_type", + "currency", + "account", + "account_owner_name" + ], + "properties": { + "currency": { + "description": "Currency associated with the bank account. Must be `cop` for Bre-B accounts.", + "type": "string", + "enum": [ + "cop" + ] + }, + "account_type": { + "type": "string", + "enum": [ + "bre_b" + ], + "description": "Type of the bank account." + }, + "account": { + "writeOnly": true, + "description": "Colombian Bre-B bank account information. Required when account type is `bre_b`.", + "$ref": "#/components/schemas/BreBBankAccount" + } + } + } + ] + }, + "CreateExternalAccountCoBankTransferInput": { + "title": "CO Bank Transfer", + "description": "Colombian bank account for COP transfers via CO bank transfer. Requires `cop` endorsement and account owner information (individual or business).\n", + "allOf": [ + { + "$ref": "#/components/schemas/ExternalAccountBaseWithOwnerInfo" + }, + { + "type": "object", + "required": [ + "account_type", + "currency", + "account", + "account_owner_name" + ], + "properties": { + "currency": { + "description": "Currency associated with the bank account. Must be `cop` for CO bank transfer accounts.", + "type": "string", + "enum": [ + "cop" + ] + }, + "account_type": { + "type": "string", + "enum": [ + "co_bank_transfer" + ], + "description": "Type of the bank account." + }, + "account": { + "writeOnly": true, + "description": "Colombian CO bank account information. Required when account type is co_bank_transfer.", + "$ref": "#/components/schemas/CoBankTransferBankAccount" + } + } + } + ] + }, + "CreateExternalAccountUsInput": { + "title": "ACH/Wire", + "description": "US bank account using account and routing numbers for ACH or Wire transfers", + "allOf": [ + { + "$ref": "#/components/schemas/ExternalAccountBaseWithoutOwnerInfo" + }, + { + "type": "object", + "required": [ + "account_type", + "account", + "currency", + "account_owner_name", + "address" + ], + "properties": { + "account_type": { + "type": "string", + "enum": [ + "us" + ], + "description": "Type of the bank account." + }, + "currency": { + "description": "Currency associated with the bank account. Must be `usd` for US accounts.", + "type": "string", + "enum": [ + "usd" + ] + }, + "account": { + "$ref": "#/components/schemas/UsBankAccount" + }, + "account_number": { + "writeOnly": true, + "description": "Account number of your bank account. This field is getting deprecated in favor of the `account.account_number` field for US accounts.", + "type": "string", + "minLength": 12, + "deprecated": true + }, + "routing_number": { + "writeOnly": true, + "description": "Routing number of your bank account. This field is getting deprecated in favor of the `account.routing_number` field for US accounts.", + "type": "string", + "minLength": 9, + "deprecated": true + } + } + } + ] + }, + "CreateExternalAccountClabeInput": { + "title": "CLABE", + "description": "Mexican CLABE account for SPEI transfers", + "allOf": [ + { + "$ref": "#/components/schemas/ExternalAccountBaseWithoutOwnerInfo" + }, + { + "type": "object", + "required": [ + "account_type", + "currency", + "clabe", + "account_owner_name" + ], + "properties": { + "account_type": { + "type": "string", + "enum": [ + "clabe" + ], + "description": "Type of the bank account." + }, + "currency": { + "description": "Currency associated with the bank account. Must be `mxn` for CLABE (SPEI) accounts.", + "type": "string", + "enum": [ + "mxn" + ] + }, + "clabe": { + "$ref": "#/components/schemas/ClabeBankAccount" + } + } + } + ] + }, + "CreateExternalAccountInput": { + "description": "Request body for creating an external account.", + "oneOf": [ + { + "$ref": "#/components/schemas/CreateExternalAccountUsInput" + }, + { + "$ref": "#/components/schemas/CreateExternalAccountIbanInput" + }, + { + "$ref": "#/components/schemas/CreateExternalAccountClabeInput" + }, + { + "$ref": "#/components/schemas/CreateExternalAccountPixKeyInput" + }, + { + "$ref": "#/components/schemas/CreateExternalAccountBrCodeInput" + }, + { + "$ref": "#/components/schemas/CreateExternalAccountFPSInput" + }, + { + "$ref": "#/components/schemas/CreateExternalAccountBreBInput" + }, + { + "$ref": "#/components/schemas/CreateExternalAccountCoBankTransferInput" + } + ] + }, + "CreateFeeExternalAccountInput": { + "description": "Request body for creating a fee external account. Fee external accounts must use USD currency.", + "allOf": [ + { + "$ref": "#/components/schemas/ExternalAccountUs" + } + ] + }, + "LiquidationAddress": { + "required": [ + "id", + "currency", + "chain", + "external_account_id", + "address", + "destination_payment_rail", + "destination_currency", + "customer_id", + "created_at", + "updated_at" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/Id", + "readOnly": true + }, + "currency": { + "$ref": "#/components/schemas/LiquidationAddressSourceCurrency" + }, + "chain": { + "$ref": "#/components/schemas/LiquidationAddressSourceChain" + }, + "supported_currencies": { + "description": "The currencies this Liquidation Address accepts on each chain. Keys are `LiquidationAddressSourceChain` values (e.g. `ethereum`, `polygon`, `base`). For a single-chain, single-currency address this is just that one chain and currency; for a multi-chain (`chain` is `evm`) or multi-currency (`currency` is `all_supported`) address it lists every currency actually accepted on each chain.\n", + "type": "object", + "readOnly": true, + "additionalProperties": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CryptoCurrency" + } + }, + "example": { + "ethereum": [ + "usdc", + "eurc" + ], + "polygon": [ + "usdc" + ] + } + }, + "customer_id": { + "description": "The ID of the customer who owns this liquidation address", + "$ref": "#/components/schemas/Id" + }, + "external_account_id": { + "description": "External bank account to which Bridge will send the funds. The currency associated with the External Account must match the destination currency.", + "$ref": "#/components/schemas/Id" + }, + "prefunded_account_id": { + "description": "The developer's prefunded account to which Bridge will send the funds.", + "$ref": "#/components/schemas/Id" + }, + "custom_developer_fee_percent": { + "$ref": "#/components/schemas/LiquidationAddressCustomDeveloperFeePercent" + }, + "global_developer_fee_percent": { + "$ref": "#/components/schemas/LiquidationAddressGlobalDeveloperFeePercent" + }, + "destination_wire_message": { + "description": "A message to be sent with a wire transfer.", + "$ref": "#/components/schemas/WireMessage" + }, + "destination_sepa_reference": { + "$ref": "#/components/schemas/SepaReference" + }, + "destination_spei_reference": { + "$ref": "#/components/schemas/SpeiReference" + }, + "destination_ach_reference": { + "$ref": "#/components/schemas/AchReference" + }, + "destination_swift_reference": { + "$ref": "#/components/schemas/SwiftReference" + }, + "destination_payment_rail": { + "description": "The payment rail that Bridge will use to send funds to the customer.", + "$ref": "#/components/schemas/SepaSwiftInclusivePaymentRail" + }, + "destination_currency": { + "description": "The currency that Bridge will use to send funds to the customer.", + "$ref": "#/components/schemas/EuroInclusiveCurrency" + }, + "address": { + "description": "The crypto wallet address the customer will send funds to in order to initiate the payment processing", + "type": "string", + "readOnly": true + }, + "memoless_address": { + "description": "An alternative crypto wallet address that encodes the memo, allowing the customer to send funds without needing to include a separate memo. Currently only available for Stellar deposits.", + "type": "string", + "readOnly": true + }, + "blockchain_memo": { + "description": "The memo that must be included with the deposit transaction when sending funds to the deposit address. Only present for blockchains that require memos (such as Stellar).", + "type": "string", + "readOnly": true + }, + "destination_address": { + "type": "string", + "description": "The crypto wallet address that Bridge will use to send funds to the customer." + }, + "destination_blockchain_memo": { + "type": "string", + "description": "The memo to include in the transaction, for blockchains that support memos only" + }, + "return_address": { + "type": "string", + "nullable": true, + "deprecated": true, + "description": "Deprecated: use `return_instructions` instead.\n\nThe crypto wallet address that Bridge will use to return funds to the customer in case of a failed transaction.\nMust be on the same chain as the liquidation address.\nCannot be used on Stellar — use `return_instructions` with a `memo` instead.\n" + }, + "return_memo": { + "type": "string", + "nullable": true, + "description": "The memo included with return transactions. Present when `return_instructions` was set with a memo (e.g. required for Stellar to route funds to the correct end-customer)." + }, + "state": { + "type": "string", + "description": "The state of the liquidation address. It could be \"active\" or \"deactivated\"" + }, + "created_at": { + "readOnly": true, + "type": "string", + "description": "Time of creation of the Liquidation Address", + "format": "date-time" + }, + "updated_at": { + "readOnly": true, + "type": "string", + "description": "Time of last update of the Liquidation Address", + "format": "date-time" + } + } + }, + "CreateKycLinks": { + "required": [ + "email", + "type" + ], + "properties": { + "full_name": { + "description": "Full name of the customer, for a business, this would be the business entity's legal name", + "type": "string", + "minLength": 1 + }, + "email": { + "description": "Email of the customer", + "type": "string", + "minLength": 1 + }, + "type": { + "description": "Type of the customer (individual vs. business)", + "type": "string", + "minLength": 1, + "enum": [ + "individual", + "business" + ] + }, + "endorsements": { + "description": "List of endorsements to request for the generated KYC link.\nFor example, `sepa` endorsement could be requested to allow an `individual` customer to submit `proof-of-address` documents in the KYC flow.", + "type": "array", + "minItems": 0, + "items": { + "$ref": "#/components/schemas/EndorsementType" + } + }, + "redirect_uri": { + "description": "The location where the customer should be redirected after completing the KYC flow. Must be in the form of http:// or https://.", + "type": "string" + }, + "transliterated_first_name": { + "type": "string", + "description": "Required when the `full_name` of an individual includes any non Latin-1 characters. Acceptable characters - Latin-1 Unicode Character Range: À-ÖØ-ßà-öø-ÿ; Standard Unicode Character Range: -~", + "minLength": 1, + "maxLength": 256 + }, + "transliterated_middle_name": { + "type": "string", + "description": "Required when the `full_name` of an individual includes any non Latin-1 characters and the individual has a middle name. Acceptable characters - Latin-1 Unicode Character Range: À-ÖØ-ßà-öø-ÿ; Standard Unicode Character Range: -~", + "minLength": 1, + "maxLength": 256 + }, + "transliterated_last_name": { + "type": "string", + "description": "Required when the `full_name` of an individual includes any non Latin-1 characters. Acceptable characters - Latin-1 Unicode Character Range: À-ÖØ-ßà-öø-ÿ; Standard Unicode Character Range: -~", + "minLength": 1, + "maxLength": 256 + }, + "transliterated_business_legal_name": { + "type": "string", + "description": "Required if the `full_name` of a business includes any non Latin-1 characters. Acceptable characters - Latin-1 Unicode Character Range: À-ÖØ-ßà-öø-ÿ; Standard Unicode Character Range: -~", + "minLength": 1, + "maxLength": 1024 + } + } + }, + "CreateStaticMemo": { + "required": [ + "source", + "destination" + ], + "properties": { + "developer_fee_percent": { + "$ref": "#/components/schemas/StaticMemoDeveloperFeePercent" + }, + "source": { + "$ref": "#/components/schemas/StaticMemoSourceInput" + }, + "destination": { + "$ref": "#/components/schemas/StaticMemoDestination" + } + } + }, + "UpdateStaticMemo": { + "properties": { + "destination": { + "$ref": "#/components/schemas/UpdateStaticMemoDestination" + }, + "developer_fee_percent": { + "$ref": "#/components/schemas/StaticMemoDeveloperFeePercent" + } + } + }, + "UpdateStaticMemoDestination": { + "properties": { + "currency": { + "$ref": "#/components/schemas/CryptoCurrency" + }, + "payment_rail": { + "$ref": "#/components/schemas/OfframpChain" + }, + "address": { + "description": "The crypto wallet address that the customer wishes to ultimately receive funds at", + "type": "string" + } + }, + "example": { + "currency": "usdc", + "payment_rail": "polygon", + "address": "0xdeadbeef" + } + }, + "StaticMemoDeveloperFeePercent": { + "description": "The developer fee percent that will be applied to this Virtual Account. The value is a base 100 percentage, i.e. 10.2% is 10.2 in the API.", + "type": "string", + "format": "number", + "minimum": 0, + "maximum": 100, + "exclusiveMaximum": true, + "example": "0.1" + }, + "StaticMemoSourceInput": { + "required": [ + "currency" + ], + "properties": { + "currency": { + "$ref": "#/components/schemas/FiatCurrency" + }, + "payment_rail": { + "description": "Static memos support both wire and ACH push regardless of this value.", + "$ref": "#/components/schemas/PaymentRail" + } + }, + "example": { + "currency": "usd", + "payment_rail": "wire" + } + }, + "StaticMemoDestination": { + "required": [ + "currency", + "payment_rail", + "address" + ], + "properties": { + "currency": { + "$ref": "#/components/schemas/CryptoCurrency" + }, + "payment_rail": { + "$ref": "#/components/schemas/OfframpChain" + }, + "address": { + "description": "The crypto wallet address that the customer wishes to ultimately receive funds at", + "type": "string" + }, + "bridge_wallet_id": { + "description": "The Bridge Wallet to which Bridge will send the funds. payment_rail must match the chain of the Bridge Wallet.", + "$ref": "#/components/schemas/Id" + }, + "blockchain_memo": { + "type": "string", + "description": "The memo to include when sending funds on chain. Only allowed for blockchains that support memos such as Stellar" + } + }, + "example": { + "currency": "usdc", + "payment_rail": "polygon", + "address": "0xdeadbeef" + } + }, + "StaticMemoResponse": { + "properties": { + "id": { + "$ref": "#/components/schemas/Id", + "readOnly": true + }, + "developer_fee_percent": { + "$ref": "#/components/schemas/StaticMemoDeveloperFeePercent" + }, + "source_deposit_instructions": { + "$ref": "#/components/schemas/StaticMemoSourceDepositInstructions" + }, + "destination": { + "$ref": "#/components/schemas/StaticMemoDestination" + }, + "created_at": { + "readOnly": true, + "type": "string", + "description": "Time of creation of the static memo", + "format": "date-time" + } + } + }, + "StaticMemoSourceDepositInstructions": { + "readOnly": true, + "properties": { + "currency": { + "$ref": "#/components/schemas/FiatCurrency" + }, + "payment_rails": { + "description": "All supported payment rails for deposits", + "type": "array", + "items": { + "$ref": "#/components/schemas/PaymentRail" + } + }, + "deposit_message": { + "description": "The message that the customer MUST include in their wire memo/message or ACH description.", + "type": "string" + }, + "bank_name": { + "description": "The name of the bank that the customer should send the deposit to", + "type": "string" + }, + "bank_address": { + "description": "The address of the bank that the customer should send the deposit to", + "type": "string" + }, + "bank_routing_number": { + "description": "The routing number of the bank that the customer should send the deposit to", + "type": "string" + }, + "bank_account_number": { + "description": "The account number of the bank that the customer should send the deposit to", + "type": "string" + }, + "bank_beneficiary_name": { + "description": "The name of the beneficiary of the bank account that the customer should send the deposit to", + "type": "string" + }, + "bank_beneficiary_address": { + "description": "The address of the beneficiary of the bank account that the customer should send the deposit to", + "type": "string" + } + }, + "example": { + "currency": "usd", + "payment_rails": [ + "ach_push", + "wire" + ], + "deposit_message": "EXAMPLE_MEMO_MESSAGE", + "bank_name": "Lead Bank", + "bank_address": "1801 Main St., Kansas City, MO 64108", + "bank_beneficiary_name": "Bridge Ventures Inc", + "bank_beneficiary_address": "21750 Hardy Oak Blvd, Ste 104 PMB 77950, San Antonio, Texas, 78258-4946", + "bank_account_number": "123456789", + "bank_routing_number": "87654321" + } + }, + "VirtualAccountEvent": { + "required": [ + "id" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/Id", + "readOnly": true + }, + "type": { + "type": "string", + "description": "The type of activity", + "enum": [ + "funds_scheduled", + "funds_received", + "payment_submitted", + "payment_processed", + "in_review", + "refund", + "refund_in_flight", + "refund_failed", + "microdeposit", + "account_update", + "deactivation", + "activation" + ] + }, + "customer_id": { + "$ref": "#/components/schemas/Id", + "description": "The id of the Bridge customer that this Virtual Account event belongs to", + "type": "string", + "minLength": 1, + "readOnly": true + }, + "virtual_account_id": { + "$ref": "#/components/schemas/Id", + "description": "The id of the Virtual Account that this Virtual Account event belongs to", + "type": "string", + "minLength": 1, + "readOnly": true + }, + "amount": { + "type": "string", + "description": "Amount for that event, represented as a dollar denominated string. Examples include \"100.25\", \"0.1\", \"1.234567\" etc. For \"incoming\" events such as funds_received or under_review, this is the initial amount received. For \"outgoing\" events such as payment_submitted and payment_processed, this is the amount of funds sent to the destination. For non-transactional events such as account_update, this will be zero." + }, + "currency": { + "$ref": "#/components/schemas/Currency" + }, + "developer_fee_amount": { + "type": "string", + "description": "Amount of the developer fee if any, represented as a dollar denominated string. This is the final amount taken out of what is ultimately received by your customer, not a percentage. Examples include \"100.25\", \"0.1\", \"1.234567\" etc." + }, + "exchange_fee_amount": { + "type": "string", + "description": "Amount of the exchange fee if any, represented as a dollar denominated string. Examples include \"100.25\", \"0.1\", \"1.234567\" etc." + }, + "subtotal_amount": { + "type": "string", + "description": "Amount of the subtotal, represented as a dollar denominated string. Examples include \"100.25\", \"0.1\", \"1.234567\" etc." + }, + "gas_fee": { + "type": "string", + "description": "Amount of the gas fee if any, represented as a dollar denominated string. Examples include \"100.25\", \"0.1\", \"1.234567\" etc." + }, + "deposit_id": { + "type": "string", + "description": "The id of the deposit related to this event. This id can be used to link multiple events to the same transaction. Omitted for some `refund` cases." + }, + "destination_tx_hash": { + "type": "string", + "description": "The hash of the on-chain transfer to the destination address" + }, + "destination_payment_rail": { + "type": "string", + "description": "The destination payment rail where the funds are deposited to" + }, + "source": { + "$ref": "#/components/schemas/VirtualAccountEventSource" + }, + "created_at": { + "readOnly": true, + "type": "string", + "description": "Time of creation of the event", + "format": "date-time" + }, + "receipt": { + "readOnly": true, + "description": "Receipt information of a virtual account event. Available for drain and payment_processed events.", + "$ref": "#/components/schemas/Receipt" + }, + "refund": { + "readOnly": true, + "description": "Refund information of a virtual account event. Available for refund events.", + "$ref": "#/components/schemas/VirtualAccountRefundDetails" + } + } + }, + "VirtualAccountEventSource": { + "required": [ + "payment_rail" + ], + "properties": { + "payment_rail": { + "$ref": "#/components/schemas/VirtualAccountEventPaymentRails" + }, + "description": { + "description": "(ACH, SPEI, and FedNow only) The description of the deposit that the customer sent", + "type": "string", + "readOnly": true + }, + "sender_name": { + "description": "(ACH, SEPA, SPEI, and FedNow only) The name of the business or individual who initiated the transaction", + "type": "string", + "readOnly": true + }, + "sender_bank_routing_number": { + "description": "(ACH and FedNow only) The routing number of the entity that initiated this transaction", + "type": "string", + "readOnly": true + }, + "end_to_end_id": { + "$ref": "#/components/schemas/EndToEndId", + "readOnly": true + }, + "trace_number": { + "description": "(ACH only) The unique, a 15-digit number associated with each ACH transaction that is used for tracking and reconciling transactions", + "type": "string", + "readOnly": true + }, + "recipient_name": { + "description": "(ACH, SEPA, and Faster Payments only) The name of the recipient of the deposit", + "type": "string", + "readOnly": true + }, + "bank_routing_number": { + "description": "(Wire only) The routing number of the bank that sent the wire to the Virtual Account", + "type": "string", + "readOnly": true + }, + "bank_name": { + "description": "(Wire and SPEI only) The name of the bank that sent the deposit.", + "type": "string", + "readOnly": true + }, + "bank_code": { + "description": "(SPEI only) The bank code of the sender's bank that initiated this SPEI transaction.", + "type": "string", + "readOnly": true + }, + "bank_beneficiary_name": { + "description": "(Wire only) The beneficiary name of this wire", + "type": "string", + "readOnly": true + }, + "bank_beneficiary_address": { + "description": "(Wire only) The beneficiary address of this wire", + "type": "string", + "readOnly": true + }, + "originator_name": { + "description": "(Wire only) The originator name of this wire", + "type": "string", + "readOnly": true + }, + "originator_address": { + "description": "(Wire only) The originator address of this wire", + "type": "string", + "readOnly": true + }, + "wire_message": { + "description": "(Wire only) The memo for this wire", + "type": "string", + "readOnly": true + }, + "imad": { + "$ref": "#/components/schemas/Imad", + "readOnly": true + }, + "charge_bearer": { + "description": "(Wire only) Which party bore the SWIFT wire's charges", + "$ref": "#/components/schemas/ChargeBearer", + "readOnly": true + }, + "bic": { + "description": "(SEPA and Wire only) The BIC of the bank that initiated this transaction. For wires this is the originating bank's BIC, reported for international (SWIFT) wires, and can differ from the US correspondent bank in bank_name and bank_routing_number", + "type": "string", + "readOnly": true + }, + "iban": { + "description": "(SEPA only) The full IBAN of the account that initiated this transaction", + "type": "string", + "readOnly": true + }, + "iban_last_4": { + "description": "(SEPA only) The last 4 digits of the IBAN of the account that initiated this transaction", + "type": "string", + "readOnly": true + }, + "clabe": { + "description": "(SPEI only) The CLABE (account number) of the account that initiated this transaction", + "type": "string", + "readOnly": true + }, + "reference": { + "$ref": "#/components/schemas/SepaReference", + "description": "(SEPA and SPEI only) The SEPA/SPEI (concepto de pago) reference field set by the initiator of this transaction", + "readOnly": true + }, + "tracking_number": { + "description": "(SPEI only) The clave de rastreo or tracking number of the SPEI transaction", + "type": "string", + "readOnly": true + }, + "payment_scheme": { + "$ref": "#/components/schemas/PaymentScheme", + "description": "(SEPA only) The payment scheme used for this transaction, such as SEPA Credit Transfer or SEPA Instant" + }, + "uetr": { + "$ref": "#/components/schemas/Uetr" + } + } + }, + "VirtualAccountRefundDetails": { + "required": [ + "code", + "reason", + "refunded_at" + ], + "properties": { + "code": { + "type": "string", + "description": "The code of the refund" + }, + "reason": { + "type": "string", + "description": "The reason of the refund" + }, + "refunded_at": { + "type": "string", + "description": "The time of the refund" + }, + "risk_rejection_reason": { + "type": "string", + "description": "If the return is due to a risk rejection, this field will be populated with the reason for the risk rejection." + } + } + }, + "CreateVirtualAccount": { + "required": [ + "source", + "destination" + ], + "properties": { + "developer_fee_percent": { + "$ref": "#/components/schemas/VirtualAccountDeveloperFeePercent" + }, + "fee_config": { + "description": "Developer fee configuration. Available by request only. Contact Bridge to enable this feature for your developer account. Cannot be provided alongside `developer_fee_percent` in the same request.", + "allOf": [ + { + "$ref": "#/components/schemas/FeeConfigRequest" + } + ] + }, + "source": { + "$ref": "#/components/schemas/VirtualAccountSourceInput" + }, + "destination": { + "$ref": "#/components/schemas/VirtualAccountDestination" + }, + "travel_rule_data": { + "description": "Travel Rule data for this virtual account. Use this only when the same originator or beneficiary should apply to every future movement through this virtual account. If counterparties can vary by event, submit the payload later with `POST /travel_rule_data/{id}` for the relevant event or resource.", + "allOf": [ + { + "$ref": "#/components/schemas/TravelRuleData" + } + ] + } + } + }, + "UpdateVirtualAccount": { + "properties": { + "destination": { + "$ref": "#/components/schemas/UpdateVirtualAccountDestination" + }, + "developer_fee_percent": { + "$ref": "#/components/schemas/VirtualAccountDeveloperFeePercent" + }, + "fee_config": { + "description": "Developer fee configuration. Available by request only. Contact Bridge to enable this feature for your developer account. When provided, performs a full replacement of the existing fee configuration. If the virtual account was previously configured with `developer_fee_percent`, providing `fee_config` will clear `developer_fee_percent` and replace it with the new configuration. Include the desired fee under `source` (e.g. `fee_config.source.fee_percent`). Cannot be provided alongside `developer_fee_percent` in the same request.", + "allOf": [ + { + "$ref": "#/components/schemas/FeeConfigRequest" + } + ] + } + } + }, + "UpdateVirtualAccountDestination": { + "properties": { + "currency": { + "$ref": "#/components/schemas/CryptoCurrency" + }, + "payment_rail": { + "$ref": "#/components/schemas/OfframpChain" + }, + "address": { + "description": "The crypto wallet address that the customer wishes to ultimately receive funds at", + "type": "string" + }, + "blockchain_memo": { + "type": "string", + "description": "The memo to include when sending funds on chain. Only allowed for blockchains that support memos such as Stellar" + }, + "bridge_wallet_id": { + "description": "The Bridge Wallet to which Bridge will send the funds. The chain associated with the Bridge Wallet must match the payment rail.", + "$ref": "#/components/schemas/Id" + } + }, + "example": { + "currency": "usdc", + "payment_rail": "polygon", + "address": "0xdeadbeef", + "blockchain_memo": "from_bridge" + } + }, + "VirtualAccountDeveloperFeePercent": { + "description": "The developer fee percent that will be applied to this Virtual Account. The value is a base 100 percentage, i.e. 10.2% is 10.2 in the API.", + "type": "string", + "format": "number", + "minimum": 0, + "maximum": 100, + "exclusiveMaximum": true, + "example": "0.1" + }, + "FeeConfigFeeParams": { + "description": "Fee parameters for a specific payment rail or default configuration", + "type": "object", + "properties": { + "fee_percent": { + "description": "Percentage fee (0-100, exclusive). Applied to the amount remaining after any flat fee deduction.", + "type": "string", + "format": "number", + "example": "1.5" + }, + "fee_amount": { + "description": "Flat fee amount deducted before percentage calculation", + "type": "string", + "format": "number", + "example": "10.00" + }, + "minimum_fee": { + "description": "Minimum total fee floor", + "type": "string", + "format": "number", + "example": "1.00" + }, + "maximum_fee": { + "description": "Maximum total fee cap", + "type": "string", + "format": "number", + "example": "1000.00" + } + } + }, + "FeeConfigRequest": { + "description": "Developer fee configuration. Available by request only. Contact Bridge to enable this feature for your developer account. The `source` object supports direct fee parameters as a shorthand for a default fee, an explicit `default` key, payment-rail keys (e.g. `ach_push`, `wire`), or a mixed default-plus-override form.", + "type": "object", + "properties": { + "source": { + "description": "Source-side fee configuration. Supports direct fee params under `source`, an explicit `default` key, payment-rail keys such as `ach_push` and `wire`, or a mixed default-plus-override form.", + "anyOf": [ + { + "$ref": "#/components/schemas/FeeConfigFeeParams" + }, + { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/FeeConfigFeeParams" + } + } + ], + "example": { + "fee_percent": "0.5", + "minimum_fee": "1.00", + "wire": { + "fee_amount": "10.00", + "fee_percent": "1.0" + } + } + } + } + }, + "FeeConfigResponse": { + "description": "Developer fee configuration. Available by request only. Contact Bridge to enable this feature for your developer account. Responses render source-side fees keyed by payment rail, using `default` for a catch-all configuration.", + "type": "object", + "properties": { + "source": { + "description": "Source-side fee configuration keyed by payment rail or `default`", + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/FeeConfigFeeParams" + }, + "example": { + "default": { + "fee_percent": "0.5", + "minimum_fee": "1.00" + }, + "wire": { + "fee_amount": "10.00", + "fee_percent": "1.0" + } + } + } + } + }, + "VirtualAccountActivationStatus": { + "description": "The activation status of the Virtual Account", + "type": "string", + "enum": [ + "activated", + "deactivated" + ] + }, + "VirtualAccountSourceInput": { + "required": [ + "currency" + ], + "properties": { + "currency": { + "$ref": "#/components/schemas/EuroInclusiveFiatCurrency" + } + }, + "example": { + "currency": "usd" + } + }, + "VirtualAccountDestination": { + "required": [ + "currency", + "payment_rail" + ], + "properties": { + "currency": { + "$ref": "#/components/schemas/CryptoCurrency" + }, + "payment_rail": { + "$ref": "#/components/schemas/OfframpChain" + }, + "address": { + "description": "The crypto wallet address that the customer wishes to ultimately receive funds at", + "type": "string" + }, + "blockchain_memo": { + "type": "string", + "description": "The memo to include when sending funds on chain. Only allowed for blockchains that support memos such as Stellar" + }, + "bridge_wallet_id": { + "description": "The Bridge Wallet to which Bridge will send the funds. The chain associated with the Bridge Wallet must match the payment rail.", + "$ref": "#/components/schemas/Id" + }, + "prefunded_account_id": { + "description": "The id of the prefunded account to which the funds will be sent. Use 'prefunded' as the payment rail and 'usd' as the currency when specifying a prefunded account id.", + "$ref": "#/components/schemas/Id" + } + }, + "example": { + "currency": "usdc", + "payment_rail": "polygon", + "address": "0xdeadbeef" + } + }, + "VirtualAccountResponse": { + "properties": { + "id": { + "$ref": "#/components/schemas/Id", + "readOnly": true + }, + "status": { + "$ref": "#/components/schemas/VirtualAccountActivationStatus" + }, + "developer_fee_percent": { + "$ref": "#/components/schemas/VirtualAccountDeveloperFeePercent" + }, + "fee_config": { + "description": "Developer fee configuration. Available by request only and returned only for developers with this feature enabled.", + "allOf": [ + { + "$ref": "#/components/schemas/FeeConfigResponse" + } + ] + }, + "customer_id": { + "$ref": "#/components/schemas/Id" + }, + "created_at": { + "readOnly": true, + "type": "string", + "description": "Time of creation of the virtual account", + "format": "date-time" + }, + "source_deposit_instructions": { + "$ref": "#/components/schemas/VirtualAccountSourceDepositInstructions" + }, + "destination": { + "$ref": "#/components/schemas/VirtualAccountDestination" + } + } + }, + "VirtualAccountSourceDepositInstructions": { + "title": "Source Deposit Instructions", + "readOnly": true, + "oneOf": [ + { + "$ref": "#/components/schemas/VirtualAccountSourceDepositInstructionsUs" + }, + { + "$ref": "#/components/schemas/VirtualAccountSourceDepositInstructionsEu" + }, + { + "$ref": "#/components/schemas/VirtualAccountSourceDepositInstructionsMx" + }, + { + "$ref": "#/components/schemas/VirtualAccountSourceDepositInstructionsBr" + }, + { + "$ref": "#/components/schemas/VirtualAccountSourceDepositInstructionsGb" + }, + { + "$ref": "#/components/schemas/VirtualAccountSourceDepositInstructionsCo" + } + ] + }, + "VirtualAccountSourceDepositInstructionsCommon": { + "readOnly": true, + "type": "object", + "required": [ + "bank_address", + "bank_name" + ], + "properties": { + "bank_name": { + "description": "The name of the bank that the customer should send the deposit to", + "type": "string" + }, + "bank_address": { + "description": "The address of the bank that the customer should send the deposit to", + "type": "string" + } + } + }, + "VirtualAccountSourceDepositInstructionsUs": { + "title": "Virtual Account US", + "allOf": [ + { + "type": "object", + "required": [ + "currency", + "payment_rails", + "bank_account_number", + "bank_routing_number", + "bank_beneficiary_name", + "bank_beneficiary_address" + ], + "properties": { + "bank_account_number": { + "description": "The account number of the bank that the customer should send the deposit to", + "type": "string" + }, + "bank_routing_number": { + "description": "The routing number of the bank that the customer should send the deposit to", + "type": "string" + }, + "bank_beneficiary_name": { + "description": "If available, the name of the beneficiary of the bank account that the customer should send the deposit to", + "type": "string" + }, + "bank_beneficiary_address": { + "description": "If available, the address of the beneficiary of the bank account that the customer should send the deposit to", + "type": "string" + }, + "currency": { + "type": "string", + "enum": [ + "usd" + ] + }, + "payment_rail": { + "$ref": "#/components/schemas/VirtualAccountSourcePaymentRails", + "deprecated": true + }, + "payment_rails": { + "description": "The payment rails supported by these deposit instructions", + "type": "array", + "items": { + "type": "string", + "enum": [ + "ach_push", + "fednow", + "wire" + ] + } + } + } + }, + { + "$ref": "#/components/schemas/VirtualAccountSourceDepositInstructionsCommon" + } + ], + "example": { + "currency": "usd", + "payment_rails": [ + "ach_push", + "fednow", + "wire" + ], + "bank_name": "Lead Bank", + "bank_address": "1801 Main St., Kansas City, MO 64108", + "bank_beneficiary_name": "Customer Name", + "bank_beneficiary_address": "1234 Main St., Kansas City, MO 64108", + "bank_account_number": "123456789", + "bank_routing_number": "87654321" + } + }, + "AccountHolderName": { + "type": "string", + "description": "The name of the account owner that the deposit must be sent to." + }, + "VirtualAccountSourceDepositInstructionsBr": { + "title": "Virtual Account BR", + "allOf": [ + { + "type": "object", + "required": [ + "currency", + "payment_rails", + "br_code", + "account_holder_name" + ], + "properties": { + "br_code": { + "description": "The BR Code that the customer should send the deposit to", + "type": "string" + }, + "account_holder_name": { + "$ref": "#/components/schemas/AccountHolderName" + }, + "currency": { + "type": "string", + "enum": [ + "brl" + ] + }, + "payment_rails": { + "description": "The payment rails supported by these deposit instructions", + "type": "array", + "items": { + "type": "string", + "enum": [ + "pix" + ] + } + } + } + }, + { + "$ref": "#/components/schemas/VirtualAccountSourceDepositInstructionsCommon" + } + ] + }, + "VirtualAccountSourceDepositInstructionsMx": { + "title": "Virtual Account MX", + "allOf": [ + { + "type": "object", + "required": [ + "currency", + "payment_rails", + "account_holder_name", + "clabe" + ], + "properties": { + "clabe": { + "description": "The CLABE (account number) of the account that the customer should send the deposit to", + "type": "string" + }, + "account_holder_name": { + "$ref": "#/components/schemas/AccountHolderName" + }, + "currency": { + "type": "string", + "enum": [ + "mxn" + ] + }, + "payment_rails": { + "description": "The payment rails supported by these deposit instructions", + "type": "array", + "items": { + "type": "string", + "enum": [ + "spei" + ] + } + } + } + }, + { + "$ref": "#/components/schemas/VirtualAccountSourceDepositInstructionsCommon" + } + ] + }, + "VirtualAccountSourceDepositInstructionsEu": { + "title": "Virtual IBAN", + "allOf": [ + { + "type": "object", + "required": [ + "iban", + "bic", + "account_holder_name", + "currency", + "payment_rails" + ], + "properties": { + "iban": { + "description": "he IBAN of the account that the customer should send the deposit to", + "type": "string" + }, + "bic": { + "description": "The BIC of the bank that the customer should send the deposit to", + "type": "string" + }, + "account_holder_name": { + "$ref": "#/components/schemas/AccountHolderName" + }, + "bank_beneficiary_name": { + "description": "The account beneficiary name — the customer for POBO accounts, otherwise the Bridge legal entity. Senders should match this name.", + "type": "string" + }, + "bank_beneficiary_address": { + "description": "The account beneficiary address. Present for POBO accounts (the customer's registered address).", + "type": "string" + }, + "currency": { + "type": "string", + "enum": [ + "eur" + ] + }, + "payment_rails": { + "type": "string", + "enum": [ + "sepa" + ] + } + } + }, + { + "$ref": "#/components/schemas/VirtualAccountSourceDepositInstructionsCommon" + } + ] + }, + "VirtualAccountSourceDepositInstructionsGb": { + "title": "Virtual Account UK", + "allOf": [ + { + "$ref": "#/components/schemas/GbBankAccountVirtualAccount" + }, + { + "type": "object", + "required": [ + "currency", + "payment_rails", + "account_holder_name" + ], + "properties": { + "account_holder_name": { + "$ref": "#/components/schemas/AccountHolderName" + }, + "bank_beneficiary_name": { + "description": "The account beneficiary name — the customer for POBO accounts, otherwise the Bridge legal entity. Senders should match this name.", + "type": "string" + }, + "bank_beneficiary_address": { + "description": "The account beneficiary address. Present for POBO accounts (the customer's registered address).", + "type": "string" + }, + "currency": { + "type": "string", + "enum": [ + "gbp" + ] + }, + "payment_rails": { + "type": "string", + "enum": [ + "faster_payments" + ] + } + } + }, + { + "$ref": "#/components/schemas/VirtualAccountSourceDepositInstructionsCommon" + } + ] + }, + "VirtualAccountSourceDepositInstructionsCo": { + "title": "Virtual Account CO (Bre-B)", + "allOf": [ + { + "type": "object", + "required": [ + "currency", + "payment_rails", + "bre_b_key", + "account_holder_name" + ], + "properties": { + "bre_b_key": { + "description": "The Bre-B key of the Colombian bank account for receiving COP deposits", + "type": "string" + }, + "account_holder_name": { + "$ref": "#/components/schemas/AccountHolderName" + }, + "deposit_message": { + "description": "The reference message to include with the COP deposit", + "type": "string" + }, + "currency": { + "type": "string", + "enum": [ + "cop" + ] + }, + "payment_rails": { + "description": "The payment rails supported by these deposit instructions", + "type": "array", + "items": { + "type": "string", + "enum": [ + "bre_b" + ] + } + } + } + }, + { + "$ref": "#/components/schemas/VirtualAccountSourceDepositInstructionsCommon" + } + ] + }, + "StaticMemoEvent": { + "required": [ + "id" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/Id", + "readOnly": true + }, + "type": { + "type": "string", + "description": "The type of activity", + "enum": [ + "funds_received", + "payment_submitted", + "payment_processed", + "in_review", + "refunded", + "refund_in_flight", + "refund_failed", + "account_update" + ] + }, + "customer_id": { + "$ref": "#/components/schemas/Id", + "description": "The id of the Bridge customer that this static memo event belongs to", + "type": "string", + "minLength": 1, + "readOnly": true + }, + "static_memo_id": { + "$ref": "#/components/schemas/Id", + "description": "The id of the Static Memo that this event belongs to", + "type": "string", + "minLength": 1, + "readOnly": true + }, + "amount": { + "type": "string", + "description": "Amount for that event, represented as a dollar denominated string. Examples include \"100.25\", \"0.1\", \"1.234567\" etc. For \"incoming\" events such as funds_received or under_review, this is the initial amount received. For \"outgoing\" events such as payment_submitted and payment_processed, this is the amount of funds sent to the destination. For non-transactional events such as account_update, this will be zero." + }, + "currency": { + "$ref": "#/components/schemas/Currency" + }, + "developer_fee_amount": { + "type": "string", + "description": "Amount of the developer fee if any, represented as a dollar denominated string. This is the final amount taken out of what is ultimately received by your customer, not a percentage. Examples include \"100.25\", \"0.1\", \"1.234567\" etc." + }, + "exchange_fee_amount": { + "type": "string", + "description": "Amount of the exchange fee if any, represented as a dollar denominated string. Examples include \"100.25\", \"0.1\", \"1.234567\" etc." + }, + "subtotal_amount": { + "type": "string", + "description": "Amount of the subtotal, represented as a dollar denominated string. Examples include \"100.25\", \"0.1\", \"1.234567\" etc." + }, + "gas_fee": { + "type": "string", + "description": "Amount of the gas fee if any, represented as a dollar denominated string. Examples include \"100.25\", \"0.1\", \"1.234567\" etc." + }, + "deposit_id": { + "type": "string", + "description": "The id of the deposit related to this event. This id can be used to link multiple events to the same transaction" + }, + "destination_tx_hash": { + "type": "string", + "description": "The hash of the on-chain transfer to the destination address" + }, + "destination_payment_rail": { + "type": "string", + "description": "The destination payment rail where the funds are deposited to" + }, + "source_deposit_instructions": { + "$ref": "#/components/schemas/StaticMemoEventSourceDepositInstructions" + }, + "source": { + "$ref": "#/components/schemas/StaticMemoEventSource" + }, + "created_at": { + "readOnly": true, + "type": "string", + "description": "Time of creation of the event", + "format": "date-time" + } + } + }, + "StaticMemoEventSourceDepositInstructions": { + "required": [ + "deposit_message" + ], + "properties": { + "deposit_message": { + "description": "The message that the customer MUST include in their wire memo/message or ach push description", + "type": "string" + } + } + }, + "StaticMemoEventSource": { + "required": [ + "payment_rail" + ], + "properties": { + "payment_rail": { + "$ref": "#/components/schemas/PaymentRail" + }, + "description": { + "description": "(ACH only) The description of the deposit that the customer sent", + "type": "string" + }, + "sender_name": { + "description": "(ACH only) The name of the business or individual who initiated the transaction", + "type": "string", + "readOnly": true + }, + "sender_bank_routing_number": { + "description": "(ACH only) The routing number of the entity that initiated this ACH transaction", + "type": "string", + "readOnly": true + }, + "trace_number": { + "description": "(ACH only) The unique, a 15-digit number associated with each ACH transaction that is used for tracking and reconciling transactions", + "type": "string", + "readOnly": true + }, + "bank_routing_number": { + "description": "(Wire only) The routing number of the bank that the customer sent the deposit to", + "type": "string", + "readOnly": true + }, + "bank_name": { + "description": "(Wire only) The name of the bank that the customer sent the deposit to", + "type": "string", + "readOnly": true + }, + "bank_beneficiary_name": { + "description": "(Wire only) The beneficiary name of this deposit", + "type": "string", + "readOnly": true + }, + "bank_beneficiary_address": { + "description": "(Wire only) The beneficiary address of this deposit", + "type": "string", + "readOnly": true + }, + "originator_name": { + "description": "(Wire only) The originator name of this deposit", + "type": "string", + "readOnly": true + }, + "originator_address": { + "description": "(Wire only) The originator address of this deposit", + "type": "string", + "readOnly": true + }, + "wire_message": { + "description": "(Wire only) The memo for this wire", + "type": "string", + "readOnly": true + }, + "imad": { + "$ref": "#/components/schemas/Imad" + }, + "omad": { + "$ref": "#/components/schemas/Omad" + } + } + }, + "CreateBridgeWallet": { + "required": [ + "chain" + ], + "properties": { + "chain": { + "$ref": "#/components/schemas/BridgeWalletChain" + } + } + }, + "CreateBatchSettlementSchedule": { + "required": [ + "destination" + ], + "properties": { + "destination": { + "description": "The destination that Bridge will use to settle funds.", + "$ref": "#/components/schemas/TransferDestination" + } + } + }, + "CreateLiquidationAddress": { + "required": [ + "currency", + "chain" + ], + "properties": { + "currency": { + "$ref": "#/components/schemas/LiquidationAddressSourceCurrency" + }, + "chain": { + "$ref": "#/components/schemas/LiquidationAddressSourceChain" + }, + "external_account_id": { + "description": "External bank account to which Bridge will send the funds. The currency associated with the External Account must match the destination currency.", + "$ref": "#/components/schemas/Id" + }, + "prefunded_account_id": { + "description": "The developer's prefunded account id that Bridge will send the funds to.", + "$ref": "#/components/schemas/Id" + }, + "bridge_wallet_id": { + "description": "The Bridge Wallet to which Bridge will send the funds. The chain associated with the Bridge Wallet must match the payment rail.", + "$ref": "#/components/schemas/Id" + }, + "destination_wire_message": { + "$ref": "#/components/schemas/WireMessage" + }, + "destination_sepa_reference": { + "$ref": "#/components/schemas/SepaReference" + }, + "destination_ach_reference": { + "$ref": "#/components/schemas/AchReference" + }, + "destination_spei_reference": { + "$ref": "#/components/schemas/SpeiReference" + }, + "destination_swift_reference": { + "$ref": "#/components/schemas/SwiftReference" + }, + "destination_reference": { + "description": "A payment reference message for newer payment rails (e.g. Pix, Faster Payments, and FedNow).", + "type": "string" + }, + "destination_payment_rail": { + "$ref": "#/components/schemas/SepaSwiftInclusivePaymentRail", + "description": "The payment rail that Bridge will use to send funds to the customer. Will default to ACH if not specified." + }, + "destination_currency": { + "$ref": "#/components/schemas/EuroInclusiveCurrency", + "description": "The currency that Bridge will use to send funds to the customer. Will default to USD if not specified." + }, + "destination_address": { + "type": "string", + "description": "The crypto wallet address that Bridge will use to send funds to the customer." + }, + "destination_blockchain_memo": { + "type": "string", + "description": "The memo to include in the transaction, for blockchains that support memos only" + }, + "return_address": { + "type": "string", + "nullable": true, + "deprecated": true, + "description": "Deprecated: use `return_instructions` instead.\n\nThe crypto wallet address that Bridge will use to return funds to the customer in case of a failed transaction.\nMust be on the same chain as the liquidation address.\nCannot be used on Stellar — use `return_instructions` with a `memo` instead.\n" + }, + "return_instructions": { + "description": "The return instructions Bridge will use to route funds back to the customer when a transaction fails.\nReplaces the deprecated `return_address` field. Set one or the other, not both.\n\nFor memo-required chains (e.g. Stellar), both `address` and `memo` are required — without a memo, Bridge cannot\nroute the return to the correct end-customer at an omnibus wallet.\n", + "allOf": [ + { + "$ref": "#/components/schemas/ReturnInstructions" + } + ] + }, + "custom_developer_fee_percent": { + "$ref": "#/components/schemas/LiquidationAddressCustomDeveloperFeePercent" + }, + "travel_rule_data": { + "description": "Travel Rule data for this liquidation address. Use this only when the same originator or beneficiary should apply to every future movement through this liquidation address. If counterparties can vary by deposit or drain, submit the payload later with `POST /travel_rule_data/{id}` for the relevant movement.", + "allOf": [ + { + "$ref": "#/components/schemas/TravelRuleData" + } + ] + } + } + }, + "UpdateLiquidationAddress": { + "properties": { + "external_account_id": { + "type": "string", + "description": "An optional identifier for the external account you wish to associate with this liquidation schedule.\n\n**Note**: Only one liquidation address can be associated with an external account per (customer, chain, currency).\n" + }, + "custom_developer_fee_percent": { + "$ref": "#/components/schemas/LiquidationAddressCustomDeveloperFeePercent" + }, + "destination": { + "$ref": "#/components/schemas/UpdateLiquidationAddressDestination" + }, + "destination_ach_reference": { + "nullable": true, + "description": "An ACH reference to include with each payout. Send `null` to clear an existing reference.", + "$ref": "#/components/schemas/AchReference" + }, + "destination_wire_message": { + "nullable": true, + "description": "A wire message to include with each payout. Send `null` to clear an existing message.", + "$ref": "#/components/schemas/WireMessage" + }, + "destination_sepa_reference": { + "nullable": true, + "description": "A SEPA reference to include with each payout. Send `null` to clear an existing reference.", + "$ref": "#/components/schemas/SepaReference" + }, + "destination_spei_reference": { + "nullable": true, + "description": "A SPEI reference to include with each payout. Send `null` to clear an existing reference.", + "$ref": "#/components/schemas/SpeiReference" + }, + "destination_swift_reference": { + "nullable": true, + "description": "A SWIFT payment reference to include with each payout. Send `null` to clear an existing reference.", + "$ref": "#/components/schemas/SwiftReference" + }, + "destination_reference": { + "nullable": true, + "description": "A payment reference message for newer payment rails (e.g. Pix, Faster Payments, and FedNow). Send `null` to clear an existing reference.", + "type": "string" + }, + "return_address": { + "type": "string", + "nullable": true, + "deprecated": true, + "description": "Deprecated: use `return_instructions` instead.\n\nThe crypto wallet address that Bridge will use to return funds to the customer in case of a failed transaction.\nMust be on the same chain as the liquidation address.\nCannot be used on Stellar — use `return_instructions` with a `memo` instead.\n" + }, + "return_instructions": { + "description": "The return instructions Bridge will use to route funds back to the customer when a transaction fails.\nReplaces the deprecated `return_address` field. Set one or the other, not both.\n\nFor memo-required chains (e.g. Stellar), both `address` and `memo` are required — without a memo, Bridge cannot\nroute the return to the correct end-customer at an omnibus wallet.\n", + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/ReturnInstructions" + } + ] + } + } + }, + "UpdateLiquidationAddressDestination": { + "type": "object", + "description": "Update the destination currency for a crypto liquidation address. Only `currency` is required;\nchanging the payment rail or address is not currently supported.\n", + "required": [ + "currency" + ], + "properties": { + "currency": { + "$ref": "#/components/schemas/Currency", + "description": "The new destination currency. Must be deployed on the existing destination chain and accessible to the customer." + } + } + }, + "LiquidationAddressCustomDeveloperFeePercent": { + "description": "The developer fee percent that will be applied to this Liquidation Address or null to use the default fee. The value is a base 100 percentage, i.e. 10.2% is 10.2 in the API.", + "type": "string", + "nullable": true, + "format": "number", + "minimum": 0, + "maximum": 100, + "exclusiveMaximum": true, + "example": "0.1" + }, + "DeveloperFeeConfigSchema": { + "description": "The schema version for this fee config. Currently only `v1` is supported.", + "type": "string", + "enum": [ + "v1" + ] + }, + "DeveloperFeeConfigDefaultFeePercentage": { + "description": "The default developer fee percent applied by this config. The value is a base 100 percentage, i.e. 10.2% is 10.2 in the API.", + "type": "string", + "format": "number", + "minimum": 0.01, + "maximum": 100, + "exclusiveMaximum": true, + "example": "0.1" + }, + "DeveloperFeeConfigSourceAssetFee": { + "description": "Per-source-currency fee overrides applied instead of `default_fee_percentage`. Keys are `CryptoCurrency` values, values are base 100 percentages, e.g. `{\"usdc\": \"0.05\"}` charges a 0.05% fee on USDC deposits.", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "example": { + "usdc": "0.05", + "usdt": "0.2" + } + }, + "CreateDeveloperFeeConfig": { + "required": [ + "name", + "schema", + "default_fee_percentage" + ], + "properties": { + "name": { + "type": "string", + "description": "A friendly name for this fee config." + }, + "schema": { + "$ref": "#/components/schemas/DeveloperFeeConfigSchema" + }, + "default_fee_percentage": { + "$ref": "#/components/schemas/DeveloperFeeConfigDefaultFeePercentage" + }, + "source_asset_fee": { + "$ref": "#/components/schemas/DeveloperFeeConfigSourceAssetFee" + }, + "description": { + "type": "string", + "description": "An optional longer description of this fee config." + } + } + }, + "UpdateDeveloperFeeConfig": { + "required": [ + "name", + "schema", + "default_fee_percentage" + ], + "properties": { + "name": { + "type": "string", + "description": "A friendly name for this fee config." + }, + "schema": { + "$ref": "#/components/schemas/DeveloperFeeConfigSchema" + }, + "default_fee_percentage": { + "$ref": "#/components/schemas/DeveloperFeeConfigDefaultFeePercentage" + }, + "source_asset_fee": { + "$ref": "#/components/schemas/DeveloperFeeConfigSourceAssetFee" + }, + "description": { + "type": "string", + "description": "An optional longer description of this fee config." + } + } + }, + "DeveloperFeeConfig": { + "required": [ + "id", + "name", + "schema", + "default_fee_percentage", + "source_asset_fee", + "created_at", + "updated_at" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/Id", + "readOnly": true + }, + "name": { + "type": "string", + "description": "A friendly name for this fee config." + }, + "schema": { + "$ref": "#/components/schemas/DeveloperFeeConfigSchema" + }, + "default_fee_percentage": { + "$ref": "#/components/schemas/DeveloperFeeConfigDefaultFeePercentage" + }, + "source_asset_fee": { + "$ref": "#/components/schemas/DeveloperFeeConfigSourceAssetFee" + }, + "description": { + "type": "string", + "nullable": true, + "description": "An optional longer description of this fee config." + }, + "created_at": { + "readOnly": true, + "type": "string", + "format": "date-time", + "description": "Time of creation of the Developer Fee Config" + }, + "updated_at": { + "readOnly": true, + "type": "string", + "format": "date-time", + "description": "Time of most recent update of the Developer Fee Config" + } + } + }, + "LiquidationAddressGlobalDeveloperFeePercent": { + "description": "The developer fee percent that will be default applied to all Liquidation Addresses.", + "type": "object", + "properties": { + "percent": { + "type": "string", + "nullable": true, + "format": "number", + "minimum": 0, + "maximum": 100, + "exclusiveMaximum": true, + "example": "0.2" + } + } + }, + "CreateBridgeWalletResponse": { + "required": [ + "chain" + ], + "allOf": [ + { + "$ref": "#/components/schemas/CreateBridgeWallet" + }, + { + "properties": { + "id": { + "$ref": "#/components/schemas/Id", + "readOnly": true + }, + "address": { + "description": "The blockchain address of the Bridge Wallet", + "type": "string", + "readOnly": true + }, + "initiation_required": { + "readOnly": true, + "type": "boolean", + "description": "When present, transfers sourced from this wallet must include an `initiation` object on the create request. Omitted for wallets that do not require initiation data." + }, + "created_at": { + "readOnly": true, + "type": "string", + "description": "Time of creation of the Bridge Wallet", + "format": "date-time" + }, + "updated_at": { + "readOnly": true, + "type": "string", + "description": "Time of most recent update of the Bridge Wallet", + "format": "date-time" + } + } + } + ] + }, + "CreateLiquidationAddressResponse": { + "required": [ + "currency", + "chain", + "destination_payment_rail", + "destination_currency" + ], + "allOf": [ + { + "$ref": "#/components/schemas/CreateLiquidationAddress" + }, + { + "properties": { + "address": { + "type": "string", + "description": "The blockchain address the customer will send funds to." + }, + "memoless_address": { + "description": "An alternative crypto wallet address that encodes the memo, allowing the customer to send funds without needing to include a separate memo. Currently only available for Stellar deposits.", + "type": "string" + }, + "external_account_id": { + "description": "External bank account to which Bridge will send the funds." + }, + "prefunded_account_id": { + "description": "The developer's prefunded account to which Bridge will send the funds." + }, + "destination_wire_message": { + "description": "A message to be sent with a wire transfer." + }, + "destination_sepa_reference": { + "description": "A reference message to be sent with a SEPA transaction." + }, + "destination_payment_rail": { + "description": "The payment rail that Bridge will use to send funds to the customer." + }, + "destination_currency": { + "description": "The currency that Bridge will use to send funds to the customer." + }, + "state": { + "type": "string", + "description": "The state of the liquidation address. It could be \"active\" or \"deactivated\"" + }, + "custom_developer_fee_percent": { + "$ref": "#/components/schemas/LiquidationAddressCustomDeveloperFeePercent" + }, + "return_memo": { + "type": "string", + "nullable": true, + "description": "The memo included with return transactions. Present when `return_instructions` was set with a memo (e.g. required for Stellar to route funds to the correct end-customer)." + }, + "supported_currencies": { + "description": "The currencies this Liquidation Address accepts on each chain. Keys are `LiquidationAddressSourceChain` values (e.g. `ethereum`, `polygon`, `base`). For a single-chain, single-currency address this is just that one chain and currency; for a multi-chain (`chain` is `evm`) or multi-currency (`currency` is `all_supported`) address it lists every currency actually accepted on each chain.\n", + "type": "object", + "readOnly": true, + "additionalProperties": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CryptoCurrency" + } + }, + "example": { + "ethereum": [ + "usdc", + "eurc" + ], + "polygon": [ + "usdc" + ] + } + } + } + } + ] + }, + "Drain": { + "required": [ + "id", + "customer_id", + "liquidation_address_id", + "amount", + "currency", + "state" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/Id", + "readOnly": true + }, + "amount": { + "description": "Amount of the drain, represented as a dollar denominated string. Examples include \"100.25\", \"0.1\", \"1.234567\", \"1.01\" etc.", + "type": "string" + }, + "customer_id": { + "$ref": "#/components/schemas/Id", + "readOnly": true + }, + "liquidation_address_id": { + "$ref": "#/components/schemas/Id", + "readOnly": true + }, + "currency": { + "$ref": "#/components/schemas/EuroInclusiveCurrency" + }, + "state": { + "description": "Status of the drain", + "readOnly": true, + "$ref": "#/components/schemas/TransactionStatus" + }, + "created_at": { + "readOnly": true, + "type": "string", + "description": "Time of creation of the drain", + "format": "date-time" + }, + "updated_at": { + "readOnly": true, + "type": "string", + "description": "Time of last update of the drain", + "format": "date-time" + }, + "deposit_tx_hash": { + "readOnly": true, + "type": "string", + "description": "Hash of the Liquidation Address deposit that triggered this drain" + }, + "from_address": { + "readOnly": true, + "type": "string", + "description": "The blockchain address that sent funds to the Liquidation Address" + }, + "source_payment_rail": { + "readOnly": true, + "type": "string", + "description": "The source payment rail where the funds originated from" + }, + "destination": { + "readOnly": true, + "description": "Destination information of a drain.", + "$ref": "#/components/schemas/DrainDestination" + }, + "destination_tx_hash": { + "readOnly": true, + "type": "string", + "description": "Hash of withdrawal of funds to the destination" + }, + "refund_tx_hash": { + "readOnly": true, + "type": "string", + "description": "Hash of refund, if the drain has been returned" + }, + "return_details": { + "readOnly": true, + "description": "Return information, if the drain has been returned.", + "$ref": "#/components/schemas/DrainReturnDetails" + }, + "receipt": { + "readOnly": true, + "description": "Receipt information of a drain.", + "$ref": "#/components/schemas/DrainReceipt" + }, + "exchange_details": { + "readOnly": true, + "description": "Exchange details for the associated trade, if applicable.", + "$ref": "#/components/schemas/ExchangeDetails" + } + } + }, + "Balance": { + "deprecated": true, + "properties": { + "active_balance": { + "description": "Active Balance (Money currently not being processed) of a Liquidation Address", + "type": "string" + }, + "pending_balance": { + "description": "Pending Balance (Money being processed) of a Liquidation Address", + "type": "string" + } + } + }, + "CoBankTransferDocumentType": { + "description": "Colombian document type identifier. `cc` = Cédula de Ciudadanía, `ce` = Cédula de Extranjería, `nit` = NIT (tax ID), `rut` = RUT (worker registration), `pa` = Passport, `ppt` = Permiso de Protección Temporal.\n", + "type": "string", + "enum": [ + "cc", + "ce", + "nit", + "rut", + "pa", + "ppt", + "ti", + "rc", + "te", + "die", + "nd" + ] + }, + "BankAccountNumberType": { + "type": "string", + "enum": [ + "us", + "iban", + "bre_b", + "clabe", + "pix", + "gb", + "unknown" + ] + }, + "CheckingOrSavingsType": { + "description": "Determines whether the US account is treated as checking or savings. All US accounts will be treated as checking by default.", + "type": "string", + "enum": [ + "checking", + "savings" + ] + }, + "BankAccountOwnerType": { + "type": "string", + "enum": [ + "individual", + "business" + ] + }, + "FiatCurrency": { + "type": "string", + "enum": [ + "usd" + ] + }, + "EuroInclusiveFiatCurrency": { + "type": "string", + "enum": [ + "usd", + "eur", + "mxn", + "brl", + "cop", + "gbp" + ] + }, + "Currency": { + "type": "string", + "enum": [ + "usdb", + "usdc", + "usdt", + "usdl_linea", + "usd", + "pyusd" + ] + }, + "EuroInclusiveCurrency": { + "type": "string", + "enum": [ + "brl", + "cop", + "eur", + "eurc", + "gbp", + "mxn", + "pyusd", + "usd", + "usdb", + "usdc", + "usdt", + "usdl_linea" + ] + }, + "CryptoCurrency": { + "type": "string", + "enum": [ + "usdb", + "usdc", + "usdt", + "usdl_linea", + "pyusd", + "eurc" + ] + }, + "LiquidationAddressSourceCurrency": { + "type": "string", + "enum": [ + "usdb", + "usdc", + "usdt", + "usdl_linea", + "pyusd", + "eurc", + "all_supported" + ] + }, + "LiquidationAddressSourceChain": { + "type": "string", + "enum": [ + "arbitrum", + "avalanche_c_chain", + "base", + "celo", + "ethereum", + "linea", + "optimism", + "polygon", + "solana", + "stellar", + "tempo", + "tron", + "xdc", + "evm" + ] + }, + "CardsCryptoCurrency": { + "type": "string", + "enum": [ + "usdc" + ] + }, + "DeveloperFees": { + "required": [ + "default_liquidation_address_fee_percent" + ], + "properties": { + "default_liquidation_address_fee_percent": { + "description": "The default fee percent that will be applied to all your Liquidation Addresses. The value is a base 100 percentage, i.e. 10.2% is \"10.2\" in the API.", + "type": "string", + "format": "float", + "minimum": 0.0, + "maximum": 1.0, + "example": "0.5", + "exclusiveMaximum": true + } + } + }, + "ApiKeyScope": { + "description": "A scope that may be granted to a scoped API key. Unrestricted keys are created via the Dashboard and implicitly hold the standard scopes; they cannot be requested here.", + "type": "string", + "enum": [ + "api_key:create", + "api_key:self:read", + "audit_log:read", + "batch_settlement:create", + "batch_settlement:read", + "card:create", + "card:delete", + "card:read", + "card:update", + "crypto_return_policy:create", + "crypto_return_policy:delete", + "crypto_return_policy:read", + "crypto_return_policy:update", + "customer:create", + "customer:delete", + "customer:read", + "customer:update", + "customer_creation_request:create", + "customer_creation_request:read", + "developer_fee:create", + "developer_fee:read", + "developer_fee:update", + "developer_trade_configuration:read", + "developer_trade_configuration:update", + "exchange_rate:read", + "external_account:create", + "external_account:delete", + "external_account:read", + "external_account:update", + "funds_request:read", + "inquiry:read", + "inquiry:resume", + "liquidation_address:create", + "liquidation_address:drain:read", + "liquidation_address:drain:update", + "liquidation_address:read", + "liquidation_address:update", + "prefunded_account:create", + "prefunded_account:history:read", + "prefunded_account:read", + "rewards:read", + "rfi:read", + "sandbox:developer:create", + "sandbox:simulate", + "spender_contract:approval:create", + "spender_contract:approval:read", + "spender_contract:create", + "spender_contract:read", + "tos_link:create", + "tos_link:read", + "transfer:create", + "transfer:create:privy_custodial_wallet", + "transfer:delete", + "transfer:read", + "transfer:update", + "travel_rule_data:create", + "virtual_account:create", + "virtual_account:delete", + "virtual_account:history:read", + "virtual_account:read", + "virtual_account:transaction:read", + "virtual_account:update", + "wallet:create", + "wallet:create:privy_custodial_wallet", + "wallet:customer:read", + "wallet:delete", + "wallet:developer:read", + "wallet:update", + "webhook:create", + "webhook:delete", + "webhook:read", + "webhook:update" + ] + }, + "CreateApiKeyInput": { + "required": [ + "scopes" + ], + "properties": { + "scopes": { + "description": "Scopes to grant the new key. Must be a non-empty array. Each scope must be one you yourself hold (scope subsetting).", + "type": "array", + "minItems": 1, + "items": { + "$ref": "#/components/schemas/ApiKeyScope" + } + }, + "name": { + "description": "A human-readable label for this key, up to 100 characters. Useful for identifying the key's purpose later.", + "type": "string", + "maxLength": 100 + } + } + }, + "ApiKey": { + "required": [ + "id", + "type", + "owner_type", + "owner_id", + "prefix", + "last_4", + "state", + "created_at", + "updated_at", + "scopes" + ], + "properties": { + "id": { + "description": "The unique identifier for this API key.", + "type": "string", + "format": "uuid" + }, + "type": { + "description": "Whether the key was created programmatically (Private) or via the Dashboard (Public).", + "type": "string", + "enum": [ + "Public", + "Private" + ] + }, + "owner_type": { + "description": "The type of entity that owns the key. Always `Developer`.", + "type": "string", + "enum": [ + "Developer" + ] + }, + "owner_id": { + "description": "The developer ID that owns the key.", + "type": "string", + "format": "uuid" + }, + "prefix": { + "description": "The environment prefix of the key. `sk-live` in production, `sk-test` in sandbox.", + "type": "string", + "enum": [ + "sk-live", + "sk-test" + ] + }, + "last_4": { + "description": "The last four characters of the key, shown alongside the prefix for disambiguation in audit logs.", + "type": "string" + }, + "state": { + "description": "Lifecycle state of the key.", + "type": "string", + "enum": [ + "Active", + "Deleted" + ] + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "scopes": { + "description": "The scopes authorized on this key. A single-element list containing `bridge:api_unrestricted`\ndenotes an unrestricted key (all standard scopes). Any other list denotes a scoped key.\n", + "type": "array", + "items": { + "type": "string" + } + }, + "name": { + "description": "The human-readable label for this key, if one was provided at creation.", + "type": "string", + "maxLength": 100 + } + } + }, + "ApiKeyWithSecret": { + "description": "Returned only on key creation. `value` is the plaintext secret and is shown exactly once.", + "allOf": [ + { + "$ref": "#/components/schemas/ApiKey" + }, + { + "required": [ + "value" + ], + "properties": { + "value": { + "description": "The plaintext secret for this API key. Store it securely — it cannot be retrieved again.", + "type": "string", + "example": "sk-live-0123456789abcdef0123456789ab9f2c" + } + } + } + ] + }, + "BridgeWalletChain": { + "type": "string", + "enum": [ + "base", + "ethereum", + "linea", + "solana", + "tempo", + "tron", + "xdc" + ] + }, + "OfframpChain": { + "type": "string", + "enum": [ + "arbitrum", + "avalanche_c_chain", + "base", + "celo", + "ethereum", + "linea", + "optimism", + "polygon", + "solana", + "stellar", + "tempo", + "tron", + "xdc" + ] + }, + "OfframpChainForCards": { + "type": "string", + "enum": [ + "arbitrum", + "avalanche_c_chain", + "base", + "ethereum", + "optimism", + "polygon", + "solana", + "stellar" + ] + }, + "PaymentRail": { + "type": "string", + "enum": [ + "ach", + "wire", + "ach_push", + "ach_same_day", + "arbitrum", + "avalanche_c_chain", + "base", + "bre_b", + "co_bank_transfer", + "celo", + "ethereum", + "optimism", + "pix", + "polygon", + "solana", + "spei", + "stellar", + "tempo" + ] + }, + "VirtualAccountSourcePaymentRails": { + "type": "string", + "enum": [ + "ach_push", + "bre_b", + "faster_payments", + "pix", + "sepa", + "spei", + "wire" + ] + }, + "PaymentScheme": { + "type": "string", + "enum": [ + "sepa_credit", + "sepa_instant" + ] + }, + "SepaSwiftInclusivePaymentRail": { + "type": "string", + "enum": [ + "ach", + "wire", + "ach_push", + "ach_same_day", + "arbitrum", + "avalanche_c_chain", + "base", + "bre_b", + "co_bank_transfer", + "celo", + "ethereum", + "faster_payments", + "fiat_deposit_return", + "linea", + "optimism", + "pix", + "polygon", + "sepa", + "solana", + "spei", + "stellar", + "swift", + "tempo", + "tron", + "xdc" + ] + }, + "TransferSourcePaymentRail": { + "type": "string", + "enum": [ + "ach", + "wire", + "ach_push", + "ach_same_day", + "fednow", + "arbitrum", + "avalanche_c_chain", + "base", + "bre_b", + "co_bank_transfer", + "bridge_wallet", + "celo", + "ethereum", + "faster_payments", + "linea", + "optimism", + "pix", + "polygon", + "sepa", + "solana", + "spei", + "stellar", + "swift", + "tempo", + "tron", + "xdc" + ] + }, + "VirtualAccountEventPaymentRails": { + "type": "string", + "enum": [ + "ach_push", + "bre_b", + "faster_payments", + "fednow", + "pix", + "sepa", + "spei", + "wire" + ] + }, + "OfframpPaymentRail": { + "type": "string", + "enum": [ + "ach", + "wire", + "ach_push", + "ach_same_day", + "fednow", + "arbitrum", + "avalanche_c_chain", + "base", + "bre_b", + "co_bank_transfer", + "celo", + "ethereum", + "optimism", + "polygon", + "solana", + "spei", + "stellar", + "swift", + "tempo", + "tron" + ] + }, + "SepaSwiftInclusiveOfframpPaymentRail": { + "type": "string", + "enum": [ + "ach", + "wire", + "ach_push", + "ach_same_day", + "fednow", + "arbitrum", + "avalanche_c_chain", + "base", + "bre_b", + "co_bank_transfer", + "celo", + "ethereum", + "fiat_deposit_return", + "linea", + "optimism", + "polygon", + "sepa", + "solana", + "spei", + "stellar", + "swift", + "tempo", + "tron", + "xdc" + ] + }, + "Error": { + "required": [ + "code", + "message" + ], + "properties": { + "code": { + "type": "string", + "minLength": 1, + "maxLength": 256 + }, + "message": { + "type": "string", + "minLength": 1, + "maxLength": 512 + }, + "source": { + "title": "ErrorSource", + "required": [ + "location", + "key" + ], + "properties": { + "location": { + "type": "string", + "enum": [ + "path", + "query", + "body", + "header" + ] + }, + "key": { + "type": "string", + "description": "Comma separated names of the properties or parameters causing the error" + } + } + } + } + }, + "PlaidLinkRequest": { + "properties": { + "link_token": { + "type": "string", + "description": "Link token generated via the Plaid Link SDK" + }, + "link_token_expires_at": { + "type": "string", + "description": "Expiration time of the link token", + "format": "date-time" + }, + "callback_url": { + "type": "string", + "description": "URL to call through Plaid Link Flow's onSuccess callback with the public token passed in the body of the request" + } + } + }, + "IndividualKycLinkResponse": { + "properties": { + "id": { + "type": "string", + "description": "ID of the KYC link" + }, + "type": { + "type": "string", + "description": "Type of the KYC link", + "enum": [ + "individual", + "business" + ] + }, + "customer_id": { + "type": "string", + "description": "ID of the customer." + }, + "full_name": { + "type": "string", + "description": "Full name of the customer, for a business, this would be the business entity's legal name" + }, + "email": { + "type": "string", + "description": "Email of the customer" + }, + "kyc_link": { + "type": "string", + "description": "Link to the KYC flow" + }, + "kyc_status": { + "type": "string", + "$ref": "#/components/schemas/KycStatus" + }, + "rejection_reasons": { + "deprecated": true, + "readOnly": true, + "description": "Reasons why a customer KYC was rejected", + "type": "array", + "minItems": 0, + "items": { + "$ref": "#/components/schemas/RejectionReason" + } + }, + "tos_link": { + "type": "string", + "description": "Link to the TOS flow" + }, + "tos_status": { + "type": "string", + "$ref": "#/components/schemas/TosStatus" + }, + "created_at": { + "type": "string", + "description": "Time of creation of the KYC link", + "format": "date-time" + } + } + }, + "PlaidExchangePublicToken": { + "required": [ + "public_token" + ], + "properties": { + "public_token": { + "type": "string", + "description": "Public token generated via the Plaid Link SDK" + } + } + }, + "TransactionStatus": { + "type": "string", + "enum": [ + "awaiting_funds", + "in_review", + "funds_received", + "payment_submitted", + "payment_processed", + "canceled", + "error", + "undeliverable", + "returned", + "refund_in_flight", + "refund_failed", + "refunded" + ] + }, + "TransferState": { + "type": "string", + "enum": [ + "awaiting_funds", + "in_review", + "funds_received", + "payment_submitted", + "payment_processed", + "canceled", + "undeliverable", + "returned", + "refund_in_flight", + "refund_failed", + "refunded" + ] + }, + "CustomerStatus": { + "type": "string", + "description": "`offboarded`: represents a customer's account that was internally reviewed and closed due to suspicious activity.\n`paused`: represents a customer's account that is currently under review because of activity on the platform.\n`deposits_restricted`: represents a customer's account that is currently restricted from making new deposits because of activity on the platform.\n", + "enum": [ + "active", + "awaiting_questionnaire", + "awaiting_ubo", + "deposits_restricted", + "incomplete", + "not_started", + "offboarded", + "paused", + "rejected", + "under_review" + ] + }, + "CustomerCapabilityState": { + "type": "string", + "description": "State of the customer capability", + "enum": [ + "pending", + "active", + "inactive", + "rejected" + ] + }, + "KycStatus": { + "type": "string", + "description": "Status of the KYC flow.", + "enum": [ + "not_started", + "incomplete", + "awaiting_questionnaire", + "awaiting_ubo", + "under_review", + "approved", + "rejected", + "paused", + "offboarded", + "deposits_restricted" + ] + }, + "RejectionReason": { + "description": "Reason why the kyc_status was rejected", + "properties": { + "developer_reason": { + "type": "string", + "description": "Developer information for why a customer was rejected. Not to be shared with the customer." + }, + "reason": { + "type": "string", + "description": "Reason for why a customer was rejected. To be shared with the customer." + }, + "created_at": { + "deprecated": true, + "nullable": true, + "type": "string", + "description": "Time of creation of the rejection reason" + } + } + }, + "TosStatus": { + "type": "string", + "description": "Status of the TOS flow", + "enum": [ + "pending", + "approved" + ] + }, + "WebhookEventCategory": { + "type": "string", + "description": "The category of the webhook event", + "enum": [ + "customer", + "kyc_link", + "liquidation_address.drain", + "static_memo.activity", + "transfer", + "virtual_account.activity", + "bridge_wallet.activity", + "card_account", + "card_transaction", + "card_withdrawal", + "posted_card_account_transaction", + "external_account", + "rfi" + ] + }, + "Webhook": { + "required": [ + "id", + "url", + "status", + "public_key" + ], + "properties": { + "id": { + "type": "string", + "description": "An identifier that uniquely identifies the webhook endpoint", + "pattern": "^wep_[a-f0-9]+$" + }, + "url": { + "type": "string", + "description": "The URL that the webhook will send events to" + }, + "status": { + "type": "string", + "description": "The status of the webhook. Only active webhooks will receive events automatically.", + "enum": [ + "active", + "disabled", + "deleted" + ] + }, + "public_key": { + "type": "string", + "description": "The public key (in PEM format) that should be used to verify the authenticity of webhook events" + }, + "event_categories": { + "type": "array", + "description": "The list of event categories that the webhook endpoint will receive", + "minItems": 0, + "items": { + "$ref": "#/components/schemas/WebhookEventCategory" + } + } + } + }, + "WebhookEvent": { + "required": [ + "api_version", + "event_id", + "event_developer_id", + "event_category", + "event_type", + "event_object_id", + "event_object", + "event_object_changes", + "event_created_at" + ], + "properties": { + "api_version": { + "type": "string", + "readOnly": true + }, + "event_id": { + "$ref": "#/components/schemas/Id", + "readOnly": true + }, + "event_developer_id": { + "type": "string", + "readOnly": true, + "description": "The developer ID of the developer" + }, + "event_sequence": { + "type": "integer", + "readOnly": true + }, + "event_category": { + "$ref": "#/components/schemas/WebhookEventCategory" + }, + "event_type": { + "type": "string", + "description": "The values here will be prefixed with the event_category. For example, a customer created event will be `customer.created`", + "enum": [ + "created", + "updated", + "updated.status_transitioned", + "deleted", + "canceled" + ] + }, + "event_object_id": { + "$ref": "#/components/schemas/Id", + "readOnly": true + }, + "event_object_status": { + "type": "string", + "readOnly": true, + "enum": [ + "not_started", + "incomplete", + "active", + "rejected", + "under_review", + "manual_review", + "awaiting_ubo", + "approved", + "awaiting_funds", + "funds_received", + "payment_submitted", + "payment_processed", + "in_review", + "canceled", + "error", + "returned", + "refund_in_flight", + "refund_failed", + "refunded", + "undeliverable" + ] + }, + "event_object": { + "type": "object", + "description": "The object that was affected by the event", + "readOnly": true + }, + "event_object_changes": { + "type": "object", + "description": "The changes that were made to the object", + "readOnly": true + }, + "event_created_at": { + "type": "string", + "format": "date-time", + "readOnly": true + } + } + }, + "WebhookEventDeliveryLog": { + "required": [ + "status", + "event_id", + "response_body", + "created_at" + ], + "properties": { + "status": { + "type": "integer", + "description": "The status code of the delivery" + }, + "event_id": { + "$ref": "#/components/schemas/Id", + "description": "The id of the event for the delivery" + }, + "response_body": { + "type": "string", + "description": "The response body of the delivery" + }, + "created_at": { + "type": "string", + "format": "date-time", + "description": "The time of the delivery" + } + } + }, + "CreateWebhook": { + "required": [ + "url", + "event_epoch" + ], + "properties": { + "url": { + "description": "The URL that the webhook will send events to. It must use the HTTPS scheme and have a valid X.509 certificate. The URL doesn't need to be live, but the host must be reachable.", + "type": "string", + "minLength": 1 + }, + "event_epoch": { + "description": "Specifies the starting point from which this webhook will receive events. This should usually be set to \"webhook_creation\", unless there is a reason why this webhook needs to process events from before its creation. When this value is set to \"webhook_creation\", the webhook will receive a small number of events preceding its creation for convenience.", + "type": "string", + "enum": [ + "webhook_creation", + "beginning_of_time" + ] + }, + "event_categories": { + "type": "array", + "description": "The list of event categories that the webhook endpoint will receive", + "minItems": 0, + "items": { + "$ref": "#/components/schemas/WebhookEventCategory" + } + } + } + }, + "FundsRequest": { + "required": [ + "id" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/Id", + "readOnly": true + }, + "deposit_id": { + "$ref": "#/components/schemas/Id", + "description": "The id that uniquely identifies the Bridge deposit associated with the funds request", + "type": "string", + "minLength": 1, + "readOnly": true + }, + "customer_id": { + "$ref": "#/components/schemas/Id", + "description": "The id of the Bridge customer that this static memo event belongs to", + "type": "string", + "minLength": 1, + "readOnly": true + }, + "amount": { + "type": "string", + "description": "Amount of the deposit, represented as a decimal string. Examples include \"100.25\", \"0.1\", \"1.234567\" etc. It is denominated in the source currency of the deposit." + }, + "currency": { + "$ref": "#/components/schemas/Currency" + }, + "payment_rail": { + "type": "string", + "description": "The source payment rail of the deposit" + }, + "fraud": { + "type": "boolean", + "description": "Whether the funds request was fraudulent or not" + }, + "notice_date": { + "type": "string", + "description": "Date that Bridge was notified about the funds request from our banking partner, in the format YYYY-MM-DD" + }, + "imad": { + "type": "string", + "description": "(Wire only) The IMAD of a wire deposit, if available" + }, + "trace_number": { + "type": "string", + "description": "(ACH only) The trace number of an ACH deposit, if available" + }, + "bank_transaction_id": { + "type": "string", + "description": "(Non-wire and Non-ACH only) In cases where an identifier tied to a public financial system is not available, we may instead provide a unique identifier that identifies the transaction for the relevant bank or financial institution" + }, + "created_at": { + "readOnly": true, + "type": "string", + "description": "Time of creation of the funds request", + "format": "date-time" + }, + "deposit_created_at": { + "readOnly": true, + "type": "string", + "description": "Time of creation of the associated deposit", + "format": "date-time" + } + } + }, + "Rfi": { + "required": [ + "id", + "state", + "developer_id", + "deadline", + "requested_items", + "dashboard_url", + "created_at" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/Id", + "readOnly": true + }, + "state": { + "type": "string", + "enum": [ + "on_developer", + "on_bridge", + "closed" + ], + "description": "The current state of the RFI" + }, + "developer_id": { + "$ref": "#/components/schemas/Id", + "readOnly": true + }, + "customer_id": { + "$ref": "#/components/schemas/Id", + "readOnly": true, + "nullable": true, + "description": "The customer this RFI is associated with, if any" + }, + "referent_id": { + "type": "string", + "nullable": true, + "description": "The id of the record (transfer, drain, deposit, or card account) this RFI relates to, if any. Resolve it against the endpoint named by `referent_type`" + }, + "referent_type": { + "type": "string", + "nullable": true, + "enum": [ + "transfer", + "drain", + "deposit", + "card_account" + ], + "description": "The type of record that `referent_id` refers to" + }, + "context": { + "type": "object", + "description": "Transaction and counterparty facts this RFI is about, keyed by field name. The set of keys present varies by RFI template - fields without a value for this RFI are omitted rather than set to null. May contain personally-identifiable information (customer name/email, IBANs, counterparty names). The properties below are the most common keys; other template-specific string keys may also be present.", + "properties": { + "amount_display": { + "type": "string", + "description": "The transaction amount, pre-formatted for display" + }, + "currency_display": { + "type": "string", + "description": "The transaction currency, pre-formatted for display" + }, + "transaction_date": { + "type": "string", + "description": "The transaction date, pre-formatted for display" + }, + "customer_name": { + "type": "string", + "description": "The customer's name" + }, + "customer_email": { + "type": "string", + "description": "The customer's email" + }, + "sender_name": { + "type": "string", + "description": "The sender's name, if this RFI concerns an incoming payment" + }, + "beneficiary_name": { + "type": "string", + "description": "The beneficiary's name, if this RFI concerns an outgoing payment" + }, + "counterparty_name": { + "type": "string", + "description": "The counterparty's name" + }, + "creditor_iban": { + "type": "string", + "description": "The creditor IBAN, for RFIs concerning an IBAN-based payment" + }, + "debtor_iban": { + "type": "string", + "description": "The debtor IBAN, for RFIs concerning an IBAN-based payment" + }, + "custom_body": { + "type": "string", + "description": "Ops-authored free text describing the request, present only for freeform RFIs" + } + } + }, + "bridge_action_taken": { + "type": "string", + "nullable": true, + "enum": [ + "customer_paused", + "transaction_paused" + ], + "description": "An action Bridge has already taken as a result of this RFI, if any" + }, + "expected_action_on_expiry": { + "type": "string", + "nullable": true, + "enum": [ + "pause_customer" + ], + "description": "The action Bridge expects to take if this RFI expires without a response, if any" + }, + "deadline": { + "type": "string", + "format": "date-time", + "description": "The time by which a response to this RFI is expected" + }, + "requested_items": { + "type": "array", + "description": "The items Bridge is asking the developer to provide for this RFI", + "items": { + "type": "object", + "required": [ + "content" + ], + "properties": { + "content": { + "type": "string", + "description": "The question or request being made, in developer-facing prose" + } + } + } + }, + "dashboard_url": { + "type": "string", + "description": "A link to view and respond to this RFI in the Bridge dashboard" + }, + "state_changed_at": { + "type": "string", + "format": "date-time", + "nullable": true, + "description": "The time the RFI's state last changed" + }, + "created_at": { + "readOnly": true, + "type": "string", + "format": "date-time", + "description": "Time of creation of the RFI" + }, + "closed_at": { + "type": "string", + "format": "date-time", + "nullable": true, + "description": "The time the RFI was closed, if it has been" + } + } + }, + "CryptoReturnPolicy": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "developer_id": { + "type": "string" + }, + "refund_destination_address": { + "type": "string" + }, + "refund_destination_blockchain_memo": { + "type": "string" + }, + "refund_destination_chain": { + "type": "string" + }, + "refund_destination_currency": { + "type": "string" + }, + "strategy": { + "type": "string" + } + } + }, + "PostCryptoReturnPoliciesInput": { + "type": "object", + "properties": { + "refund_destination_address": { + "type": "string", + "description": "The address to which the refund will be sent. Required if the strategy is `static_address`, but must be unset if the strategy is `refund_to_sender`." + }, + "refund_destination_blockchain_memo": { + "type": "string", + "description": "The memo to include with the refund transaction. Must be unset if the strategy is `refund_to_sender`." + }, + "refund_destination_chain": { + "type": "string", + "description": "The blockchain on which the refund will be sent. Required if the strategy is `static_address`, but must be unset if the strategy is `refund_to_sender`." + }, + "refund_destination_currency": { + "type": "string", + "description": "The currency to which the refund will be sent. Required if the strategy is `static_address`, but must be unset if the strategy is `refund_to_sender`." + }, + "strategy": { + "type": "string", + "description": "The strategy to use for the refund. Can be `refund_to_sender` or `static_address`. We only support multiple policies for `static_address`; different strategies cannot have multiple policies. If multiple `static_address` policies exist, the policy that matches both the currency and chain will be used first. If no such policy is found, the policy that matches only the currency will be used instead." + } + } + }, + "PostCardAccountsInput": { + "required": [ + "currency", + "chain" + ], + "properties": { + "client_reference_id": { + "type": "string", + "description": "An optional client-provided reference ID that uniquely identifies the card account in the client's system" + }, + "currency": { + "$ref": "#/components/schemas/CardsCryptoCurrency", + "description": "Crypto currency used by the card account being created" + }, + "chain": { + "$ref": "#/components/schemas/OfframpChainForCards", + "description": "Chain used by the card account being created" + }, + "crypto_account": { + "$ref": "#/components/schemas/CardCryptoAccount" + }, + "card_design_shortname": { + "type": "string", + "description": "The shortname of the card design to use for the card account. If not specified, the default card design will be used." + } + } + }, + "PostCardFreezeInput": { + "required": [ + "initiator", + "reason" + ], + "properties": { + "initiator": { + "$ref": "#/components/schemas/CardFreezeInitiator" + }, + "reason": { + "$ref": "#/components/schemas/CardFreezeReason" + }, + "reason_detail": { + "type": "string", + "description": "A more detailed reason for the freeze" + }, + "starting_at": { + "type": "string", + "description": "An optional starting time in ISO8601 format. It defaults to the current date-time if unspecified" + }, + "ending_at": { + "type": "string", + "description": "An optional ending time in ISO8601 format. If this ending time is not specified, the card account will stay frozen indefinitely until it gets unfrozen by another request" + } + } + }, + "PostCardUnfreezeInput": { + "required": [ + "initiator" + ], + "properties": { + "initiator": { + "allOf": [ + { + "$ref": "#/components/schemas/CardFreezeInitiator" + } + ], + "description": "The party of the freeze to be removed" + } + } + }, + "CardUnfreezeResponse": { + "description": "Card unfreeze response", + "required": [ + "card_account_id", + "initiator", + "reason", + "created_at", + "status" + ], + "allOf": [ + { + "$ref": "#/components/schemas/CardFreeze" + }, + { + "properties": { + "initiator": { + "description": "The initiator of the removed freeze" + }, + "reason": { + "description": "The reason of the removed freeze" + }, + "reason_detail": { + "description": "The reason detail of the removed freeze" + }, + "starting_at": { + "description": "The start time of the removed freeze, in ISO8601 format" + }, + "ending_at": { + "description": "The end time of the removed freeze, in ISO8601 format" + }, + "created_at": { + "description": "The creation time of the removed freeze, in ISO8601 format" + }, + "status": { + "type": "string", + "description": "The processing status of the unfreeze request", + "readOnly": true, + "enum": [ + "freeze_removed" + ] + } + } + } + ] + }, + "PostCardPushProvisioningInput": { + "required": [ + "initiator" + ], + "properties": { + "wallet_provider": { + "allOf": [ + { + "$ref": "#/components/schemas/CardWalletProvider" + } + ], + "description": "The wallet provider of the push provisioning request" + }, + "apple_pay": { + "description": "Apple Pay specific provisioning request data. Required for `apple_pay` wallet provider.", + "required": [ + "leaf_cert", + "subordinate_cert", + "nonce", + "nonce_signature" + ], + "properties": { + "encoding": { + "type": "string", + "description": "Specifies the encoding of each field in the Apple Pay provisioning request. Defaults to `hex` if unspecified.", + "enum": [ + "base64", + "hex" + ] + }, + "leaf_cert": { + "type": "string", + "description": "The leaf certificate returned by the wallet provider that was signed using the subordinate cert. The binary data of this certificate should be hex (case-insensitive) or base64 encoded, as specified by the encoding field" + }, + "subordinate_cert": { + "type": "string", + "description": "The subordinate certificate returned by the wallet provider that was signed using the wallet provider's Certificate Authority (CA) certificate. The binary data of this certificate should be hex (case-insensitive) or base64 encoded, as specified by the encoding field" + }, + "nonce": { + "type": "string", + "description": "The nonce value returned by Apple Pay. It should be hex (case-insensitive) or base64 encoded, as specified by the encoding field" + }, + "nonce_signature": { + "type": "string", + "description": "The nonce signature value returned by Apple Pay. It should be hex (case-insensitive) or base64 encoded, as specified by the encoding field" + } + } + }, + "google_pay": { + "description": "Google Pay specific push provisioning request data. Required for `google_pay` wallet provider.", + "required": [ + "client_wallet_account_id", + "client_device_id" + ], + "properties": { + "client_wallet_account_id": { + "type": "string", + "description": "Value returned by Google Pay for use with Visa" + }, + "client_device_id": { + "type": "string", + "description": "Value returned by Google Pay for use with Visa" + } + } + } + } + }, + "CardPushProvisioningResponse": { + "description": "The mobile wallet push provisioning response", + "required": [ + "card_account_id", + "initiator", + "reason", + "created_at", + "status" + ], + "properties": { + "wallet_provider": { + "allOf": [ + { + "$ref": "#/components/schemas/CardWalletProvider" + } + ], + "description": "The wallet provider of the push provisioning request" + }, + "apple_pay": { + "description": "The detailed provisioning request data that need to be sent directly to the `apple_pay` wallet provider", + "properties": { + "activation_data": { + "type": "string", + "description": "The request's activation data. This field is always Base64-encoded" + }, + "encrypted_pass_data": { + "type": "string", + "description": "An encrypted JSON file containing the sensitive information needed to add a card to a wallet. This field is always Base64-encoded" + }, + "ephemeral_public_key": { + "type": "string", + "description": "A generated key that is combined with a private key. This field is always Base64-encoded" + } + } + }, + "google_pay": { + "description": "The detailed provisioning request data that need to be sent directly to the `google_pay` wallet provider", + "properties": { + "opaque_payment_card": { + "type": "string", + "description": "A Base64-encoded or Base64url-encoded opaque string" + } + } + } + } + }, + "PostCardAccountEphemeralKeyInput": { + "description": "The request to create an ephemeral key to reveal card details", + "required": [ + "client_nonce" + ], + "properties": { + "client_nonce": { + "type": "string", + "description": "The client-side nonce that will be associated with the ephemeral key. This must be generated from the client secret and timestamp as per the [integration guide](https://apidocs.bridge.xyz/docs/safely-reveal-card-details-to-customers) in order to be usable for revealing card details." + } + } + }, + "CardAccountEphemeralKeyResponse": { + "description": "A response containing the ephemeral key to reveal card details", + "required": [ + "ephemeral_key" + ], + "properties": { + "ephemeral_key": { + "type": "string", + "description": "The ephemeral key to reveal card details. This key is only valid for 5 minutes. Your backend should return this key to the frontend instead of directly using it, to avoid putting your backend in PCI compliance scope. Please see the integration guide on [safely revealing card details](/platform/cards/additional/safely-reveal-card-details) for more information." + } + } + }, + "CardAccount": { + "type": "object", + "required": [ + "id", + "customer_id", + "status", + "balances", + "freezes" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/Id", + "description": "ID of the card account" + }, + "client_reference_id": { + "type": "string", + "description": "The client-provided reference ID" + }, + "customer_id": { + "$ref": "#/components/schemas/Id", + "description": "ID of the customer" + }, + "cardholder_name": { + "type": "object", + "$ref": "#/components/schemas/CardholderName" + }, + "card_image_url": { + "type": "string", + "deprecated": true, + "description": "An expiring URL used to render the card image, with a validity period of 5 minutes. _Note:_ This field will be deprecated in favor of the more secure and scalable card details API. Please see the integration guide on [safely revealing card details](https://apidocs.bridge.xyz/docs/safely-reveal-card-details-to-customers) for more information." + }, + "status": { + "type": "string", + "description": "Status of the card account", + "enum": [ + "active", + "pending", + "inactive", + "frozen" + ] + }, + "status_reason": { + "type": "string", + "description": "An optional detailed explanation for the card account status" + }, + "card_details": { + "type": "object", + "$ref": "#/components/schemas/CardDetails" + }, + "balances": { + "type": "object", + "$ref": "#/components/schemas/CardBalances" + }, + "freezes": { + "type": "array", + "minItems": 0, + "items": { + "allOf": [ + { + "$ref": "#/components/schemas/CardFreeze" + } + ], + "properties": { + "initiator": { + "description": "The party that initiated the freeze. A freeze can be initiated by the customer, the developer, or Bridge. Only one freeze per initiator can be active at a time. If a new freeze is initiated by the same party, it overwrites any existing freeze", + "enum": [ + "bridge" + ] + } + } + } + }, + "stripe_card_id": { + "type": "string", + "nullable": true, + "description": "The [Stripe Issuing card ID](https://docs.stripe.com/api/issuing/cards/object?issuing_card_object-id), if the card account is backed by Stripe Issuing" + }, + "crypto_account": { + "type": "object", + "$ref": "#/components/schemas/CardCryptoAccount" + }, + "funding_instructions": { + "$ref": "#/components/schemas/CardAccountFundingInstructions" + }, + "additional_funding_instructions": { + "type": "array", + "minItems": 0, + "items": { + "$ref": "#/components/schemas/CardAccountFundingInstructions" + } + } + } + }, + "CardBalances": { + "description": "Balances of the card account", + "type": "object", + "required": [ + "available", + "hold" + ], + "properties": { + "available": { + "description": "The available balance of the card account", + "type": "object", + "$ref": "#/components/schemas/CardBalance" + }, + "hold": { + "description": "The balance tha is placed on hold for pending authorizations", + "type": "object", + "$ref": "#/components/schemas/CardBalance" + } + } + }, + "CardBalance": { + "required": [ + "amount", + "currency" + ], + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "$ref": "#/components/schemas/CardsCryptoCurrency" + } + } + }, + "CardDetails": { + "description": "Details of the issued card. This object contains enough payment card details to identify the issued card, but only provides the last four digits of the card number to maintain security.", + "type": "object", + "required": [ + "last_4", + "expiry", + "bin" + ], + "properties": { + "last_4": { + "description": "The last four digits of the card number", + "type": "string", + "example": "1264" + }, + "expiry": { + "description": "The expiration date of the card, in MM/YY format", + "type": "string", + "example": "10/24" + }, + "bin": { + "description": "The BIN of the card, including the first 8 digits", + "type": "string", + "example": "44325280" + }, + "pin_status": { + "type": "string", + "description": "The current status of the card PIN", + "enum": [ + "not_set", + "ok" + ] + } + } + }, + "CardholderName": { + "description": "The name of the cardholder associated to the card. By default, this will be the name of the associated customer. To override the cardholder name, you can contact Bridge support.", + "type": "object", + "required": [ + "first_name", + "last_name" + ], + "properties": { + "first_name": { + "type": "string" + }, + "middle_name": { + "type": "string" + }, + "last_name": { + "type": "string" + } + } + }, + "CardFreezeInitiator": { + "type": "string", + "description": "The party that initiated the freeze. A freeze can be initiated by either the customer or developer. Only one freeze per initiator can be active at a time. If a new freeze is initiated by the same party, it overwrites any existing freeze", + "enum": [ + "developer", + "customer" + ] + }, + "CardFreezeReason": { + "type": "string", + "description": "The reason of the freeze", + "enum": [ + "lost_or_stolen", + "suspicious_activity", + "planned_inactivity", + "suspected_fraud", + "other" + ] + }, + "CardFreeze": { + "description": "Card freeze", + "required": [ + "card_account_id", + "initiator", + "reason", + "created_at", + "status" + ], + "properties": { + "card_account_id": { + "$ref": "#/components/schemas/Id", + "description": "Card account ID" + }, + "initiator": { + "$ref": "#/components/schemas/CardFreezeInitiator" + }, + "reason": { + "$ref": "#/components/schemas/CardFreezeReason" + }, + "reason_detail": { + "type": "string", + "description": "A more detailed reason for the freeze" + }, + "starting_at": { + "type": "string", + "description": "The start time of the freeze, in ISO8601 format" + }, + "ending_at": { + "type": "string", + "description": "The end time of the freeze, in ISO8601 format" + }, + "created_at": { + "type": "string", + "description": "The creation time of the freeze, in ISO8601 format", + "readOnly": true + } + } + }, + "CardCryptoAccount": { + "description": "The crypto account for a self-custodial card account. This field is not supported for a Bridge-custodial card funding setup (note that if you are on cards trial, you are automatically on a custodial funding setup).", + "required": [ + "type", + "address" + ], + "properties": { + "type": { + "type": "string", + "description": "The type of the crypto account", + "enum": [ + "standard", + "bridge_wallet", + "noncustodial_ata" + ] + }, + "address": { + "type": "string", + "description": "The public address of the crypto account" + } + } + }, + "CardAccountFundingInstructions": { + "description": "Funding instructions applicable only to the top-up card funding strategy, which is configured at the developer level", + "required": [ + "currency", + "chain", + "address" + ], + "properties": { + "currency": { + "$ref": "#/components/schemas/CardsCryptoCurrency", + "description": "The crypto currency used by the card account" + }, + "chain": { + "$ref": "#/components/schemas/OfframpChainForCards", + "description": "The chain used by the card account" + }, + "address": { + "type": "string", + "description": "The deposit address provided by Bridge to fund the card account" + }, + "memo": { + "type": "string", + "description": "If present, this is the message that the customer MUST include in their on-chain funding transfers. It is only applicable to memo-based blockchains such as Stellar and Tron" + } + } + }, + "CardWalletProvider": { + "type": "string", + "description": "The mobile wallet provider", + "enum": [ + "apple_pay", + "google_pay" + ] + }, + "CardAuthorization": { + "description": "A pending card authorization", + "required": [ + "id", + "amount", + "currency", + "merchant_category_code", + "description", + "authorized_at", + "details" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/Id", + "description": "ID of the pending authorization" + }, + "amount": { + "type": "string", + "description": "The amount represented as a decimal string" + }, + "billing_amount": { + "type": "string", + "description": "The billing amount, represented as a decimal string. The billing amount is the amount of the transaction excluding any additional hold. This amount should be present on all purchases, but will only differ from the amount field for some merchant categories in which an upcharge is involved (e.g. gas stations, hotels)." + }, + "currency": { + "$ref": "#/components/schemas/FiatCurrency", + "description": "The currency of the transaction" + }, + "merchant_category_code": { + "type": "string", + "description": "A merchant category code for card transactions (e.g., '5712')" + }, + "description": { + "type": "string", + "description": "A description of the card transaction, including the merchant's name and location information" + }, + "authorized_at": { + "type": "string", + "description": "Timestamp when the card transaction was authorized, in ISO8601 format" + }, + "details": { + "properties": { + "vendor_auth_id": { + "type": "string", + "description": "ID in the vendor system used to identify this authorized card transaction" + } + } + }, + "local_transaction_details": { + "$ref": "#/components/schemas/CardLocalTransactionDetails" + }, + "verification_data": { + "$ref": "#/components/schemas/CardAuthorizationVerificationData" + }, + "stripe_issuing_authorization_id": { + "type": "string", + "nullable": true, + "description": "The [Stripe Issuing authorization ID](https://docs.stripe.com/api/issuing/authorizations/object#issuing_authorization_object-id), if the authorization is backed by Stripe Issuing" + }, + "stripe_authorization_code": { + "type": "string", + "nullable": true, + "description": "The network-assigned [authorization code](https://docs.corp.stripe.com/api/issuing/authorizations/object#issuing_authorization_object-request_history-authorization_code) for this request, if the authorization is backed by Stripe Issuing" + } + } + }, + "CardTransaction": { + "description": "A posted transaction", + "required": [ + "id", + "category", + "amount", + "currency", + "description", + "posted_at" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/Id", + "description": "ID of the transaction" + }, + "card_account_id": { + "$ref": "#/components/schemas/Id", + "description": "ID of the card account associated to this transaction" + }, + "customer_id": { + "$ref": "#/components/schemas/Id", + "description": "ID of the customer of the card account associated to this transaction" + }, + "category": { + "type": "string", + "description": "The category of the transaction", + "enum": [ + "adjustment", + "fee", + "purchase", + "refund", + "crypto_funding", + "crypto_return", + "crypto_withdrawal" + ] + }, + "amount": { + "type": "string", + "description": "The amount represented as a decimal string" + }, + "billing_amount": { + "type": "string", + "description": "The billing amount, represented as a decimal string. The billing amount is the amount of the transaction excluding any additional hold. This amount should be present on all purchases, but will only differ from the amount field for some merchant categories in which an upcharge is involved (e.g. gas stations, hotels)." + }, + "currency": { + "type": "string", + "description": "The currency of the transaction", + "enum": [ + "usd", + "usdc" + ] + }, + "merchant_category_code": { + "type": "string", + "description": "The merchant category code, if applicable (e.g., '5712'). Always returned for transactions with category `purchase` or `refund`" + }, + "merchant_name": { + "type": "string", + "description": "The merchant name, if applicable. Always returned for transactions with category `purchase` or `refund`" + }, + "merchant_location": { + "type": "string", + "description": "The merchant location, if applicable. Always returned for transactions with category `purchase` or `refund`" + }, + "description": { + "type": "string", + "description": "The transaction description. It includes the merchant's name and location information for card transactions" + }, + "local_transaction_details": { + "$ref": "#/components/schemas/CardLocalTransactionDetails" + }, + "posted_at": { + "type": "string", + "description": "Timestamp when the transaction was posted, in ISO8601 format" + }, + "authorized_at": { + "type": "string", + "description": "Timestamp when the transaction was authorized, in ISO8601 format. Applicable only to transactions with category `purchase` or `refund` and always returned when applicable" + }, + "status": { + "type": "string", + "description": "The status of the transaction", + "enum": [ + "pending", + "posted" + ] + }, + "crypto_transaction_details": { + "$ref": "#/components/schemas/CardCryptoTransactionDetails" + }, + "related_transaction_ids": { + "type": "array", + "description": "IDs of related card transactions", + "items": { + "type": "string" + } + }, + "stripe_issuing_transaction_id": { + "type": "string", + "nullable": true, + "description": "The [Stripe Issuing transaction ID](https://docs.stripe.com/api/issuing/transactions/object?issuing_transaction_object-id), if the transaction is backed by Stripe Issuing" + } + } + }, + "CardCryptoTransactionDetails": { + "description": "Details of the underlying crypto transaction for crypto funding, withdrawal, or return transactions", + "properties": { + "from_address": { + "type": "string", + "description": "The source blockchain address of the crypto transaction. Present for crypto funding transactions" + }, + "to_address": { + "type": "string", + "description": "The destination blockchain address of the crypto transaction" + }, + "tx_hash": { + "type": "string", + "description": "The blockchain transaction hash" + }, + "chain": { + "type": "string", + "description": "The blockchain network on which the transaction occurred", + "enum": [ + "arbitrum", + "avalanche_c_chain", + "base", + "ethereum", + "optimism", + "polygon", + "solana", + "stellar", + "tron" + ] + }, + "memo": { + "type": "string", + "description": "An optional memo associated with the crypto transaction, if applicable" + } + } + }, + "CardLocalTransactionDetails": { + "description": "Details of a transaction processed in a local currency other than USD, with currency conversion applied", + "required": [ + "amount", + "currency", + "exchange_rate" + ], + "properties": { + "amount": { + "type": "string", + "description": "The amount in local currency, represented as a decimal string" + }, + "currency": { + "type": "string", + "description": "The transaction's local currency" + }, + "exchange_rate": { + "type": "string", + "description": "The exchange rate applied to convert the local currency amount into USD for the transaction" + } + } + }, + "CardAuthorizationVerificationData": { + "description": "Information on verifications that were performed on information that the cardholder provided to the merchant.", + "type": "object", + "properties": { + "address_check": { + "type": "string", + "description": "Whether the cardholder provided an address and if it matched the cardholder’s address on file.", + "enum": [ + "match", + "not_provided", + "mismatch" + ] + }, + "address_postal_code_check": { + "type": "string", + "description": "Whether the cardholder provided a postal code and if it matched the cardholder’s postal code on file.", + "enum": [ + "match", + "not_provided", + "mismatch" + ] + }, + "cvv_check": { + "type": "string", + "description": "Whether the cardholder provided a CVV and if it matched the CVV on record.", + "enum": [ + "match", + "not_provided", + "mismatch" + ] + }, + "pin_check": { + "type": "string", + "description": "Whether the cardholder provided a PIN and if it matched the PIN on record.", + "enum": [ + "verified", + "failed", + "locked", + "not_set", + "blocked", + "no_pin_passed", + "unknown" + ] + }, + "three_d_secure_check": { + "type": "string", + "description": "The results of the 3DS authentication attempt for this authorization, if applicable.", + "enum": [ + "attempt_acknowledged", + "authenticated", + "failed", + "required" + ] + } + } + }, + "CardWithdrawalDestination": { + "required": [ + "chain", + "address" + ], + "properties": { + "chain": { + "type": "string", + "description": "The chain of the wallet the withdrawn crypto funds should be transferred to" + }, + "address": { + "type": "string", + "description": "The address of the wallet the withdrawn crypto funds should be transferred to" + }, + "memo": { + "type": "string", + "description": "The memo to attach to the withdrawal transaction. Will be transmitted for blockchains that support memos only." + }, + "tx_hash": { + "type": "string", + "description": "The crypto transaction hash for the withdrawal once it's confirmed on the chain", + "readOnly": true + }, + "gas_fee": { + "$ref": "#/components/schemas/GasFee", + "description": "The gas fee for the withdrawal transaction. Note that this is the representation of the native gas fee of the onchain transaction, which may be different from the fiat-converted gas fee charged on the invoice." + } + } + }, + "GasFee": { + "description": "The gas fee for a crypto transaction", + "required": [ + "amount", + "currency" + ], + "properties": { + "amount": { + "type": "string", + "description": "The amount of the gas fee represented as a decimal string", + "readOnly": true + }, + "currency": { + "type": "string", + "description": "The currency of the gas fee.", + "readOnly": true + } + } + }, + "CardSpendingLimit": { + "description": "A spending limit for a card account", + "required": [ + "period", + "total_amount", + "remaining_amount" + ], + "properties": { + "period": { + "type": "string", + "description": "The period of the spending limit", + "enum": [ + "daily", + "trial_lifetime" + ] + }, + "timezone": { + "type": "string", + "description": "The timezone of the spending limit, only applicable to spending limits that have a `next_reset_at`" + }, + "next_reset_at": { + "type": "string", + "description": "The next reset time of the spending limit, in ISO8601 format" + }, + "total_amount": { + "type": "string", + "description": "The total amount of the spending limit" + }, + "remaining_amount": { + "type": "string", + "description": "The remaining amount of the spending limit" + }, + "currency": { + "$ref": "#/components/schemas/FiatCurrency", + "description": "The currency of the spending limit" + } + } + }, + "PostCardAccountDepositAddressInput": { + "description": "The details of the new deposit address to be provisioned.", + "required": [ + "chain" + ], + "properties": { + "chain": { + "type": "string", + "description": "The chain to provision the new deposit address on.", + "$ref": "#/components/schemas/OfframpChainForCards" + } + } + }, + "CardWithdrawal": { + "description": "A card funds withdrawal", + "required": [ + "id", + "card_account_id", + "customer_id", + "amount", + "currency", + "destination", + "created_at", + "updated_at" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/Id", + "description": "ID of the withdrawal", + "readOnly": true + }, + "card_account_id": { + "$ref": "#/components/schemas/Id", + "description": "ID of the card account associated with the withdrawal", + "readOnly": true + }, + "customer_id": { + "$ref": "#/components/schemas/Id", + "description": "ID of the customer who owns the card account", + "readOnly": true + }, + "amount": { + "type": "string", + "description": "The amount represented as a decimal string" + }, + "type": { + "type": "string", + "description": "The type of the withdrawal. Defaults to `top_up_balance_withdrawal`.", + "enum": [ + "top_up_balance_withdrawal", + "fee" + ] + }, + "currency": { + "$ref": "#/components/schemas/CardsCryptoCurrency", + "description": "The currency of the withdrawal, which is the crypto currency on the card account", + "readOnly": true + }, + "destination": { + "$ref": "#/components/schemas/CardWithdrawalDestination" + }, + "client_note": { + "type": "string", + "description": "An optional client-provided note for the withdrawal" + }, + "created_at": { + "type": "string", + "description": "Timestamp when the withdrawal was created, in ISO8601 format", + "readOnly": true + }, + "updated_at": { + "type": "string", + "description": "Timestamp when the withdrawal was last updated, in ISO8601 format", + "readOnly": true + } + } + }, + "CardPinUpdateResponse": { + "description": "Response containing a secure URL to update a card's PIN", + "type": "object", + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "format": "uri", + "description": "Single-use, time-limited URL that can be used to securely update the card PIN in an iframe", + "example": "https://secure.example.com/update-pin?token=xyz789" + } + } + }, + "CardProgramSummary": { + "description": "The summary of a card program for a given period", + "type": "object", + "properties": { + "period": { + "type": "string", + "description": "The period type of the card program summary", + "enum": [ + "year", + "month", + "week", + "day", + "lifetime" + ] + }, + "period_starting": { + "type": "string", + "description": "The starting date of the period, in ISO8601 format", + "example": "2025-01-01" + }, + "cards_provisioned_count": { + "type": "integer", + "description": "The number of cards provisioned during the period", + "example": 1123 + }, + "card_transactions_count": { + "type": "integer", + "description": "The number of card transactions during the period, excluding refunds.", + "example": 31415 + }, + "provisioned_cards_by_country": { + "type": "object", + "description": "The number of cards provisioned during the period, by issuing country. The key is the ISO-3166-1 alpha-3 country code, and the value is the number of cards provisioned for that issuing country.", + "example": { + "USA": 123, + "MEX": 45 + } + }, + "transaction_volume": { + "type": "string", + "description": "The total transaction volume during the period, in USD", + "example": "-100.0" + }, + "transacting_card_accounts_count": { + "type": "integer", + "description": "The number of card accounts that transacted during the period", + "example": 2047 + }, + "card_transactions_count_by_country": { + "type": "object", + "description": "The number of card transactions during the period, by merchant country. The key is the ISO-3166-1 alpha-3 country code, and the value is the number of card transactions for that merchant country.", + "example": { + "USA": 74, + "MEX": 55 + } + }, + "transaction_volume_by_country": { + "type": "object", + "description": "The transaction volume during the period, by merchant country. The key is the ISO-3166-1 alpha-3 country code, and the value is the transaction volume for that merchant country.", + "example": { + "USA": "7.04", + "MEX": "5.0" + } + }, + "transacting_cards_by_country": { + "type": "object", + "description": "The number of cards that transacted during the period, by issuing country. The key is the ISO-3166-1 alpha-3 country code, and the value is the number of cards transacted for that issuing country.", + "example": { + "USA": 123, + "MEX": 45 + } + } + } + }, + "CardDesigns": { + "description": "A listing of the designs that you can use to issue a card with.", + "type": "object", + "properties": { + "card_designs": { + "type": "array", + "description": "A listing of the designs that you can use to issue a card with.", + "items": { + "type": "object", + "properties": { + "shortname": { + "type": "string", + "description": "The shortname of the card design. You can pass this into the `card_design_shortname` parameter when creating a card account." + }, + "type": { + "type": "string", + "description": "The type of card that the design applies to", + "enum": [ + "virtual", + "physical" + ] + } + } + } + }, + "default_card_design_shortname": { + "type": "string", + "description": "The shortname of the default card design" + } + } + }, + "CustomerRewardSummary": { + "title": "Customer Reward Summary for a given stablecoin", + "type": "object", + "properties": { + "developer_id": { + "type": "string", + "description": "The developer ID of the customer" + }, + "customer_id": { + "type": "string", + "description": "The customer ID of the customer" + }, + "currency": { + "type": "string", + "description": "The stablecoin symbol for the reward summary" + }, + "balance": { + "type": "string", + "description": "The balance of the customer in the given stablecoin" + }, + "rewards": { + "type": "string", + "description": "The rewards of the customer in the given stablecoin" + }, + "updated_at": { + "type": "string", + "description": "The timestamp of the last update to the reward summary, in ISO8601 format" + } + } + }, + "DeveloperRewardSummary": { + "title": "Reward Summary for a given stablecoin", + "type": "object", + "properties": { + "developer_id": { + "type": "string", + "description": "The developer ID of the developer" + }, + "currency": { + "type": "string", + "description": "The stablecoin symbol for the reward summary" + }, + "balance": { + "type": "string", + "description": "The balance of the developer in the given stablecoin" + }, + "rewards": { + "type": "string", + "description": "The rewards of the developer in the given stablecoin" + }, + "updated_at": { + "type": "string", + "description": "The timestamp of the last update to the reward summary, in ISO8601 format" + } + } + }, + "CustomerRewardHistory": { + "title": "Customer Reward History for a given stablecoin", + "type": "object", + "properties": { + "customer_id": { + "type": "string", + "description": "The customer ID of the customer" + }, + "rewards": { + "type": "array", + "description": "The rewards of the customer in the given stablecoin", + "items": { + "type": "object", + "properties": { + "balance": { + "type": "string", + "description": "The balance of the customer in the given stablecoin" + }, + "amount": { + "type": "string", + "description": "The amount of the reward" + }, + "currency": { + "type": "string", + "description": "The stablecoin symbol for the reward summary" + }, + "date": { + "type": "string", + "description": "The date of the calculated reward" + } + } + } + } + } + }, + "DeveloperRewardHistory": { + "title": "Developer Daily Reward History", + "type": "object", + "properties": { + "currency": { + "type": "string", + "description": "The stablecoin symbol" + }, + "developer_id": { + "type": "string", + "description": "The developer ID" + }, + "reserves_currency": { + "type": "string", + "description": "The denomination currency for all monetary amounts" + }, + "data": { + "type": "array", + "items": { + "type": "object", + "properties": { + "date": { + "type": "string", + "description": "The reward calculation date (YYYY-MM-DD)" + }, + "distributed": { + "type": "boolean", + "description": "Whether rewards for this date have been distributed" + }, + "total": { + "type": "object", + "properties": { + "aum": { + "type": "string", + "description": "Developer AUM across all providers" + }, + "developer_rewards": { + "type": "string", + "description": "Gross rewards (net of premint yield)" + }, + "net_rewards": { + "type": "string", + "description": "Net rewards after fees" + }, + "bridge_fee_bps": { + "type": "string", + "description": "Effective fee rate for that day" + }, + "bridge_fee": { + "type": "string", + "description": "Fee amount for that day" + }, + "annualized_yield_bps": { + "type": "string", + "description": "Blended annualized yield across providers" + } + } + }, + "providers": { + "type": "array", + "items": { + "type": "object", + "properties": { + "provider": { + "type": "string", + "description": "Provider identifier" + }, + "aum": { + "type": "string", + "description": "Developer AUM held at this provider" + }, + "developer_rewards": { + "type": "string", + "description": "Gross rewards from this provider" + }, + "annualized_yield_bps": { + "type": "string", + "description": "Annualized yield rate for this provider" + } + } + } + } + } + } + }, + "pagination": { + "type": "object", + "properties": { + "has_more": { + "type": "boolean", + "description": "Whether more pages are available" + }, + "next_cursor": { + "type": "string", + "nullable": true, + "description": "Cursor for the next page" + } + } + } + } + } + }, + "parameters": { + "AssociatedPersonIDParameter": { + "name": "associatedPersonID", + "in": "path", + "description": "Unique identifier for an associated person", + "required": true, + "schema": { + "$ref": "#/components/schemas/Id" + } + }, + "BridgeWalletIDParameter": { + "name": "bridgeWalletID", + "in": "path", + "required": true, + "schema": { + "$ref": "#/components/schemas/Id" + } + }, + "CustomerIDParameter": { + "name": "customerID", + "in": "path", + "required": true, + "schema": { + "$ref": "#/components/schemas/Id" + } + }, + "TemplateIDParameter": { + "name": "template_id", + "in": "query", + "required": false, + "schema": { + "$ref": "#/components/schemas/Id" + }, + "description": "This is a template id. If this is specified, the transfers with the specified template id will be returned." + }, + "TransferIDParameter": { + "name": "transferID", + "in": "path", + "required": true, + "schema": { + "$ref": "#/components/schemas/Id" + } + }, + "TransferStateParameter": { + "name": "state", + "in": "query", + "required": false, + "schema": { + "type": "string", + "enum": [ + "awaiting_funds", + "funds_received", + "payment_submitted", + "payment_processed", + "in_review", + "kyc_required", + "kyc_in_review", + "developer_kyb_required", + "canceled", + "error", + "returned", + "refund_in_flight", + "refund_failed", + "refunded", + "undeliverable" + ] + }, + "description": "Filter transfers by their external state. See [Transfer States](https://apidocs.bridge.xyz/platform/orchestration/transfers/transfer-states) for more details." + }, + "VirtualAccountIDParameter": { + "name": "virtualAccountID", + "in": "path", + "required": true, + "schema": { + "$ref": "#/components/schemas/Id" + } + }, + "StaticMemoIDParameter": { + "name": "staticMemoID", + "in": "path", + "required": true, + "schema": { + "$ref": "#/components/schemas/Id" + } + }, + "PrefundedAccountIDParameter": { + "name": "prefundedAccountID", + "in": "path", + "required": true, + "schema": { + "$ref": "#/components/schemas/Id" + } + }, + "DeveloperFeeConfigIDParameter": { + "name": "developerFeeConfigID", + "in": "path", + "required": true, + "schema": { + "$ref": "#/components/schemas/Id" + } + }, + "DeveloperFeeConfigStartingAfterParameter": { + "in": "query", + "name": "starting_after", + "schema": { + "type": "string" + }, + "description": "This is a developer fee config id. If this is specified, the next page that starts with a developer fee config right AFTER the specified developer fee config id on the developer fee config timeline, which is always ordered from the newest to the oldest by creation time, will be returned. This also implies that developer fee configs older than the specified developer fee config id will be returned (shouldn't be set if ending_before is set)" + }, + "DeveloperFeeConfigEndingBeforeParameter": { + "in": "query", + "name": "ending_before", + "schema": { + "type": "string" + }, + "description": "This is a developer fee config id. If this is specified, the previous page that ends with a developer fee config right BEFORE the specified developer fee config id on the developer fee config timeline, which is always ordered from the newest to the oldest by creation time, will be returned. This also implies that developer fee configs newer than the specified developer fee config id will be returned (shouldn't be set if starting_after is set)" + }, + "CustomerIDQueryParameter": { + "name": "customer_id", + "in": "query", + "required": false, + "schema": { + "type": "string" + }, + "description": "If specified, results will be filtered to the given customer_id only" + }, + "DrainIDQueryParameter": { + "name": "drain_id", + "in": "query", + "required": false, + "schema": { + "type": "string" + }, + "description": "If specified, results will be filtered to the given drain id only" + }, + "DepositIDQueryParameter": { + "name": "deposit_id", + "in": "query", + "required": false, + "schema": { + "type": "string" + }, + "description": "The deposit id associated with the events. Cannot be passed if deposit_ids is also passed" + }, + "DepositIDsQueryParameter": { + "name": "deposit_ids", + "in": "query", + "required": false, + "schema": { + "type": "array", + "items": { + "type": "string" + } + }, + "description": "The deposit ids associated with the events. Pass a list of deposit ids like \"deposit_ids[]=id1&deposit_ids[]=id2\". Cannot be passed if deposit_id is also passed" + }, + "TxHashParameter": { + "name": "tx_hash", + "in": "query", + "required": false, + "schema": { + "type": "string" + }, + "description": "The hash of the transaction" + }, + "EventTypeParameter": { + "name": "event_type", + "in": "query", + "required": false, + "schema": { + "type": "string", + "enum": [ + "funds_received", + "payment_submitted", + "payment_processed", + "in_review", + "refund", + "refund_in_flight", + "refund_failed", + "microdeposit", + "account_update", + "deactivation", + "activation" + ] + }, + "description": "Filter history by event type" + }, + "PayinIDParameter": { + "name": "payinID", + "in": "path", + "required": true, + "schema": { + "$ref": "#/components/schemas/Id" + } + }, + "PayoutIDParameter": { + "name": "payoutID", + "in": "path", + "required": true, + "schema": { + "$ref": "#/components/schemas/Id" + } + }, + "ExternalAccountIDParameter": { + "name": "externalAccountID", + "in": "path", + "required": true, + "schema": { + "$ref": "#/components/schemas/Id" + } + }, + "LiquidationAddressIDParameter": { + "name": "liquidationAddressID", + "in": "path", + "required": true, + "schema": { + "$ref": "#/components/schemas/Id" + } + }, + "IdempotencyKeyParameter": { + "in": "header", + "name": "Idempotency-Key", + "required": true, + "schema": { + "type": "string" + } + }, + "CustomerEmailParameter": { + "in": "query", + "name": "email", + "required": false, + "schema": { + "type": "string" + }, + "description": "If included, filters to customers with the given email" + }, + "LimitParameter": { + "in": "query", + "name": "limit", + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 10 + }, + "description": "The number of items to return (min 1, default 10, max 100)" + }, + "TransferStartingAfterParameter": { + "in": "query", + "name": "starting_after", + "schema": { + "type": "string" + }, + "description": "This is a transfer id. If this is specified, the next page that starts with a transfer right AFTER the specified transfer id on the transfer timeline, which is always ordered from the newest to the oldest by creation time, will be returned. This also implies that transfers older than the specified transfer id will be returned (shouldn't be set if ending_before is set)" + }, + "TransferEndingBeforeParameter": { + "in": "query", + "name": "ending_before", + "schema": { + "type": "string" + }, + "description": "This is a transfer id. If this is specified, the previous page that ends with a transfer right BEFORE the specified transfer id on the transfer timeline, which is always ordered from the newest to the oldest by creation time, will be returned. This also implies that transfers newer than the specified transfer id will be returned (shouldn't be set if starting_after is set)" + }, + "LiquidationScheduleStartingAfterParameter": { + "in": "query", + "name": "starting_after", + "schema": { + "type": "string" + }, + "description": "This is a liquidation address id. If this is specified, the next page that starts with a liquidation address right AFTER the specified liquidation address id on the liquidation address timeline, which is always ordered from the newest to the oldest by creation time, will be returned. This also implies that liquidation address older than the specified liquidation address id will be returned (shouldn't be set if ending_before is set)" + }, + "LiquidationScheduleEndingBeforeParameter": { + "in": "query", + "name": "ending_before", + "schema": { + "type": "string" + }, + "description": "This is a liquidation address id. If this is specified, the previous page that ends with a liquidation address right BEFORE the specified liquidation address id on the liquidation address timeline, which is always ordered from the newest to the oldest by creation time, will be returned. This also implies that liquidation address newer than the specified liquidation address id will be returned (shouldn't be set if starting_after is set)" + }, + "StaticMemoStartingAfterParameter": { + "in": "query", + "name": "starting_after", + "schema": { + "type": "string" + }, + "description": "This is a static memo id. If this is specified, the next page that starts with a static memo right AFTER the specified static memo id on the static memo timeline, which is always ordered from the newest to the oldest by creation time, will be returned. This also implies that static memo older than the specified static memo id will be returned (shouldn't be set if ending_before is set)" + }, + "StaticMemoEndingBeforeParameter": { + "in": "query", + "name": "ending_before", + "schema": { + "type": "string" + }, + "description": "This is a static memo id. If this is specified, the previous page that ends with a static memo right BEFORE the specified static memo id on the static memo timeline, which is always ordered from the newest to the oldest by creation time, will be returned. This also implies that static memo newer than the specified static memo id will be returned (shouldn't be set if starting_after is set)" + }, + "VirtualAccountStartingAfterParameter": { + "in": "query", + "name": "starting_after", + "schema": { + "type": "string" + }, + "description": "This is a virtual account id. If this is specified, the next page that starts with a virtual account right AFTER the specified virtual account id on the virtual account timeline, which is always ordered from the newest to the oldest by creation time, will be returned. This also implies that virtual account older than the specified virtual account id will be returned (shouldn't be set if ending_before is set)" + }, + "VirtualAccountEndingBeforeParameter": { + "in": "query", + "name": "ending_before", + "schema": { + "type": "string" + }, + "description": "This is a virtual account id. If this is specified, the previous page that ends with a virtual account right BEFORE the specified virtual account id on the virtual account timeline, which is always ordered from the newest to the oldest by creation time, will be returned. This also implies that virtual account newer than the specified virtual account id will be returned (shouldn't be set if starting_after is set)" + }, + "ExternalAccountStartingAfterParameter": { + "in": "query", + "name": "starting_after", + "schema": { + "type": "string" + }, + "description": "This is an external account id. If this is specified, the next page that starts with an external account right AFTER the specified external account id on the external account timeline, which is always ordered from the newest to the oldest by creation time, will be returned. This also implies that external accounts older than the specified external account id will be returned (shouldn't be set if ending_before is set)" + }, + "ExternalAccountEndingBeforeParameter": { + "in": "query", + "name": "ending_before", + "schema": { + "type": "string" + }, + "description": "This is an external account id. If this is specified, the previous page that ends with an external account right BEFORE the specified external account id on the external account timeline, which is always ordered from the newest to the oldest by creation time, will be returned. This also implies that external accounts newer than the specified external account id will be returned (shouldn't be set if starting_after is set)" + }, + "UpdatedAfterMsParameter": { + "in": "query", + "name": "updated_after_ms", + "schema": { + "type": "integer" + }, + "description": "This is a unix timestamp in milliseconds. If this is specified, objects updated AFTER the specified timestamp will be returned" + }, + "UpdatedBeforeMsParameter": { + "in": "query", + "name": "updated_before_ms", + "schema": { + "type": "integer" + }, + "description": "This is a unix timestamp in milliseconds. If this is specified, objects updated BEFORE the specified timestamp will be returned" + }, + "CustomerStartingAfterParameter": { + "in": "query", + "name": "starting_after", + "schema": { + "type": "string" + }, + "description": "This is a customer id. If this is specified, the next page that starts with a customer right AFTER the specified customer id on the customer timeline, which is always ordered from the newest to the oldest by creation time, will be returned. This also implies that customers older than the specified customer id will be returned (shouldn't be set if ending_before is set)" + }, + "CustomerEndingBeforeParameter": { + "in": "query", + "name": "ending_before", + "schema": { + "type": "string" + }, + "description": "This is a customer id. If this is specified, the previous page that ends with a customer right BEFORE the specified customer id on the customer timeline, which is always ordered from the newest to the oldest by creation time, will be returned. This also implies that customers newer than the specified customer id will be returned (shouldn't be set if starting_after is set)" + }, + "DrainStartingAfterParameter": { + "in": "query", + "name": "starting_after", + "schema": { + "type": "string" + }, + "description": "This is a drain id. If this is specified, the next page that starts with a drain right AFTER the specified drain id on the drain timeline, which is always ordered from the newest to the oldest by creation time, will be returned. This also implies that drains older than the specified drain id will be returned (shouldn't be set if ending_before is set)" + }, + "DrainEndingBeforeParameter": { + "in": "query", + "name": "ending_before", + "schema": { + "type": "string" + }, + "description": "This is a drain id. If this is specified, the previous page that ends with a drain right BEFORE the specified drain id on the drain timeline, which is always ordered from the newest to the oldest by creation time, will be returned. This also implies that drains newer than the specified drain id will be returned (shouldn't be set if starting_after is set)" + }, + "EventStartingAfterParameter": { + "in": "query", + "name": "starting_after", + "schema": { + "type": "string" + }, + "description": "This is an event id. If this is specified, the next page that starts with an event right AFTER the specified event id on the event timeline, which is always ordered from the newest to the oldest by creation time, will be returned. This also implies that events older than the specified event id will be returned (shouldn't be set if ending_before is set)" + }, + "EventEndingBeforeParameter": { + "in": "query", + "name": "ending_before", + "schema": { + "type": "string" + }, + "description": "This is an event id. If this is specified, the previous page that ends with an event right BEFORE the specified event id on the event timeline, which is always ordered from the newest to the oldest by creation time, will be returned. This also implies that events newer than the specified event id will be returned (shouldn't be set if starting_after is set)" + }, + "PrefundedAccountHistoryStartingAfterParameter": { + "in": "query", + "name": "starting_after", + "schema": { + "type": "string" + }, + "description": "This is a prefunded event id. If this is specified, the next page that starts with an event right AFTER the specified event id on the event timeline, which is always ordered from the newest to the oldest by creation time, will be returned. This also implies that events older than the specified event id will be returned (shouldn't be set if ending_before is set)" + }, + "PrefundedAccountHistoryEndingBeforeParameter": { + "in": "query", + "name": "ending_before", + "schema": { + "type": "string" + }, + "description": "This is a prefunded event id. If this is specified, the previous page that ends with an event right BEFORE the specified event id on the event timeline, which is always ordered from the newest to the oldest by creation time, will be returned. This also implies that events newer than the specified event id will be returned (shouldn't be set if starting_after is set)" + }, + "BridgeWalletHistoryStartingAfterParameter": { + "in": "query", + "name": "starting_after", + "schema": { + "type": "string" + }, + "description": "This is a bridge wallet event id. If this is specified, the next page that starts with an event right AFTER the specified event id on the event timeline, which is always ordered from the newest to the oldest by creation time, will be returned. This also implies that events older than the specified event id will be returned (shouldn't be set if ending_before is set)" + }, + "BridgeWalletHistoryEndingBeforeParameter": { + "in": "query", + "name": "ending_before", + "schema": { + "type": "string" + }, + "description": "This is a bridge wallet event id. If this is specified, the previous page that ends with an event right BEFORE the specified event id on the event timeline, which is always ordered from the newest to the oldest by creation time, will be returned. This also implies that events newer than the specified event id will be returned (shouldn't be set if starting_after is set)" + }, + "BridgeWalletHistoryStartingTimeParameter": { + "in": "query", + "name": "starting_time", + "required": false, + "schema": { + "type": "string" + }, + "description": "The inclusive starting time in ISO8601 format. If specified, only Bridge Wallet history events created at or after this time are returned. Can be combined with ending_time to form a bounded time window or with an event ID cursor to paginate within the filtered results." + }, + "BridgeWalletHistoryEndingTimeParameter": { + "in": "query", + "name": "ending_time", + "required": false, + "schema": { + "type": "string" + }, + "description": "The exclusive ending time in ISO8601 format. If specified, only Bridge Wallet history events created before this time are returned. Can be combined with starting_time to form a bounded time window or with an event ID cursor to paginate within the filtered results." + }, + "WithdrawalStartingAfterParameter": { + "in": "query", + "name": "starting_after", + "schema": { + "type": "string" + }, + "description": "This is a withdrawal id. If this is specified, the next page that starts with a withdrawal right AFTER the specified id on the timeline, which is always ordered from the newest to the oldest by creation time, will be returned. This also implies that withdrawals older than the specified id will be returned (shouldn't be set if `ending_before` is set)" + }, + "WithdrawalEndingBeforeParameter": { + "in": "query", + "name": "ending_before", + "schema": { + "type": "string" + }, + "description": "This is a withdrawal id. If this is specified, the previous page that ends with a withdrawal right BEFORE the specified id on the timeline, which is always ordered from the newest to the oldest by creation time, will be returned. This also implies that withdrawals newer than the specified id will be returned (shouldn't be set if `starting_after` is set)" + }, + "FundsRequestStartingAfterParameter": { + "in": "query", + "name": "starting_after", + "schema": { + "type": "string" + }, + "description": "This is a funds request id. If this is specified, the next page that starts with a funds request right AFTER the specified id on the timeline, which is always ordered from the newest to the oldest by creation time, will be returned. This also implies that funds request older than the specified funds request id will be returned (shouldn't be set if `ending_before` is set)" + }, + "FundsRequestEndingBeforeParameter": { + "in": "query", + "name": "ending_before", + "schema": { + "type": "string" + }, + "description": "This is a funds request id. If this is specified, the previous page that ends with a funds request right BEFORE the specified id on the timeline, which is always ordered from the newest to the oldest by creation time, will be returned. This also implies that funds request newer than the specified funds request id will be returned (shouldn't be set if `starting_after` is set)" + }, + "RfiStartingAfterParameter": { + "in": "query", + "name": "starting_after", + "schema": { + "type": "string" + }, + "description": "This is an RFI id. If this is specified, the next page that starts with an RFI right AFTER the specified id on the timeline, which is always ordered from the newest to the oldest by creation time, will be returned. This also implies that RFIs older than the specified RFI id will be returned (shouldn't be set if `ending_before` is set)" + }, + "RfiEndingBeforeParameter": { + "in": "query", + "name": "ending_before", + "schema": { + "type": "string" + }, + "description": "This is an RFI id. If this is specified, the previous page that ends with an RFI right BEFORE the specified id on the timeline, which is always ordered from the newest to the oldest by creation time, will be returned. This also implies that RFIs newer than the specified RFI id will be returned (shouldn't be set if `starting_after` is set)" + }, + "EndorsementParameter": { + "in": "query", + "name": "endorsement", + "required": false, + "schema": { + "type": "string", + "enum": [ + "sepa", + "spei", + "cards" + ] + }, + "description": "An endorsement is the approval required for a customer to use a particular product or service offered by Bridge" + }, + "RedirectUriParameter": { + "in": "query", + "name": "redirect_uri", + "required": false, + "schema": { + "type": "string", + "example": "http%3A%2F%2Fexample.com%2Fredirect" + }, + "description": "An optional url encoded link that users will be redirected to after completing the hosted KYC flow." + }, + "WebhookIDParameter": { + "name": "webhookID", + "in": "path", + "required": true, + "schema": { + "$ref": "#/components/schemas/Id" + } + }, + "KycLinkIDParameter": { + "name": "kycLinkID", + "in": "path", + "required": true, + "schema": { + "$ref": "#/components/schemas/Id" + } + }, + "RfiIDParameter": { + "name": "rfiID", + "in": "path", + "required": true, + "schema": { + "$ref": "#/components/schemas/Id" + } + }, + "RfiStateParameter": { + "name": "state", + "in": "query", + "required": false, + "schema": { + "type": "string", + "enum": [ + "on_developer", + "on_bridge", + "closed" + ] + }, + "description": "If specified, results will be filtered to RFIs with the given state only" + }, + "KycLinksEmailParameter": { + "name": "email", + "in": "query", + "required": false, + "schema": { + "type": "string" + }, + "description": "If included, filters to KYC links for the customer with the given email" + }, + "KycLinksCustomerIDParameter": { + "name": "customer_id", + "in": "query", + "required": false, + "schema": { + "type": "string" + }, + "description": "If included, filters to KYC links for the customer with the given id" + }, + "FiatInstructionsActivationStatusParameter": { + "in": "query", + "required": false, + "name": "status", + "description": "Limit results to those with the given activation status", + "example": "activated", + "schema": { + "$ref": "#/components/schemas/VirtualAccountActivationStatus" + } + }, + "CardAccountIDParameter": { + "name": "cardAccountID", + "in": "path", + "required": true, + "schema": { + "$ref": "#/components/schemas/Id" + } + }, + "CardTransactionIDParameter": { + "name": "transactionID", + "in": "path", + "required": true, + "schema": { + "$ref": "#/components/schemas/Id" + } + }, + "CardWithdrawalIDParameter": { + "name": "cardWithdrawalID", + "in": "path", + "required": true, + "schema": { + "$ref": "#/components/schemas/Id" + } + }, + "StartingTimeParameter": { + "in": "query", + "name": "starting_time", + "required": false, + "schema": { + "type": "string" + }, + "description": "The starting time in ISO8601 format. Default is 50 days ago." + }, + "EndingTimeParameter": { + "in": "query", + "name": "ending_time", + "required": false, + "schema": { + "type": "string" + }, + "description": "The exclusive ending time in ISO8601 format. Default is now." + }, + "PageSizeParameter": { + "in": "query", + "name": "page_size", + "required": false, + "schema": { + "type": "string" + }, + "description": "The max number of items to return for the requested page, with a max of 200. The default is 100" + }, + "PageNumberParameter": { + "in": "query", + "name": "page", + "required": false, + "schema": { + "type": "string" + }, + "description": "A specific page to fetch. If omitted, the first page (starting at 1) will be returned. Note that this is only supported for navigating posted transactions." + }, + "CardAuthorizationStatusParameter": { + "in": "query", + "name": "status", + "required": false, + "schema": { + "type": "string", + "enum": [ + "approved", + "denied" + ] + }, + "style": "form", + "description": "A status to filter the authorizations by. If not provided, will default to `approved`." + }, + "CardTransactionStatusParameter": { + "in": "query", + "name": "status", + "required": false, + "schema": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "pending", + "posted" + ] + } + }, + "style": "form", + "explode": true, + "description": "A status to filter the transactions by. If not provided, will default to `posted`." + }, + "CardTransactionPaginationTokenParameter": { + "in": "query", + "name": "pagination_token", + "required": false, + "schema": { + "type": "string" + }, + "description": "A pagination token to fetch the next page of transactions." + }, + "CardTransactionCategoryFamilyParameter": { + "in": "query", + "name": "category_family", + "required": false, + "schema": { + "type": "string", + "enum": [ + "cards", + "crypto" + ] + }, + "description": "A category family to filter the transactions by. If set to `cards`, only card purchase related transactions will be returned. If set to `crypto`, only funding related transactions will be returned.` If not provided, all posted transactions will be returned." + }, + "CardAuthorizationLimitParameter": { + "in": "query", + "name": "limit", + "schema": { + "type": "integer" + }, + "description": "The number of pending card authorizations to return, with a max of 200. The default is 100" + }, + "CardTransactionLimitParameter": { + "in": "query", + "name": "limit", + "schema": { + "type": "integer" + }, + "description": "The number of transactions to return, with a max of 200. The default is 100" + }, + "CardStatementPeriodParameter": { + "in": "path", + "name": "period", + "required": true, + "schema": { + "type": "string" + }, + "description": "A string in the `YYYYMM` format representing a card statement period" + }, + "CardProgramSummaryPeriodParameter": { + "in": "query", + "name": "period", + "required": true, + "schema": { + "type": "string", + "enum": [ + "year", + "month", + "week", + "day", + "lifetime" + ] + }, + "description": "The type of period to summarize the card program by. If `lifetime` is specified, the `period_key` is not required." + }, + "CardProgramSummaryPeriodKeyParameter": { + "in": "query", + "name": "period_key", + "schema": { + "type": "string" + }, + "description": "A string to indicate the period to retrieve the card program summary for.\n- For `year`, the period key should be in the `YYYY` format\n- For `month`, the period key should be in the `YYYYMM` format\n- For `week`, the period key should be in the `YYYYMMDD` format indicating the beginning day of the week.\n- For `day`, the period key should be in the `YYYYMMDD` format\n- For `lifetime`, the period key is not required\nNote that if a specific period is specified, this endpoint currently only supports fetching for periods with complete data (e.g. only up to the previous year, month, week, or day).\n" + }, + "BridgeWalletStartingAfterParameter": { + "in": "query", + "name": "starting_after", + "schema": { + "type": "string" + }, + "description": "This is a bridge wallet id. If this is specified, the next page that starts with a bridge wallet right AFTER the specified bridge wallet id on the bridge wallet timeline, which is always ordered from the newest to the oldest by creation time, will be returned. This also implies that bridge wallets older than the specified bridge wallet id will be returned (shouldn't be set if ending_before is set)" + }, + "BridgeWalletEndingBeforeParameter": { + "in": "query", + "name": "ending_before", + "schema": { + "type": "string" + }, + "description": "This is a bridge wallet id. If this is specified, the previous page that ends with a bridge wallet right BEFORE the specified bridge wallet id on the bridge wallet timeline, which is always ordered from the newest to the oldest by creation time, will be returned. This also implies that bridge wallets newer than the specified bridge wallet id will be returned (shouldn't be set if starting_after is set)" + }, + "RewardCurrencyParameter": { + "in": "path", + "name": "currency", + "required": true, + "schema": { + "type": "string" + }, + "description": "The stablecoin symbol" + }, + "FraudParameter": { + "in": "query", + "name": "fraud", + "required": false, + "schema": { + "type": "boolean" + }, + "description": "If this is specified as either \"true\" or \"false\", then only fraudulent or non-fraudulent entries will be returned, respectively" + }, + "NoticeDateStartingOnParameter": { + "in": "query", + "name": "notice_date_starting_on", + "required": false, + "schema": { + "type": "string" + }, + "description": "A date in the format YYYY-MM-DD. If specified, then only entries with a notice date on or after the provided date, inclusive, will be returned" + }, + "NoticeDateEndingOnParameter": { + "in": "query", + "name": "notice_date_ending_on", + "required": false, + "schema": { + "type": "string" + }, + "description": "A date in the format YYYY-MM-DD. If specified, then only entries with a notice date on or before the provided date, inclusive, will be returned" + } + }, + "responses": { + "BridgeWalletHistoryResponse": { + "description": "List of transactions for this Bridge Wallet", + "content": { + "application/json": { + "schema": { + "title": "Bridge Wallet History", + "type": "object", + "required": [ + "count", + "data" + ], + "properties": { + "count": { + "type": "integer", + "description": "The number of events returned" + }, + "data": { + "type": "array", + "minItems": 0, + "items": { + "$ref": "#/components/schemas/BridgeWalletEventResponse" + } + } + } + }, + "examples": { + "WithdrawalBridgeWalletEvent": { + "$ref": "#/components/examples/WithdrawalBridgeWalletEvent" + }, + "DepositDrainBridgeWalletEvent": { + "$ref": "#/components/examples/DepositDrainBridgeWalletEvent" + }, + "DepositStaticMemoEventBridgeWalletEvent": { + "$ref": "#/components/examples/DepositStaticMemoEventBridgeWalletEvent" + }, + "DepositVirtualAccountEventBridgeWalletEvent": { + "$ref": "#/components/examples/DepositVirtualAccountEventBridgeWalletEvent" + }, + "DepositTransferBridgeWalletEvent": { + "$ref": "#/components/examples/DepositTransferBridgeWalletEvent" + }, + "DirectDepositBridgeWalletEvent": { + "$ref": "#/components/examples/DirectDepositBridgeWalletEvent" + }, + "ReturnBridgeWalletEvent": { + "$ref": "#/components/examples/ReturnBridgeWalletEvent" + }, + "UndeliverableBridgeWalletEvent": { + "$ref": "#/components/examples/UndeliverableBridgeWalletEvent" + }, + "CardSpendBridgeWalletEvent": { + "$ref": "#/components/examples/CardSpendBridgeWalletEvent" + }, + "CardRefundBridgeWalletEvent": { + "$ref": "#/components/examples/CardRefundBridgeWalletEvent" + } + } + } + } + }, + "BadRequestError": { + "description": "Request containing missing or invalid parameters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "BadCustomerRequestErrorExample": { + "summary": "Bad customer request", + "value": { + "code": "bad_customer_request", + "message": "fields missing from customer body.", + "name": "first_name,ssn" + } + } + } + } + } + }, + "DeveloperFeeConfigBadRequestError": { + "description": "Request containing missing or invalid fee config parameters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "InvalidDefaultFeePercentageErrorExample": { + "summary": "Invalid default_fee_percentage", + "value": { + "code": "bad_request", + "message": "default_fee_percentage must be between [0.01, 100)" + } + }, + "InvalidSourceAssetFeeCurrencyErrorExample": { + "summary": "Unrecognized source_asset_fee currency", + "value": { + "code": "bad_request", + "message": "unrecognized currency: xyz" + } + } + } + } + } + }, + "ResourceStateConflictError": { + "description": "The requested resource is temporarily in a conflicting state. Retry the same request later with the same idempotency key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "ResourceStateConflictErrorExample": { + "summary": "Balance lock contention while creating a transfer", + "value": { + "code": "resource_state_conflict", + "message": "Another transfer or balance update is currently in progress for this funding source. Please retry this request." + } + } + } + } + } + }, + "TransferAmlError": { + "description": "The transfer has failed due to an AML violation (anti-money laundering). Reach out to Bridge for more information", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "TransferAmlErrorExample": { + "summary": "An AML violation error response", + "value": { + "code": "aml_violation", + "message": "Failed AML Screening" + } + } + } + } + } + }, + "UnverifiableInputError": { + "description": "Request parameters not verified", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "NotFoundError": { + "description": "No resource found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "NotFoundErrorExample": { + "summary": "Invalid customer id", + "value": { + "code": "Invalid", + "message": "Unknown customer id" + } + } + } + } + } + }, + "DeveloperFeeConfigNotFoundError": { + "description": "No Developer Fee Config found for the given ID", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "NotFoundErrorExample": { + "summary": "Unknown developer fee config id", + "value": { + "code": "not_found", + "message": "Entity not found." + } + } + } + } + } + }, + "UnexpectedError": { + "description": "Unexpected error. User may try and send the request again.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "UnexpectedError": { + "summary": "An unexpected error", + "value": { + "errors": [ + { + "code": "unexpected", + "message": "An expected error occurred, you may try again later" + } + ] + } + } + } + } + } + }, + "AuthenticationError": { + "description": "Missing or invalid API key", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "MissingTokenError": { + "summary": "No Api-Key header", + "description": "The header may be missing or misspelled.", + "value": { + "code": "required", + "location": "header", + "name": "Api-Key", + "message": "Missing Api-Key header" + } + }, + "InvalidTokenError": { + "summary": "Invalid key in Api-Key header", + "value": { + "code": "invalid", + "location": "header", + "name": "Api-Key", + "message": "Invalid Api-Key header" + } + } + } + } + } + }, + "DeveloperFeeConfigAuthenticationError": { + "description": "Missing or invalid API key, or the Developer Fees beta has not been enabled for this developer account", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "MissingTokenError": { + "summary": "No Api-Key header", + "description": "The header may be missing or misspelled.", + "value": { + "code": "required", + "location": "header", + "name": "Api-Key", + "message": "Missing Api-Key header" + } + }, + "InvalidTokenError": { + "summary": "Invalid key in Api-Key header", + "value": { + "code": "invalid", + "location": "header", + "name": "Api-Key", + "message": "Invalid Api-Key header" + } + }, + "NotAllowedError": { + "summary": "Developer Fees beta not enabled", + "description": "The Developer Fees beta has not been enabled for this developer account. Contact Bridge to request access.", + "value": { + "code": "not_allowed", + "message": "This endpoint has not been enabled for your account, please reach out for more details" + } + } + } + } + } + }, + "BadExternalAccountUpdateError": { + "description": "Request containing missing or invalid parameters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "BeneficiaryAddressAlreadyExistsExample": { + "summary": "Beneficiary address already exists", + "value": { + "code": "invalid_parameters", + "message": "Please resubmit the following parameters that are either missing or invalid.", + "source": { + "key": { + "address": "Beneficiary address already exists" + } + } + } + }, + "InvalidrequestExample": { + "summary": "Bad External Account request", + "value": { + "code": "invalid_parameters", + "message": "Please resubmit the following parameters that are either missing or invalid.", + "source": { + "key": { + "address.city": "must be set" + } + } + } + } + } + } + } + }, + "BadExternalAccountReactivateError": { + "description": "Request containing missing or invalid parameters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + }, + "examples": { + "ExternalAccountAlreadyActiveExample": { + "summary": "External account already active", + "value": { + "code": "invalid_parameters", + "message": "Please resubmit the following parameters that are either missing or invalid.", + "source": { + "key": { + "status": "External account already active" + } + } + } + } + } + } + } + } + }, + "securitySchemes": { + "ApiKey": { + "type": "apiKey", + "name": "Api-Key", + "in": "header" + } + } + }, + "security": [ + { + "ApiKey": [] + } + ] +} diff --git a/packages/bridge/openapi/generator-warnings.json b/packages/bridge/openapi/generator-warnings.json new file mode 100644 index 0000000..33bb6cf --- /dev/null +++ b/packages/bridge/openapi/generator-warnings.json @@ -0,0 +1,50 @@ +{ + "items": [ + { + "code": "optional-request-body-approximated", + "message": "Optional request body was approximated by adding a no-content payload alternative.", + "path": "/customers/{customerID}/card_accounts/{cardAccountID}/ephemeral_keys", + "method": "post", + "operationId": "postCustomersByCustomerIDCardAccountsByCardAccountIDEphemeralKeys" + }, + { + "code": "optional-request-body-approximated", + "message": "Optional request body was approximated by adding a no-content payload alternative.", + "path": "/customers/{customerID}/card_accounts/{cardAccountID}/freeze", + "method": "post", + "operationId": "postCustomersByCustomerIDCardAccountsByCardAccountIDFreeze" + }, + { + "code": "optional-request-body-approximated", + "message": "Optional request body was approximated by adding a no-content payload alternative.", + "path": "/customers/{customerID}/card_accounts/{cardAccountID}/unfreeze", + "method": "post", + "operationId": "postCustomersByCustomerIDCardAccountsByCardAccountIDUnfreeze" + }, + { + "code": "optional-request-body-approximated", + "message": "Optional request body was approximated by adding a no-content payload alternative.", + "path": "/customers/{customerID}/card_accounts/{cardAccountID}/create_mobile_wallet_provisioning_request", + "method": "post", + "operationId": "postCustomersByCustomerIDCardAccountsByCardAccountIDCreateMobileWalletProvisioningRequest" + }, + { + "code": "response-headers-ignored", + "message": "Response headers on status 200 were ignored in HttpApi generation.", + "path": "/customers/{customerID}/card_accounts/{cardAccountID}/statements/{period}.pdf", + "method": "post", + "operationId": "postCustomersByCustomerIDCardAccountsByCardAccountIDStatementsPeriodPdf" + }, + { + "code": "response-headers-ignored", + "message": "Response headers on status 200 were ignored in HttpApi generation.", + "path": "/cardholders/{cardholderID}/cards/{cardID}/statements/{period}.pdf", + "method": "post", + "operationId": "postCardholdersByCardholderIDCardsByCardIDStatementsPeriodPdf" + } + ], + "review": { + "optional-request-body-approximated": "Four card-account POST request bodies omit `required`, whose OpenAPI 3.0 default is false. The overlay makes that explicit; rc.112 represents the optional body as an HttpApiSchema.NoContent alternative and emits this warning. Effect v4 rc.112 OpenApi.fromApi currently writes required:true for any non-empty body, so downstream OpenAPI round-tripping cannot preserve this source optionality, although the generated endpoint retains the no-content payload alternative.", + "response-headers-ignored": "The only two instances are the Content-Disposition attachment headers on the PDF statement endpoints. The generated HttpApi schema retains the application/pdf Uint8Array body, but rc.112 cannot describe response headers; consumers that need the filename can select decoded-and-response mode and inspect the raw HttpClientResponse." + } +} diff --git a/packages/bridge/openapi/normalization-overlay.json b/packages/bridge/openapi/normalization-overlay.json new file mode 100644 index 0000000..9c738bf --- /dev/null +++ b/packages/bridge/openapi/normalization-overlay.json @@ -0,0 +1,691 @@ +{ + "patches": [ + { + "op": "add", + "path": "/paths/~1developer~1fees/post/responses/200/content/application~1json/schema", + "value": { + "$ref": "#/components/schemas/DeveloperFees" + }, + "description": "Bridge's POST response includes a concrete JSON example for default_liquidation_address_fee_percent but omits its schema. Reuse the existing DeveloperFees contract shared by GET /developer/fees." + }, + { + "op": "add", + "path": "/components/schemas/CreateLiquidationAddressResponse/type", + "value": "object", + "description": "This response is an object assembled by allOf with required object fields, but upstream omits type: object. Making the implied type explicit avoids an invalid primitive union and preserves the required response fields." + }, + { + "op": "replace", + "path": "/components/schemas/CardFreeze/properties/initiator", + "value": { + "type": "string", + "enum": ["developer", "customer", "bridge"], + "description": "The party that initiated the freeze. Card account responses also include freezes initiated by Bridge." + }, + "description": "CardAccount freezes explicitly allow the bridge initiator while the shared request enum omits it. Scope the response union here so PostCardFreezeInput remains limited to customer or developer." + }, + { + "op": "replace", + "path": "/components/schemas/FeeExternalAccount/required", + "value": ["id", "created_at", "updated_at", "account_owner_name", "currency", "account_type", "active"], + "description": "The published successful fee-account response omits customer_id and account_name; customer_id is not meaningful for a developer-owned account, and account_name has no declared property schema. Do not synthesize these as required fields." + }, + { + "op": "remove", + "path": "/components/schemas/LiquidationAddressCustomDeveloperFeePercent/example", + "description": "The nullable fee-percent example is a string value; rc.112 copies it onto the null union branch as well, producing an invalid TypeScript annotation. Keep the constraint and nullability, but omit this branch-ambiguous example metadata." + }, + { + "op": "add", + "path": "/paths/~1customers~1{customerID}~1card_accounts~1{cardAccountID}~1ephemeral_keys/post/requestBody/required", + "value": false, + "description": "OpenAPI 3.0 requestBody.required defaults to false. Make that default explicit because rc.112 otherwise treats an omitted flag as a required payload." + }, + { + "op": "add", + "path": "/paths/~1customers~1{customerID}~1card_accounts~1{cardAccountID}~1freeze/post/requestBody/required", + "value": false, + "description": "OpenAPI 3.0 requestBody.required defaults to false. Make that default explicit because rc.112 otherwise treats an omitted flag as a required payload." + }, + { + "op": "add", + "path": "/paths/~1customers~1{customerID}~1card_accounts~1{cardAccountID}~1unfreeze/post/requestBody/required", + "value": false, + "description": "OpenAPI 3.0 requestBody.required defaults to false. Make that default explicit because rc.112 otherwise treats an omitted flag as a required payload." + }, + { + "op": "add", + "path": "/paths/~1customers~1{customerID}~1card_accounts~1{cardAccountID}~1create_mobile_wallet_provisioning_request/post/requestBody/required", + "value": false, + "description": "OpenAPI 3.0 requestBody.required defaults to false. Make that default explicit because rc.112 otherwise treats an omitted flag as a required payload." + }, + { + "op": "add", + "path": "/components/schemas/Endorsement/properties/requirements/properties/missing/additionalProperties", + "value": true, + "description": "Bridge documents this response as an open breakdown object and its successful examples use { all_of: [...] }, but publishes no value schema. OpenAPI permits arbitrary properties by default; make that JSON-compatible shape explicit instead of generating an impossible never-valued record." + }, + { + "op": "add", + "path": "/components/schemas/Endorsement/properties/requirements/properties/missing/nullable", + "value": true, + "description": "The declared type is object, but Bridge's published successful customer examples return missing: null. Preserve that observed response alternative while keeping non-null breakdown values JSON-compatible." + }, + { + "op": "add", + "path": "/components/schemas/Endorsement/properties/requirements/properties/issues/items/oneOf/1/additionalProperties", + "value": { "type": "string" }, + "description": "The published issue description defines object values as field-to-issue-code mappings (for example id_front_photo: id_expired). Explicitly type the omitted map value schema as a string." + }, + { + "op": "add", + "path": "/components/schemas/Endorsement/properties/future_requirements/items/properties/missing/additionalProperties", + "value": true, + "description": "Future requirements reuse the same open missing-breakdown object as current requirements and likewise omit its property schema. Preserve JSON values while allowing the documented null alternative." + }, + { + "op": "add", + "path": "/components/schemas/Endorsement/properties/future_requirements/items/properties/issues/items/oneOf/1/additionalProperties", + "value": { "type": "string" }, + "description": "Future issues use the same field-to-issue-code object shape as current issues; define the omitted values as strings per the published description." + }, + { + "op": "add", + "path": "/components/schemas/CardProgramSummary/properties/provisioned_cards_by_country/additionalProperties", + "value": { "type": "integer" }, + "description": "This open country-keyed count map has integer values in the published examples but omits additionalProperties, which the pinned generator otherwise interprets as a record of never." + }, + { + "op": "add", + "path": "/components/schemas/CardProgramSummary/properties/card_transactions_count_by_country/additionalProperties", + "value": { "type": "integer" }, + "description": "This open country-keyed transaction-count map has integer values in the published examples but omits additionalProperties, which the pinned generator otherwise interprets as a record of never." + }, + { + "op": "add", + "path": "/components/schemas/CardProgramSummary/properties/transaction_volume_by_country/additionalProperties", + "value": { "type": "string" }, + "description": "Transaction-volume values are decimal strings in the published examples. State that omitted value type explicitly while preserving open country keys." + }, + { + "op": "add", + "path": "/components/schemas/CardProgramSummary/properties/transacting_cards_by_country/additionalProperties", + "value": { "type": "integer" }, + "description": "This open country-keyed card-count map has integer values in the published examples but omits additionalProperties, which the pinned generator otherwise interprets as a record of never." + }, + { + "op": "add", + "path": "/components/schemas/Customer/properties/last_name/nullable", + "value": true, + "description": "The published successful business-customer response explicitly returns last_name: null. Customer is response-only; leave the separate create/update payload schemas unchanged." + }, + { + "op": "replace", + "path": "/components/schemas/Endorsement/properties/requirements/properties/complete/items", + "value": { + "oneOf": [ + { "type": "string" }, + { + "type": "object", + "required": ["associated_person", "items"], + "properties": { + "associated_person": { "type": "string" }, + "items": { "type": "array", "items": { "type": "string" } } + }, + "additionalProperties": false + } + ] + }, + "description": "The published successful business-customer response includes one structured completed requirement with associated_person and a string items array. Keep ordinary string entries and model this documented object exactly, without an unknown-value escape hatch." + }, + { + "op": "replace", + "path": "/paths/~1customers/get/responses/200/content/application~1json/schema/required", + "value": ["data"], + "description": "Both published successful GET /customers examples omit count. Make only this response's count optional while keeping the data array required and count constrained to an integer when present." + } + ], + "objectSchemas": [ + { + "pointer": "/components/schemas/ExternalAccount", + "reason": "ExternalAccount is the declared oneOf of bank-rail object variants. The pinned generator needs the OpenAPI-implied object type, and object composition keeps additional fields because OpenAPI leaves additionalProperties open by default." + }, + { + "pointer": "/components/schemas/ExternalAccountBaseWithOwnerInfo", + "reason": "This shared external-account property schema omits type: object. Add the implied type and preserve OpenAPI's default allowance for additional fields so allOf variants can compose." + }, + { + "pointer": "/components/schemas/ExternalAccountBaseWithoutOwnerInfo", + "reason": "This shared external-account input property schema omits type: object. Add the implied type and preserve OpenAPI's default allowance for additional fields so allOf variants can compose." + }, + { + "pointer": "/components/schemas/ExternalAccountUs", + "reason": "This external-account response variant is an allOf object whose root omits type: object. Normalize the implied object type and retain open additional properties across its shared and rail-specific fields." + }, + { + "pointer": "/components/schemas/ExternalAccountUs/allOf/1", + "reason": "This US external-account allOf branch contributes rail-specific properties and must allow the shared properties from its sibling branch." + }, + { + "pointer": "/components/schemas/ExternalAccountIban", + "reason": "This external-account response variant is an allOf object whose root omits type: object. Normalize the implied object type and retain open additional properties across its shared and rail-specific fields." + }, + { + "pointer": "/components/schemas/ExternalAccountIban/allOf/1", + "reason": "This IBAN external-account allOf branch contributes rail-specific properties and must allow the shared properties from its sibling branch." + }, + { + "pointer": "/components/schemas/ExternalAccountClabe", + "reason": "This external-account response variant is an allOf object whose root omits type: object. Normalize the implied object type and retain open additional properties across its shared and rail-specific fields." + }, + { + "pointer": "/components/schemas/ExternalAccountClabe/allOf/1", + "reason": "This CLABE external-account allOf branch contributes rail-specific properties and must allow the shared properties from its sibling branch." + }, + { + "pointer": "/components/schemas/ExternalAccountPix", + "reason": "This external-account response variant is an allOf object whose root omits type: object. Normalize the implied object type and retain open additional properties across its shared and rail-specific fields." + }, + { + "pointer": "/components/schemas/ExternalAccountPix/allOf/1", + "reason": "This Pix external-account allOf branch contributes rail-specific properties and must allow the shared properties from its sibling branch." + }, + { + "pointer": "/components/schemas/ExternalAccountGb", + "reason": "This external-account response variant is an allOf object whose root omits type: object. Normalize the implied object type and retain open additional properties across its shared and rail-specific fields." + }, + { + "pointer": "/components/schemas/ExternalAccountGb/allOf/1", + "reason": "This GB external-account allOf branch contributes rail-specific properties and must allow the shared properties from its sibling branch." + }, + { + "pointer": "/components/schemas/ExternalAccountBreB", + "reason": "This external-account response variant is an allOf object whose root omits type: object. Normalize the implied object type and retain open additional properties across its shared and rail-specific fields." + }, + { + "pointer": "/components/schemas/ExternalAccountBreB/allOf/1", + "reason": "This Bre-B external-account allOf branch contributes rail-specific properties and must allow the shared properties from its sibling branch." + }, + { + "pointer": "/components/schemas/ExternalAccountCoBankTransfer", + "reason": "This external-account response variant is an allOf object whose root omits type: object. Normalize the implied object type and retain open additional properties across its shared and rail-specific fields." + }, + { + "pointer": "/components/schemas/ExternalAccountCoBankTransfer/allOf/1", + "reason": "This CO bank-transfer external-account allOf branch contributes rail-specific properties and must allow the shared properties from its sibling branch." + }, + { + "pointer": "/components/schemas/ExternalAccountResponse", + "reason": "The response schema requires shared fields and allOf-intersects the ExternalAccount rail union. Make its implied object root explicit and keep properties contributed by the union." + }, + { + "pointer": "/components/schemas/CreateExternalAccountInput", + "reason": "This request schema is the declared oneOf of bank-rail input objects. Make the implied object type explicit so the generated union retains every rail variant." + }, + { + "pointer": "/components/schemas/CreateExternalAccountUsInput", + "reason": "This US external-account input is an allOf object whose root omits type: object. Normalize the implied type and keep shared fields from composing with rail-specific fields." + }, + { + "pointer": "/components/schemas/CreateExternalAccountUsInput/allOf/1", + "reason": "This US external-account input allOf branch contributes rail-specific properties and must allow the shared properties from its sibling branch." + }, + { + "pointer": "/components/schemas/CreateExternalAccountIbanInput", + "reason": "This IBAN external-account input is an allOf object whose root omits type: object. Normalize the implied type and keep shared fields from composing with rail-specific fields." + }, + { + "pointer": "/components/schemas/CreateExternalAccountIbanInput/allOf/1", + "reason": "This IBAN external-account input allOf branch contributes rail-specific properties and must allow the shared properties from its sibling branch." + }, + { + "pointer": "/components/schemas/CreateExternalAccountClabeInput", + "reason": "This CLABE external-account input is an allOf object whose root omits type: object. Normalize the implied type and keep shared fields from composing with rail-specific fields." + }, + { + "pointer": "/components/schemas/CreateExternalAccountClabeInput/allOf/1", + "reason": "This CLABE external-account input allOf branch contributes rail-specific properties and must allow the shared properties from its sibling branch." + }, + { + "pointer": "/components/schemas/CreateExternalAccountPixKeyInput", + "reason": "This Pix-key external-account input is an allOf object whose root omits type: object. Normalize the implied type and keep shared fields from composing with rail-specific fields." + }, + { + "pointer": "/components/schemas/CreateExternalAccountPixKeyInput/allOf/1", + "reason": "This Pix-key external-account input allOf branch contributes rail-specific properties and must allow the shared properties from its sibling branch." + }, + { + "pointer": "/components/schemas/CreateExternalAccountBrCodeInput", + "reason": "This BR Code external-account input is an allOf object whose root omits type: object. Normalize the implied type and keep shared fields from composing with rail-specific fields." + }, + { + "pointer": "/components/schemas/CreateExternalAccountBrCodeInput/allOf/1", + "reason": "This BR Code external-account input allOf branch contributes rail-specific properties and must allow the shared properties from its sibling branch." + }, + { + "pointer": "/components/schemas/CreateExternalAccountFPSInput", + "reason": "This Faster Payments external-account input is an allOf object whose root omits type: object. Normalize the implied type and keep shared fields from composing with rail-specific fields." + }, + { + "pointer": "/components/schemas/CreateExternalAccountFPSInput/allOf/1", + "reason": "This Faster Payments external-account input allOf branch contributes rail-specific properties and must allow the shared properties from its sibling branch." + }, + { + "pointer": "/components/schemas/CreateExternalAccountBreBInput", + "reason": "This Bre-B external-account input is an allOf object whose root omits type: object. Normalize the implied type and keep shared fields from composing with rail-specific fields." + }, + { + "pointer": "/components/schemas/CreateExternalAccountBreBInput/allOf/1", + "reason": "This Bre-B external-account input allOf branch contributes rail-specific properties and must allow the shared properties from its sibling branch." + }, + { + "pointer": "/components/schemas/CreateExternalAccountCoBankTransferInput", + "reason": "This CO bank-transfer external-account input is an allOf object whose root omits type: object. Normalize the implied type and keep shared fields from composing with rail-specific fields." + }, + { + "pointer": "/components/schemas/CreateExternalAccountCoBankTransferInput/allOf/1", + "reason": "This CO bank-transfer external-account input allOf branch contributes rail-specific properties and must allow the shared properties from its sibling branch." + }, + { + "pointer": "/components/schemas/CreateFeeExternalAccountInput", + "reason": "This fee-account input is an allOf object whose root omits type: object. Normalize the implied type while retaining fields from ExternalAccountUs." + }, + { + "pointer": "/components/schemas/FeeExternalAccount", + "reason": "This fee-account response is an allOf object whose root omits type: object. Normalize the implied type while retaining the required ExternalAccountUs fields." + }, + { + "pointer": "/components/schemas/CreateLiquidationAddress", + "reason": "This liquidation-address request schema has object properties but omits type: object. Make the implied object shape explicit and preserve the OpenAPI default for additional fields." + }, + { + "pointer": "/components/schemas/CreateLiquidationAddressResponse", + "reason": "This allOf response root must remain open so request fields and response fields contributed by its two branches can intersect." + }, + { + "pointer": "/components/schemas/CreateLiquidationAddressResponse/allOf/1", + "reason": "This liquidation-address response allOf branch contributes response fields and must allow the request fields from its sibling branch." + }, + { + "pointer": "/components/schemas/CardAccount", + "reason": "CardAccount is an object response with a composed freeze item. Preserve OpenAPI's default allowance for additional card-account properties." + }, + { + "pointer": "/components/schemas/CardFreeze", + "reason": "CardFreeze has required object fields but omits type: object. Make the implied object shape explicit and retain OpenAPI's default additional-field behavior." + }, + { + "pointer": "/components/schemas/CardCryptoAccount", + "reason": "CardCryptoAccount has required object fields but omits type: object. Make the implied object shape explicit and retain OpenAPI's default additional-field behavior." + }, + { + "pointer": "/components/schemas/CardAccount/properties/freezes/items", + "reason": "This card-freeze item combines the CardFreeze ref with an inline initiator restriction; make the object explicit and allow the remaining CardFreeze fields." + }, + { + "pointer": "/components/schemas/CardAccount/properties/balances", + "reason": "CardAccount balances reference a sibling object schema; keep all declared balance properties while preserving the OpenAPI default for additional balance fields." + }, + { + "pointer": "/components/schemas/CardAccount/properties/cardholder_name", + "reason": "CardholderName is referenced with an OpenAPI 3.0 type sibling; keep the sibling open so it does not reject fields declared by the referenced component." + }, + { + "pointer": "/components/schemas/CardAccount/properties/card_details", + "reason": "CardDetails is referenced with an OpenAPI 3.0 type sibling; keep the sibling open so it does not reject fields declared by the referenced component." + }, + { + "pointer": "/components/schemas/CardAccount/properties/crypto_account", + "reason": "CardCryptoAccount is referenced with an OpenAPI 3.0 type sibling; keep the sibling open so it does not reject fields declared by the referenced component." + }, + { + "pointer": "/components/schemas/CardholderName", + "reason": "CardholderName is an object component with required names; make its object type explicit and preserve OpenAPI's default for additional fields." + }, + { + "pointer": "/components/schemas/CardDetails", + "reason": "CardDetails is an object component with required card fields; make its object type explicit and preserve OpenAPI's default for additional fields." + }, + { + "pointer": "/components/schemas/CardBalances/properties/available", + "reason": "Card balance entries reference CardBalance with an OpenAPI 3.0 type sibling; keep the sibling open so it does not reject the referenced balance fields." + }, + { + "pointer": "/components/schemas/CardBalances/properties/hold", + "reason": "Card hold entries reference CardBalance with an OpenAPI 3.0 type sibling; keep the sibling open so it does not reject the referenced balance fields." + }, + { + "pointer": "/components/schemas/CardBalances", + "reason": "CardBalances has required object fields but omits type: object. Make its object shape explicit and preserve OpenAPI's default for additional fields." + }, + { + "pointer": "/components/schemas/CardBalance", + "reason": "CardBalance has object properties but omits type: object. Make its object shape explicit so CardBalances can retain its required fields." + }, + { + "pointer": "/components/schemas/WebhookEvent", + "reason": "WebhookEvent has required object fields but omits type: object. Make the event envelope explicit and retain its OpenAPI default for additional fields." + }, + { + "pointer": "/components/schemas/WebhookEvent/properties/event_object", + "reason": "Webhook event objects contain resource-specific fields not enumerable in one shared schema; accept JSON properties instead of generating an impossible closed record." + }, + { + "pointer": "/components/schemas/WebhookEvent/properties/event_object_changes", + "reason": "Webhook event change objects contain resource-specific fields not enumerable in one shared schema; accept JSON properties instead of generating an impossible closed record." + }, + { + "pointer": "/components/schemas/VirtualAccountResponse", + "reason": "VirtualAccountResponse declares object fields but omits the OpenAPI-implied type: object. Make that shape explicit so the six source-instruction alternatives and allOf response composition stay typed." + }, + { + "pointer": "/components/schemas/VirtualAccountSourceDepositInstructionsUs", + "reason": "This US deposit-instruction allOf variant omits type: object at its root. Normalize the implied object root and retain fields from its rail-specific and common branches." + }, + { + "pointer": "/components/schemas/VirtualAccountSourceDepositInstructionsEu", + "reason": "This EU deposit-instruction allOf variant omits type: object at its root. Normalize the implied object root and retain fields from its rail-specific and common branches." + }, + { + "pointer": "/components/schemas/VirtualAccountSourceDepositInstructionsMx", + "reason": "This Mexico deposit-instruction allOf variant omits type: object at its root. Normalize the implied object root and retain fields from its rail-specific and common branches." + }, + { + "pointer": "/components/schemas/VirtualAccountSourceDepositInstructionsBr", + "reason": "This Brazil deposit-instruction allOf variant omits type: object at its root. Normalize the implied object root and retain fields from its rail-specific and common branches." + }, + { + "pointer": "/components/schemas/VirtualAccountSourceDepositInstructionsGb", + "reason": "This UK deposit-instruction allOf variant omits type: object at its root. Normalize the implied object root and retain fields from its rail-specific and common branches." + }, + { + "pointer": "/components/schemas/VirtualAccountSourceDepositInstructionsCo", + "reason": "This Colombia deposit-instruction allOf variant omits type: object at its root. Normalize the implied object root and retain fields from its rail-specific and common branches." + }, + { + "pointer": "/components/schemas/VirtualAccountSourceDepositInstructionsCommon", + "reason": "The shared deposit-instruction component contributes bank name and address inside rail-specific allOf variants. OpenAPI permits extra properties, so retain fields contributed by sibling rail branches." + }, + { + "pointer": "/components/schemas/GbBankAccountVirtualAccount", + "reason": "The UK deposit-instruction variant reuses this object through allOf. Keep the shared account fields open so its currency, payment rail, account-holder, and common bank properties compose." + }, + { + "pointer": "/components/schemas/VirtualAccountSourceDepositInstructionsUs/allOf/0", + "reason": "The US rail-specific allOf branch must allow common bank fields contributed by its sibling branch under OpenAPI's default additionalProperties behavior." + }, + { + "pointer": "/components/schemas/VirtualAccountSourceDepositInstructionsEu/allOf/0", + "reason": "The EU rail-specific allOf branch must allow common bank fields contributed by its sibling branch under OpenAPI's default additionalProperties behavior." + }, + { + "pointer": "/components/schemas/VirtualAccountSourceDepositInstructionsMx/allOf/0", + "reason": "The Mexico rail-specific allOf branch must allow common bank fields contributed by its sibling branch under OpenAPI's default additionalProperties behavior." + }, + { + "pointer": "/components/schemas/VirtualAccountSourceDepositInstructionsBr/allOf/0", + "reason": "The Brazil rail-specific allOf branch must allow common bank fields contributed by its sibling branch under OpenAPI's default additionalProperties behavior." + }, + { + "pointer": "/components/schemas/VirtualAccountSourceDepositInstructionsGb/allOf/0", + "reason": "The shared GB bank-account branch must allow common deposit-instruction fields contributed by other allOf siblings." + }, + { + "pointer": "/components/schemas/VirtualAccountSourceDepositInstructionsGb/allOf/1", + "reason": "The UK rail-specific allOf branch must allow common bank fields contributed by its sibling branch under OpenAPI's default additionalProperties behavior." + }, + { + "pointer": "/components/schemas/VirtualAccountSourceDepositInstructionsCo/allOf/0", + "reason": "The Colombia rail-specific allOf branch must allow common bank fields contributed by its sibling branch under OpenAPI's default additionalProperties behavior." + }, + { + "pointer": "/paths/~1customers~1{customerID}~1virtual_accounts~1{virtualAccountID}~1deactivate/post/responses/200/content/application~1json/schema", + "reason": "The deactivate success response is an allOf object over VirtualAccountResponse but omits its own root type. Normalize this implied object root so the referenced response properties remain typed." + }, + { + "pointer": "/paths/~1customers~1{customerID}~1virtual_accounts~1{virtualAccountID}~1deactivate/post/responses/200/content/application~1json/schema/allOf/1", + "reason": "The example-only deactivate status override is an object branch in an allOf response; retain the base response's remaining properties under OpenAPI's default additionalProperties behavior." + } + ], + "propertyObjectSchemas": { + "reason": "A property-bearing or required-bearing component schema node with no explicit type and no allOf/oneOf/anyOf is an object schema. Normalize only the missing type; retain the raw fields, nullability, required lists, enums and composition. OpenAPI 3.0 leaves additional properties allowed by default.", + "pointers": [ + "/components/schemas/Address", + "/components/schemas/Address2025WinterRefresh", + "/components/schemas/ApiKey", + "/components/schemas/ApiKeyWithSecret/allOf/1", + "/components/schemas/AssociatedPerson", + "/components/schemas/Balance", + "/components/schemas/BrCodeBankAccount", + "/components/schemas/BreBBankAccount", + "/components/schemas/BridgeWallet/allOf/1", + "/components/schemas/BridgeWalletWithBalances/allOf/1", + "/components/schemas/CardAccountEphemeralKeyResponse", + "/components/schemas/CardAccountFundingInstructions", + "/components/schemas/CardAuthorization", + "/components/schemas/CardAuthorization/properties/details", + "/components/schemas/CardCryptoTransactionDetails", + "/components/schemas/CardLocalTransactionDetails", + "/components/schemas/CardPushProvisioningResponse", + "/components/schemas/CardPushProvisioningResponse/properties/apple_pay", + "/components/schemas/CardPushProvisioningResponse/properties/google_pay", + "/components/schemas/CardSpendingLimit", + "/components/schemas/CardTransaction", + "/components/schemas/CardUnfreezeResponse/allOf/1", + "/components/schemas/CardWithdrawal", + "/components/schemas/CardWithdrawalDestination", + "/components/schemas/ClabeBankAccount", + "/components/schemas/CoBankTransferBankAccount", + "/components/schemas/Country", + "/components/schemas/CreateApiKeyInput", + "/components/schemas/CreateBatchSettlementSchedule", + "/components/schemas/CreateBridgeWallet", + "/components/schemas/CreateBridgeWalletResponse/allOf/1", + "/components/schemas/CreateDeveloperFeeConfig", + "/components/schemas/CreateIndividualCustomerPayload/allOf/2", + "/components/schemas/CreateKycLinks", + "/components/schemas/CreateStaticMemo", + "/components/schemas/CreateVirtualAccount", + "/components/schemas/CreateWebhook", + "/components/schemas/Customer", + "/components/schemas/DepositInstructions", + "/components/schemas/DeveloperFeeConfig", + "/components/schemas/DeveloperFees", + "/components/schemas/Drain", + "/components/schemas/DrainDestination", + "/components/schemas/DrainReceipt", + "/components/schemas/DrainReturnDetails", + "/components/schemas/Endorsement", + "/components/schemas/Error", + "/components/schemas/Error/properties/source", + "/components/schemas/ExchangeDetails", + "/components/schemas/ExternalAccountAddress", + "/components/schemas/FakePayin", + "/components/schemas/FundsRequest", + "/components/schemas/GasFee", + "/components/schemas/IbanBankAccount", + "/components/schemas/IndividualKycLinkResponse", + "/components/schemas/LiquidationAddress", + "/components/schemas/Payin", + "/components/schemas/Payout", + "/components/schemas/PixKeyBankAccount", + "/components/schemas/PlaidExchangePublicToken", + "/components/schemas/PlaidLinkRequest", + "/components/schemas/PostCardAccountDepositAddressInput", + "/components/schemas/PostCardAccountEphemeralKeyInput", + "/components/schemas/PostCardAccountsInput", + "/components/schemas/PostCardFreezeInput", + "/components/schemas/PostCardPushProvisioningInput", + "/components/schemas/PostCardPushProvisioningInput/properties/apple_pay", + "/components/schemas/PostCardPushProvisioningInput/properties/google_pay", + "/components/schemas/PostCardUnfreezeInput", + "/components/schemas/PrefundedAccount", + "/components/schemas/PrefundedAccountHistory", + "/components/schemas/PutWebhookPayload", + "/components/schemas/Receipt", + "/components/schemas/RejectionReason", + "/components/schemas/Rfi", + "/components/schemas/SendWebhookPayload", + "/components/schemas/StaticMemoDestination", + "/components/schemas/StaticMemoEvent", + "/components/schemas/StaticMemoEventSource", + "/components/schemas/StaticMemoEventSourceDepositInstructions", + "/components/schemas/StaticMemoResponse", + "/components/schemas/StaticMemoSourceDepositInstructions", + "/components/schemas/StaticMemoSourceInput", + "/components/schemas/Subdivision", + "/components/schemas/TransferDestination", + "/components/schemas/TransferRequest", + "/components/schemas/TransferRequest/properties/destination/allOf/1", + "/components/schemas/TransferRequest/properties/source/allOf/1", + "/components/schemas/TransferResponse", + "/components/schemas/TransferResponse/properties/destination/allOf/1", + "/components/schemas/TransferResponse/properties/source/allOf/1", + "/components/schemas/TransferResponse/properties/source_deposit_instructions/allOf/1", + "/components/schemas/TransferReturnDetails", + "/components/schemas/TransferRouteResponse", + "/components/schemas/TransferSource", + "/components/schemas/TransferUpdateRequest", + "/components/schemas/UpdateBusinessCustomerPayload", + "/components/schemas/UpdateDeveloperFeeConfig", + "/components/schemas/UpdateExternalAccountInput", + "/components/schemas/UpdateIndividualCustomerPayload", + "/components/schemas/UpdateLiquidationAddress", + "/components/schemas/UpdateStaticMemo", + "/components/schemas/UpdateStaticMemoDestination", + "/components/schemas/UpdateVirtualAccount", + "/components/schemas/UpdateVirtualAccountDestination", + "/components/schemas/UsBankAccount", + "/components/schemas/UsBankAccountUpdate", + "/components/schemas/VirtualAccountDestination", + "/components/schemas/VirtualAccountEvent", + "/components/schemas/VirtualAccountEventSource", + "/components/schemas/VirtualAccountRefundDetails", + "/components/schemas/VirtualAccountSourceInput", + "/components/schemas/Webhook", + "/components/schemas/WebhookEventDeliveryLog" + ] + }, + "schemaVariants": [ + { + "source": "UsBankAccount", + "input": "UsBankAccountInput", + "outputRequired": ["routing_number", "last_4"], + "inputRequired": ["account_number", "routing_number"], + "requestRefs": [ + "/components/schemas/CreateExternalAccountUsInput/allOf/1/properties/account/$ref" + ], + "inputRefOverrides": [], + "reason": "The shared bank schema marks account_number writeOnly and last_4 readOnly but requires both. Keep the documented response requirements on UsBankAccount and provide a request variant that requires writable account fields only." + }, + { + "source": "IbanBankAccount", + "input": "IbanBankAccountInput", + "outputRequired": ["country", "last_4"], + "inputRequired": ["account_number", "country"], + "requestRefs": [ + "/components/schemas/CreateExternalAccountIbanInput/allOf/1/properties/iban/$ref" + ], + "inputRefOverrides": [], + "reason": "IBAN account_number is writeOnly and last_4 is readOnly, although both are listed as required. Preserve the response shape and give create requests a direction-correct required list." + }, + { + "source": "ClabeBankAccount", + "input": "ClabeBankAccountInput", + "outputRequired": ["last_4"], + "inputRequired": ["account_number"], + "requestRefs": [ + "/components/schemas/CreateExternalAccountClabeInput/allOf/1/properties/clabe/$ref" + ], + "inputRefOverrides": [], + "reason": "CLABE account_number is writeOnly and last_4 is readOnly, although both are listed as required. Preserve the response shape and give create requests a direction-correct required list." + }, + { + "source": "PixKeyBankAccount", + "input": "PixKeyBankAccountInput", + "outputRequired": ["account_preview"], + "inputRequired": ["pix_key"], + "requestRefs": [ + "/components/schemas/CreateExternalAccountPixKeyInput/allOf/1/properties/pix_key/$ref" + ], + "inputRefOverrides": [], + "reason": "PixKeyBankAccount requires its writeOnly pix_key and readOnly account_preview together. Keep account_preview required for responses and require the supplied key for requests." + }, + { + "source": "BrCodeBankAccount", + "input": "BrCodeBankAccountInput", + "outputRequired": ["account_preview"], + "inputRequired": ["br_code"], + "requestRefs": [ + "/components/schemas/CreateExternalAccountBrCodeInput/allOf/1/properties/br_code/$ref" + ], + "inputRefOverrides": [], + "reason": "BrCodeBankAccount requires the writeOnly BR code and readOnly preview together. Keep the response preview requirement and give create requests their writable required field." + }, + { + "source": "GbBankAccount", + "input": "GbBankAccountInput", + "outputRequired": ["last_4", "sort_code"], + "inputRequired": ["account_number", "sort_code"], + "requestRefs": [ + "/components/schemas/CreateExternalAccountFPSInput/allOf/1/properties/account/$ref" + ], + "inputRefOverrides": [], + "reason": "GB account_number is writeOnly while last_4 is readOnly, but the upstream shared schema requires both. Preserve output requirements and define create requirements from writable fields." + }, + { + "source": "BreBBankAccount", + "input": "BreBBankAccountInput", + "outputRequired": ["last_4"], + "inputRequired": ["bre_b_key"], + "requestRefs": [ + "/components/schemas/CreateExternalAccountBreBInput/allOf/1/properties/account/$ref" + ], + "inputRefOverrides": [], + "reason": "The Bre-B key is writeOnly and last_4 is readOnly although both are required upstream. Preserve the masked response field and require only the supplied key on create." + }, + { + "source": "CoBankTransferBankAccount", + "input": "CoBankTransferBankAccountInput", + "outputRequired": ["last_4", "routing_number"], + "inputRequired": ["account_number", "bank_code", "account_type", "document_type", "document_number", "phone_number"], + "requestRefs": [ + "/components/schemas/CreateExternalAccountCoBankTransferInput/allOf/1/properties/account/$ref" + ], + "inputRefOverrides": [], + "reason": "CO bank transfer's required list describes supplied account details, but success responses expose only the readOnly last_4 and routing_number fields. Keep those response requirements and separate the create contract." + }, + { + "source": "ExternalAccountUs", + "input": "ExternalAccountUsInput", + "requestRefs": [ + "/components/schemas/CreateFeeExternalAccountInput/allOf/0/$ref" + ], + "inputRefOverrides": [ + { + "pointer": "/allOf/1/properties/account/$ref", + "schema": "UsBankAccountInput" + } + ], + "reason": "CreateFeeExternalAccountInput currently points at the response variant, so its nested account requires response-only last_4. Clone the same request-compatible US rail shape and swap only its nested bank contract." + } + ], + "generatedSchemaOverrides": [ + { + "name": "PostCustomersByCustomerIDCardAccountsByCardAccountIDStatementsPeriodPdf200ApplicationPdf", + "fromType": "string", + "type": "Uint8Array", + "fromSchema": "Schema.String.annotate({ \"format\": \"binary\" })", + "schema": "Schema.Uint8Array.annotate({ \"format\": \"binary\" })", + "reason": "The rc.112 generator emits a string schema for OpenAPI format: binary, then applies HttpApiSchema.asUint8Array, which requires Uint8Array on the encoded side. Map this PDF transport schema to bytes." + }, + { + "name": "PostCardholdersByCardholderIDCardsByCardIDStatementsPeriodPdf200ApplicationPdf", + "fromType": "string", + "type": "Uint8Array", + "fromSchema": "Schema.String.annotate({ \"format\": \"binary\" })", + "schema": "Schema.Uint8Array.annotate({ \"format\": \"binary\" })", + "reason": "The rc.112 generator emits a string schema for OpenAPI format: binary, then applies HttpApiSchema.asUint8Array, which requires Uint8Array on the encoded side. Map this PDF transport schema to bytes." + } + ] +} diff --git a/packages/bridge/openapi/operation-manifest.json b/packages/bridge/openapi/operation-manifest.json new file mode 100644 index 0000000..4f96693 --- /dev/null +++ b/packages/bridge/openapi/operation-manifest.json @@ -0,0 +1,837 @@ +{ + "sourceSha256": "e8aee6cee1b5518d81f384c8b718dd9d9154dd9eb55345ff73d8b8dbe88327f2", + "groups": { + "API Keys": "apiKeys", + "Associated Persons": "associatedPersons", + "Batch Settlements": "batchSettlements", + "Bridge Wallets": "bridgeWallets", + "Cards": "cards", + "Crypto Return Policies": "cryptoReturnPolicies", + "Customers": "customers", + "Developer Fees": "developerFees", + "Developers": "developers", + "Exchange Rates": "exchangeRates", + "External Accounts": "externalAccounts", + "Fiat Payout Configuration": "fiatPayoutConfiguration", + "Funds Requests": "fundsRequests", + "KYC Links": "kycLinks", + "Liquidation Addresses": "liquidationAddresses", + "Lists": "lists", + "Plaid": "plaid", + "Prefunded Accounts": "prefundedAccounts", + "Rewards": "rewards", + "RFIs": "rfis", + "Sandbox": "sandbox", + "Static Memos": "staticMemos", + "Transfers": "transfers", + "Travel Rule": "travelRule", + "Virtual Accounts": "virtualAccounts", + "Webhooks": "webhooks" + }, + "operations": [ + { + "method": "post", + "path": "/api_keys", + "operationId": "postApiKeys", + "group": "apiKeys" + }, + { + "method": "get", + "path": "/api_keys/whoami", + "operationId": "getApiKeysWhoami", + "group": "apiKeys" + }, + { + "method": "get", + "path": "/associated_persons/{associatedPersonID}", + "operationId": "getAssociatedPersonsByAssociatedPersonID", + "group": "associatedPersons" + }, + { + "method": "put", + "path": "/associated_persons/{associatedPersonID}", + "operationId": "putAssociatedPersonsByAssociatedPersonID", + "group": "associatedPersons" + }, + { + "method": "delete", + "path": "/associated_persons/{associatedPersonID}", + "operationId": "deleteAssociatedPersonsByAssociatedPersonID", + "group": "associatedPersons" + }, + { + "method": "post", + "path": "/cardholders/{cardholderID}/cards/{cardID}/statements/{period}.pdf", + "operationId": "postCardholdersByCardholderIDCardsByCardIDStatementsPeriodPdf", + "group": "cards" + }, + { + "method": "get", + "path": "/crypto_return_policies", + "operationId": "getCryptoReturnPolicies", + "group": "cryptoReturnPolicies" + }, + { + "method": "post", + "path": "/crypto_return_policies", + "operationId": "postCryptoReturnPolicies", + "group": "cryptoReturnPolicies" + }, + { + "method": "put", + "path": "/crypto_return_policies/{policyID}", + "operationId": "putCryptoReturnPoliciesByPolicyID", + "group": "cryptoReturnPolicies" + }, + { + "method": "delete", + "path": "/crypto_return_policies/{policyID}", + "operationId": "deleteCryptoReturnPoliciesByPolicyID", + "group": "cryptoReturnPolicies" + }, + { + "method": "get", + "path": "/customers", + "operationId": "getCustomers", + "group": "customers" + }, + { + "method": "post", + "path": "/customers", + "operationId": "postCustomers", + "group": "customers" + }, + { + "method": "get", + "path": "/customers/{customerID}", + "operationId": "getCustomersByCustomerID", + "group": "customers" + }, + { + "method": "put", + "path": "/customers/{customerID}", + "operationId": "putCustomersByCustomerID", + "group": "customers" + }, + { + "method": "delete", + "path": "/customers/{customerID}", + "operationId": "deleteCustomersByCustomerID", + "group": "customers" + }, + { + "method": "get", + "path": "/customers/{customerID}/associated_persons", + "operationId": "getCustomersByCustomerIDAssociatedPersons", + "group": "customers" + }, + { + "method": "post", + "path": "/customers/{customerID}/associated_persons", + "operationId": "postCustomersByCustomerIDAssociatedPersons", + "group": "customers" + }, + { + "method": "get", + "path": "/customers/{customerID}/associated_persons/{associatedPersonID}", + "operationId": "getCustomersByCustomerIDAssociatedPersonsByAssociatedPersonID", + "group": "customers" + }, + { + "method": "put", + "path": "/customers/{customerID}/associated_persons/{associatedPersonID}", + "operationId": "putCustomersByCustomerIDAssociatedPersonsByAssociatedPersonID", + "group": "customers" + }, + { + "method": "delete", + "path": "/customers/{customerID}/associated_persons/{associatedPersonID}", + "operationId": "deleteCustomersByCustomerIDAssociatedPersonsByAssociatedPersonID", + "group": "customers" + }, + { + "method": "post", + "path": "/customers/{customerID}/batch_settlement_schedules", + "operationId": "postCustomersByCustomerIDBatchSettlementSchedules", + "group": "batchSettlements" + }, + { + "method": "get", + "path": "/customers/{customerID}/card_accounts", + "operationId": "getCustomersByCustomerIDCardAccounts", + "group": "cards" + }, + { + "method": "post", + "path": "/customers/{customerID}/card_accounts", + "operationId": "postCustomersByCustomerIDCardAccounts", + "group": "cards" + }, + { + "method": "get", + "path": "/customers/{customerID}/card_accounts/{cardAccountID}", + "operationId": "getCustomersByCustomerIDCardAccountsByCardAccountID", + "group": "cards" + }, + { + "method": "put", + "path": "/customers/{customerID}/card_accounts/{cardAccountID}", + "operationId": "putCustomersByCustomerIDCardAccountsByCardAccountID", + "group": "cards" + }, + { + "method": "get", + "path": "/customers/{customerID}/card_accounts/{cardAccountID}/auth_controls", + "operationId": "getCustomersByCustomerIDCardAccountsByCardAccountIDAuthControls", + "group": "cards" + }, + { + "method": "get", + "path": "/customers/{customerID}/card_accounts/{cardAccountID}/authorizations", + "operationId": "getCustomersByCustomerIDCardAccountsByCardAccountIDAuthorizations", + "group": "cards" + }, + { + "method": "post", + "path": "/customers/{customerID}/card_accounts/{cardAccountID}/create_mobile_wallet_provisioning_request", + "operationId": "postCustomersByCustomerIDCardAccountsByCardAccountIDCreateMobileWalletProvisioningRequest", + "group": "cards" + }, + { + "method": "post", + "path": "/customers/{customerID}/card_accounts/{cardAccountID}/deposit_addresses", + "operationId": "postCustomersByCustomerIDCardAccountsByCardAccountIDDepositAddresses", + "group": "cards" + }, + { + "method": "post", + "path": "/customers/{customerID}/card_accounts/{cardAccountID}/ephemeral_keys", + "operationId": "postCustomersByCustomerIDCardAccountsByCardAccountIDEphemeralKeys", + "group": "cards" + }, + { + "method": "post", + "path": "/customers/{customerID}/card_accounts/{cardAccountID}/freeze", + "operationId": "postCustomersByCustomerIDCardAccountsByCardAccountIDFreeze", + "group": "cards" + }, + { + "method": "post", + "path": "/customers/{customerID}/card_accounts/{cardAccountID}/pin", + "operationId": "postCustomersByCustomerIDCardAccountsByCardAccountIDPin", + "group": "cards" + }, + { + "method": "post", + "path": "/customers/{customerID}/card_accounts/{cardAccountID}/statements/{period}.pdf", + "operationId": "postCustomersByCustomerIDCardAccountsByCardAccountIDStatementsPeriodPdf", + "group": "cards" + }, + { + "method": "get", + "path": "/customers/{customerID}/card_accounts/{cardAccountID}/transactions", + "operationId": "getCustomersByCustomerIDCardAccountsByCardAccountIDTransactions", + "group": "cards" + }, + { + "method": "get", + "path": "/customers/{customerID}/card_accounts/{cardAccountID}/transactions/{transactionID}", + "operationId": "getCustomersByCustomerIDCardAccountsByCardAccountIDTransactionsByTransactionID", + "group": "cards" + }, + { + "method": "post", + "path": "/customers/{customerID}/card_accounts/{cardAccountID}/unfreeze", + "operationId": "postCustomersByCustomerIDCardAccountsByCardAccountIDUnfreeze", + "group": "cards" + }, + { + "method": "get", + "path": "/customers/{customerID}/card_accounts/{cardAccountID}/withdrawals", + "operationId": "getCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawals", + "group": "cards" + }, + { + "method": "post", + "path": "/customers/{customerID}/card_accounts/{cardAccountID}/withdrawals", + "operationId": "postCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawals", + "group": "cards" + }, + { + "method": "get", + "path": "/customers/{customerID}/card_accounts/{cardAccountID}/withdrawals/{cardWithdrawalID}", + "operationId": "getCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawalsByCardWithdrawalID", + "group": "cards" + }, + { + "method": "get", + "path": "/customers/{customerID}/external_accounts", + "operationId": "getCustomersByCustomerIDExternalAccounts", + "group": "externalAccounts" + }, + { + "method": "post", + "path": "/customers/{customerID}/external_accounts", + "operationId": "postCustomersByCustomerIDExternalAccounts", + "group": "externalAccounts" + }, + { + "method": "get", + "path": "/customers/{customerID}/external_accounts/{externalAccountID}", + "operationId": "getCustomersByCustomerIDExternalAccountsByExternalAccountID", + "group": "externalAccounts" + }, + { + "method": "put", + "path": "/customers/{customerID}/external_accounts/{externalAccountID}", + "operationId": "putCustomersByCustomerIDExternalAccountsByExternalAccountID", + "group": "externalAccounts" + }, + { + "method": "delete", + "path": "/customers/{customerID}/external_accounts/{externalAccountID}", + "operationId": "deleteCustomersByCustomerIDExternalAccountsByExternalAccountID", + "group": "externalAccounts" + }, + { + "method": "post", + "path": "/customers/{customerID}/external_accounts/{externalAccountID}/deactivate", + "operationId": "postCustomersByCustomerIDExternalAccountsByExternalAccountIDDeactivate", + "group": "externalAccounts" + }, + { + "method": "post", + "path": "/customers/{customerID}/external_accounts/{externalAccountID}/reactivate", + "operationId": "postCustomersByCustomerIDExternalAccountsByExternalAccountIDReactivate", + "group": "externalAccounts" + }, + { + "method": "post", + "path": "/customers/{customerID}/external_accounts/{externalAccountID}/verify", + "operationId": "postCustomersByCustomerIDExternalAccountsByExternalAccountIDVerify", + "group": "externalAccounts" + }, + { + "method": "get", + "path": "/customers/{customerID}/fiat_payout_configuration", + "operationId": "getCustomersByCustomerIDFiatPayoutConfiguration", + "group": "fiatPayoutConfiguration" + }, + { + "method": "patch", + "path": "/customers/{customerID}/fiat_payout_configuration", + "operationId": "patchCustomersByCustomerIDFiatPayoutConfiguration", + "group": "fiatPayoutConfiguration" + }, + { + "method": "get", + "path": "/customers/{customerID}/kyc_link", + "operationId": "getCustomersByCustomerIDKycLink", + "group": "customers" + }, + { + "method": "get", + "path": "/customers/{customerID}/liquidation_addresses", + "operationId": "getCustomersByCustomerIDLiquidationAddresses", + "group": "liquidationAddresses" + }, + { + "method": "post", + "path": "/customers/{customerID}/liquidation_addresses", + "operationId": "postCustomersByCustomerIDLiquidationAddresses", + "group": "liquidationAddresses" + }, + { + "method": "get", + "path": "/customers/{customerID}/liquidation_addresses/{liquidationAddressID}", + "operationId": "getCustomersByCustomerIDLiquidationAddressesByLiquidationAddressID", + "group": "liquidationAddresses" + }, + { + "method": "put", + "path": "/customers/{customerID}/liquidation_addresses/{liquidationAddressID}", + "operationId": "putCustomersByCustomerIDLiquidationAddressesByLiquidationAddressID", + "group": "liquidationAddresses" + }, + { + "method": "get", + "path": "/customers/{customerID}/liquidation_addresses/{liquidationAddressID}/balances", + "operationId": "getCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDBalances", + "group": "liquidationAddresses" + }, + { + "method": "get", + "path": "/customers/{customerID}/liquidation_addresses/{liquidationAddressID}/drains", + "operationId": "getCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDDrains", + "group": "liquidationAddresses" + }, + { + "method": "post", + "path": "/customers/{customerID}/liquidation_addresses/{liquidationAddressID}/drains/{drainID}/execute", + "operationId": "postCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDDrainsByDrainIDExecute", + "group": "liquidationAddresses" + }, + { + "method": "post", + "path": "/customers/{customerID}/plaid_link_requests", + "operationId": "postCustomersByCustomerIDPlaidLinkRequests", + "group": "plaid" + }, + { + "method": "post", + "path": "/customers/{customerID}/simulate_kyc_approval", + "operationId": "postCustomersByCustomerIDSimulateKycApproval", + "group": "sandbox" + }, + { + "method": "get", + "path": "/customers/{customerID}/static_memos", + "operationId": "getCustomersByCustomerIDStaticMemos", + "group": "staticMemos" + }, + { + "method": "post", + "path": "/customers/{customerID}/static_memos", + "operationId": "postCustomersByCustomerIDStaticMemos", + "group": "staticMemos" + }, + { + "method": "get", + "path": "/customers/{customerID}/static_memos/{staticMemoID}", + "operationId": "getCustomersByCustomerIDStaticMemosByStaticMemoID", + "group": "staticMemos" + }, + { + "method": "put", + "path": "/customers/{customerID}/static_memos/{staticMemoID}", + "operationId": "putCustomersByCustomerIDStaticMemosByStaticMemoID", + "group": "staticMemos" + }, + { + "method": "get", + "path": "/customers/{customerID}/static_memos/{staticMemoID}/history", + "operationId": "getCustomersByCustomerIDStaticMemosByStaticMemoIDHistory", + "group": "staticMemos" + }, + { + "method": "get", + "path": "/customers/{customerID}/tos_acceptance_link", + "operationId": "getCustomersByCustomerIDTosAcceptanceLink", + "group": "customers" + }, + { + "method": "get", + "path": "/customers/{customerID}/transfers", + "operationId": "getCustomersByCustomerIDTransfers", + "group": "customers" + }, + { + "method": "get", + "path": "/customers/{customerID}/transfers/static_templates", + "operationId": "getCustomersByCustomerIDTransfersStaticTemplates", + "group": "customers" + }, + { + "method": "get", + "path": "/customers/{customerID}/virtual_accounts", + "operationId": "getCustomersByCustomerIDVirtualAccounts", + "group": "virtualAccounts" + }, + { + "method": "post", + "path": "/customers/{customerID}/virtual_accounts", + "operationId": "postCustomersByCustomerIDVirtualAccounts", + "group": "virtualAccounts" + }, + { + "method": "get", + "path": "/customers/{customerID}/virtual_accounts/{virtualAccountID}", + "operationId": "getCustomersByCustomerIDVirtualAccountsByVirtualAccountID", + "group": "virtualAccounts" + }, + { + "method": "put", + "path": "/customers/{customerID}/virtual_accounts/{virtualAccountID}", + "operationId": "putCustomersByCustomerIDVirtualAccountsByVirtualAccountID", + "group": "virtualAccounts" + }, + { + "method": "post", + "path": "/customers/{customerID}/virtual_accounts/{virtualAccountID}/deactivate", + "operationId": "postCustomersByCustomerIDVirtualAccountsByVirtualAccountIDDeactivate", + "group": "virtualAccounts" + }, + { + "method": "get", + "path": "/customers/{customerID}/virtual_accounts/{virtualAccountID}/history", + "operationId": "getCustomersByCustomerIDVirtualAccountsByVirtualAccountIDHistory", + "group": "virtualAccounts" + }, + { + "method": "post", + "path": "/customers/{customerID}/virtual_accounts/{virtualAccountID}/reactivate", + "operationId": "postCustomersByCustomerIDVirtualAccountsByVirtualAccountIDReactivate", + "group": "virtualAccounts" + }, + { + "method": "get", + "path": "/customers/{customerID}/wallets", + "operationId": "getCustomersByCustomerIDWallets", + "group": "bridgeWallets" + }, + { + "method": "post", + "path": "/customers/{customerID}/wallets", + "operationId": "postCustomersByCustomerIDWallets", + "group": "bridgeWallets" + }, + { + "method": "get", + "path": "/customers/{customerID}/wallets/{bridgeWalletID}", + "operationId": "getCustomersByCustomerIDWalletsByBridgeWalletID", + "group": "bridgeWallets" + }, + { + "method": "post", + "path": "/customers/tos_links", + "operationId": "postCustomersTosLinks", + "group": "customers" + }, + { + "method": "get", + "path": "/developer/cards/designs", + "operationId": "getDeveloperCardsDesigns", + "group": "cards" + }, + { + "method": "get", + "path": "/developer/cards/summary", + "operationId": "getDeveloperCardsSummary", + "group": "cards" + }, + { + "method": "get", + "path": "/developer/fee_external_account", + "operationId": "getDeveloperFeeExternalAccount", + "group": "developers" + }, + { + "method": "post", + "path": "/developer/fee_external_account", + "operationId": "postDeveloperFeeExternalAccount", + "group": "developers" + }, + { + "method": "get", + "path": "/developer/fees", + "operationId": "getDeveloperFees", + "group": "developers" + }, + { + "method": "post", + "path": "/developer/fees", + "operationId": "postDeveloperFees", + "group": "developers" + }, + { + "method": "get", + "path": "/exchange_rates", + "operationId": "getExchangeRates", + "group": "exchangeRates" + }, + { + "method": "get", + "path": "/external_accounts", + "operationId": "getExternalAccounts", + "group": "externalAccounts" + }, + { + "method": "get", + "path": "/fees/configurations", + "operationId": "getFeesConfigurations", + "group": "developerFees" + }, + { + "method": "post", + "path": "/fees/configurations", + "operationId": "postFeesConfigurations", + "group": "developerFees" + }, + { + "method": "get", + "path": "/fees/configurations/{developerFeeConfigID}", + "operationId": "getFeesConfigurationsByDeveloperFeeConfigID", + "group": "developerFees" + }, + { + "method": "put", + "path": "/fees/configurations/{developerFeeConfigID}", + "operationId": "putFeesConfigurationsByDeveloperFeeConfigID", + "group": "developerFees" + }, + { + "method": "get", + "path": "/funds_requests", + "operationId": "getFundsRequests", + "group": "fundsRequests" + }, + { + "method": "get", + "path": "/kyc_links", + "operationId": "getKycLinks", + "group": "kycLinks" + }, + { + "method": "post", + "path": "/kyc_links", + "operationId": "postKycLinks", + "group": "kycLinks" + }, + { + "method": "get", + "path": "/kyc_links/{kycLinkID}", + "operationId": "getKycLinksByKycLinkID", + "group": "kycLinks" + }, + { + "method": "get", + "path": "/liquidation_addresses", + "operationId": "getLiquidationAddresses", + "group": "liquidationAddresses" + }, + { + "method": "get", + "path": "/liquidation_addresses/drains", + "operationId": "getLiquidationAddressesDrains", + "group": "liquidationAddresses" + }, + { + "method": "get", + "path": "/liquidation_addresses/drains/pending", + "operationId": "getLiquidationAddressesDrainsPending", + "group": "liquidationAddresses" + }, + { + "method": "get", + "path": "/lists/countries", + "operationId": "getListsCountries", + "group": "lists" + }, + { + "method": "get", + "path": "/lists/occupation_codes", + "operationId": "getListsOccupationCodes", + "group": "lists" + }, + { + "method": "post", + "path": "/plaid_exchange_public_token/{link_token}", + "operationId": "postPlaidExchangePublicTokenByLinkToken", + "group": "plaid" + }, + { + "method": "get", + "path": "/prefunded_accounts", + "operationId": "getPrefundedAccounts", + "group": "prefundedAccounts" + }, + { + "method": "get", + "path": "/prefunded_accounts/{prefundedAccountID}", + "operationId": "getPrefundedAccountsByPrefundedAccountID", + "group": "prefundedAccounts" + }, + { + "method": "get", + "path": "/prefunded_accounts/{prefundedAccountID}/history", + "operationId": "getPrefundedAccountsByPrefundedAccountIDHistory", + "group": "prefundedAccounts" + }, + { + "method": "get", + "path": "/rewards/{currency}", + "operationId": "getRewardsByCurrency", + "group": "rewards" + }, + { + "method": "get", + "path": "/rewards/{currency}/customer/{customerID}", + "operationId": "getRewardsByCurrencyCustomerByCustomerID", + "group": "rewards" + }, + { + "method": "get", + "path": "/rewards/{currency}/customer/{customerID}/history", + "operationId": "getRewardsByCurrencyCustomerByCustomerIDHistory", + "group": "rewards" + }, + { + "method": "get", + "path": "/rewards/{currency}/history", + "operationId": "getRewardsByCurrencyHistory", + "group": "rewards" + }, + { + "method": "get", + "path": "/rfis", + "operationId": "getRfis", + "group": "rfis" + }, + { + "method": "get", + "path": "/rfis/{rfiID}", + "operationId": "getRfisByRfiID", + "group": "rfis" + }, + { + "method": "get", + "path": "/static_memos", + "operationId": "getStaticMemos", + "group": "staticMemos" + }, + { + "method": "get", + "path": "/static_memos/history", + "operationId": "getStaticMemosHistory", + "group": "staticMemos" + }, + { + "method": "get", + "path": "/transfers", + "operationId": "getTransfers", + "group": "transfers" + }, + { + "method": "post", + "path": "/transfers", + "operationId": "postTransfers", + "group": "transfers" + }, + { + "method": "get", + "path": "/transfers/{transferID}", + "operationId": "getTransfersByTransferID", + "group": "transfers" + }, + { + "method": "put", + "path": "/transfers/{transferID}", + "operationId": "putTransfersByTransferID", + "group": "transfers" + }, + { + "method": "delete", + "path": "/transfers/{transferID}", + "operationId": "deleteTransfersByTransferID", + "group": "transfers" + }, + { + "method": "post", + "path": "/transfers/{transferID}/execute", + "operationId": "postTransfersByTransferIDExecute", + "group": "transfers" + }, + { + "method": "get", + "path": "/transfers/pending", + "operationId": "getTransfersPending", + "group": "transfers" + }, + { + "method": "get", + "path": "/transfers/static_templates", + "operationId": "getTransfersStaticTemplates", + "group": "transfers" + }, + { + "method": "post", + "path": "/travel_rule_data/{id}", + "operationId": "postTravelRuleDataById", + "group": "travelRule" + }, + { + "method": "get", + "path": "/virtual_accounts", + "operationId": "getVirtualAccounts", + "group": "virtualAccounts" + }, + { + "method": "get", + "path": "/virtual_accounts/history", + "operationId": "getVirtualAccountsHistory", + "group": "virtualAccounts" + }, + { + "method": "get", + "path": "/wallets", + "operationId": "getWallets", + "group": "bridgeWallets" + }, + { + "method": "get", + "path": "/wallets/{bridgeWalletID}", + "operationId": "getWalletsByBridgeWalletID", + "group": "bridgeWallets" + }, + { + "method": "get", + "path": "/wallets/{bridgeWalletID}/history", + "operationId": "getWalletsByBridgeWalletIDHistory", + "group": "bridgeWallets" + }, + { + "method": "get", + "path": "/wallets/total_balances", + "operationId": "getWalletsTotalBalances", + "group": "bridgeWallets" + }, + { + "method": "get", + "path": "/webhook_events", + "operationId": "getWebhookEvents", + "group": "webhooks" + }, + { + "method": "get", + "path": "/webhooks", + "operationId": "getWebhooks", + "group": "webhooks" + }, + { + "method": "post", + "path": "/webhooks", + "operationId": "postWebhooks", + "group": "webhooks" + }, + { + "method": "put", + "path": "/webhooks/{webhookID}", + "operationId": "putWebhooksByWebhookID", + "group": "webhooks" + }, + { + "method": "delete", + "path": "/webhooks/{webhookID}", + "operationId": "deleteWebhooksByWebhookID", + "group": "webhooks" + }, + { + "method": "get", + "path": "/webhooks/{webhookID}/events", + "operationId": "getWebhooksByWebhookIDEvents", + "group": "webhooks" + }, + { + "method": "get", + "path": "/webhooks/{webhookID}/logs", + "operationId": "getWebhooksByWebhookIDLogs", + "group": "webhooks" + }, + { + "method": "post", + "path": "/webhooks/{webhookID}/send", + "operationId": "postWebhooksByWebhookIDSend", + "group": "webhooks" + } + ] +} diff --git a/packages/bridge/package.json b/packages/bridge/package.json new file mode 100644 index 0000000..8d7ca53 --- /dev/null +++ b/packages/bridge/package.json @@ -0,0 +1,87 @@ +{ + "name": "@misofm/bridge", + "version": "0.1.0", + "packageManager": "bun@1.4.0", + "description": "Portable Effect v4 SDK for the Bridge API", + "license": "Apache-2.0", + "repository": { + "type": "git", + "url": "git+https://github.com/misofm/sdks.git", + "directory": "packages/bridge" + }, + "homepage": "https://github.com/misofm/sdks#readme", + "bugs": { + "url": "https://github.com/misofm/sdks/issues" + }, + "keywords": [ + "bridge", + "effect", + "miso", + "sdk" + ], + "publishConfig": { + "access": "public" + }, + "type": "module", + "sideEffects": false, + "main": "./dist/index.js", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "default": "./dist/index.js" + }, + "./bridge": { + "types": "./dist/Bridge.d.ts", + "default": "./dist/Bridge.js" + }, + "./generated": { + "types": "./dist/generated/BridgeApi.d.ts", + "default": "./dist/generated/BridgeApi.js" + }, + "./pagination": { + "types": "./dist/Pagination.d.ts", + "default": "./dist/Pagination.js" + }, + "./webhooks": { + "types": "./dist/Webhooks.d.ts", + "default": "./dist/Webhooks.js" + }, + "./errors": { + "types": "./dist/Errors.d.ts", + "default": "./dist/Errors.js" + }, + "./package.json": "./package.json" + }, + "files": [ + "dist", + "src", + "README.md", + "docs", + "examples", + "LICENSE", + "package.json" + ], + "scripts": { + "generate": "bun scripts/generate.ts", + "generate:check": "bun scripts/generate.ts --check", + "typecheck": "tsc --noEmit -p tsconfig.json", + "test": "bun test", + "build": "tsc -p tsconfig.build.json", + "test:consumer": "bun scripts/check-consumer.ts", + "test:workerd": "bun scripts/check-workerd.ts" + }, + "devDependencies": { + "@effect/openapi-generator": "4.0.0-rc.112", + "@effect/platform-node": "4.0.0-rc.112", + "@types/bun": "^1.4.0", + "effect": "4.0.0-rc.112", + "typescript": "^7.0.2", + "wrangler": "4.137.0" + }, + "peerDependencies": { + "effect": "4.0.0-rc.112", + "typescript": "^5.7 || ^6 || ^7" + } +} diff --git a/packages/bridge/scripts/check-consumer.ts b/packages/bridge/scripts/check-consumer.ts new file mode 100644 index 0000000..2371d25 --- /dev/null +++ b/packages/bridge/scripts/check-consumer.ts @@ -0,0 +1,62 @@ +import { execFileSync } from "node:child_process" +import { copyFileSync, mkdtempSync, readFileSync, rmSync } from "node:fs" +import { tmpdir } from "node:os" +import { join, resolve } from "node:path" + +const packageDir = resolve(import.meta.dir, "..") +const fixtureDir = join(packageDir, "tests", "consumer") +const tempDir = mkdtempSync(join(tmpdir(), "misofm-bridge-consumer-")) + +try { + const packed = JSON.parse(execFileSync( + "npm", + ["pack", "--ignore-scripts", "--json", "--pack-destination", tempDir], + { cwd: packageDir } + ).toString()) as ReadonlyArray<{ filename: string; files: ReadonlyArray<{ path: string }> }> + const tarball = packed[0] + if (!tarball) throw new Error("npm pack produced no Bridge tarball") + const packageJson = JSON.parse(readFileSync(join(packageDir, "package.json"), "utf8")) as { + name: string + exports: Record + } + const packedFiles = new Set(tarball.files.map((file) => file.path)) + for (const [subpath, entry] of Object.entries(packageJson.exports)) { + if (subpath === "./package.json") continue + if (typeof entry !== "object" || entry === null || !("default" in entry) || !("types" in entry)) { + throw new Error(`Export ${subpath} must provide both ESM and declarations`) + } + for (const target of [(entry as { default: string }).default, (entry as { types: string }).types]) { + if (!packedFiles.has(target.replace(/^\.\//, ""))) { + throw new Error(`Export ${subpath} points to missing packed file ${target}`) + } + } + } + + const fixtureFiles = [ + "package.json", + "tsconfig.json", + "tsconfig.worker.json", + "consumer.ts", + "runtime.mjs", + "worker-smoke.mjs" + ] + for (const filename of fixtureFiles) copyFileSync(join(fixtureDir, filename), join(tempDir, filename)) + copyFileSync(join(tempDir, tarball.filename), join(tempDir, "bridge.tgz")) + copyFileSync( + join(packageDir, "examples", "cloudflare-worker", "src", "index.ts"), + join(tempDir, "worker.ts") + ) + + console.log("Bridge consumer: installing isolated packed package") + execFileSync("npm", ["install", "--ignore-scripts", "--no-audit", "--no-fund"], { + cwd: tempDir, + stdio: "inherit" + }) + console.log("Bridge consumer: typechecking every exported subpath") + execFileSync("npm", ["run", "check"], { cwd: tempDir, stdio: "inherit" }) + console.log("Bridge consumer: compiling and running the Worker example with mocked Fetch") + execFileSync("npm", ["run", "check:worker"], { cwd: tempDir, stdio: "inherit" }) + console.log(`Bridge consumer: OK — ${packageJson.name} ${tarball.filename}`) +} finally { + rmSync(tempDir, { recursive: true, force: true }) +} diff --git a/packages/bridge/scripts/check-workerd.ts b/packages/bridge/scripts/check-workerd.ts new file mode 100644 index 0000000..4dc6d65 --- /dev/null +++ b/packages/bridge/scripts/check-workerd.ts @@ -0,0 +1,229 @@ +import assert from "node:assert/strict" +import { spawn } from "node:child_process" +import { createRequire } from "node:module" +import { createServer as createHttpServer } from "node:http" +import { createServer as createTcpServer } from "node:net" +import { readFileSync } from "node:fs" +import { mkdtemp, rm, writeFile } from "node:fs/promises" +import { tmpdir } from "node:os" +import { dirname, join, resolve } from "node:path" +import { setTimeout as delay } from "node:timers/promises" + +const host = "127.0.0.1" +const syntheticKey = "bridge-workerd-smoke-synthetic-key" +const packageDir = resolve(import.meta.dir, "..") +const exampleDir = join(packageDir, "examples", "cloudflare-worker") +const require = createRequire(import.meta.url) + +// Bun's ambient Node compatibility declarations omit EventEmitter methods on +// net.Server and ChildProcess. Those host values implement Node's standard +// `on` method at runtime, which this script needs for listen/shutdown errors. +interface EventSource { + on(event: string, listener: (...args: Array) => void): unknown +} + +const onEvent = (target: object, event: string, listener: (...args: Array) => void): void => { + (target as unknown as EventSource).on(event, listener) +} + +interface WranglerPackage { + readonly bin: { readonly wrangler: string } +} + +interface SeenRequest { + readonly method: string | undefined + readonly url: string | undefined + readonly apiKey: string | undefined +} + +const reservePort = async (): Promise => { + const server = createTcpServer() + const port = await new Promise((resolvePort, reject) => { + onEvent(server, "error", reject) + server.listen(0, host, () => { + const address = server.address() + if (address === null || typeof address === "string") { + reject(new Error("Could not reserve a local TCP port")) + return + } + resolvePort(address.port) + }) + }) + await new Promise((resolveClose, reject) => { + server.close((error) => error ? reject(error) : resolveClose()) + }) + return port +} + +const listenOnLoopback = (server: ReturnType): Promise => + new Promise((resolvePort, reject) => { + onEvent(server, "error", reject) + server.listen(0, host, () => { + const address = server.address() + if (address === null || typeof address === "string") { + reject(new Error("Could not start the local Bridge mock")) + return + } + resolvePort(address.port) + }) + }) + +const startWrangler = (port: number, upstreamBaseUrl: string, configPath: string, stateDir: string) => { + const packageJsonPath = require.resolve("wrangler/package.json") + const wranglerPackage = JSON.parse(readFileSync(packageJsonPath, "utf8")) as WranglerPackage + const cliPath = resolve(dirname(packageJsonPath), wranglerPackage.bin.wrangler) + const child = spawn("node", [ + cliPath, + "dev", + "--config", + configPath, + "--local", + "--ip", + host, + "--port", + String(port), + "--log-level", + "info", + "--persist-to", + stateDir, + "--var", + `BRIDGE_API_KEY:${syntheticKey}`, + "--var", + `BRIDGE_API_BASE_URL:${upstreamBaseUrl}` + ], { + cwd: exampleDir, + env: { + ...process.env, + CI: "1", + NO_UPDATE_NOTIFIER: "1", + WRANGLER_SEND_METRICS: "false", + CLOUDFLARE_INCLUDE_PROCESS_ENV: "false", + CLOUDFLARE_LOAD_DEV_VARS_FROM_DOT_ENV: "false" + }, + stdio: ["ignore", "pipe", "pipe"], + detached: process.platform !== "win32" + }) + + let output = "" + const append = (chunk: Uint8Array) => { + output = `${output}${Buffer.from(chunk).toString()}`.slice(-12_000) + } + child.stdout?.on("data", append) + child.stderr?.on("data", append) + + return { + child, + get output() { + return output + } + } +} + +const waitForWorker = async ( + url: string, + process: ReturnType +): Promise => { + const deadline = Date.now() + 60_000 + while (Date.now() < deadline) { + if (process.child.exitCode !== null || process.child.signalCode !== null) { + throw new Error(`Wrangler exited before ready.\n${process.output}`) + } + try { + const response = await fetch(url, { signal: AbortSignal.timeout(500) }) + if (response.status === 404) return + } catch { + // Wrangler is still starting its local workerd server. + } + await delay(250) + } + throw new Error(`Timed out waiting for local workerd.\n${process.output}`) +} + +const stopWrangler = async (child: ReturnType): Promise => { + const childPid = child.pid + if (childPid === undefined) return + const kill = (signal: NodeJS.Signals) => { + try { + if (process.platform === "win32") child.kill(signal) + else process.kill(-childPid, signal) + } catch { + // The process or its group may already have exited. + } + } + const exited = new Promise((resolveExit) => { + if (child.exitCode !== null || child.signalCode !== null) resolveExit() + else onEvent(child, "exit", () => resolveExit()) + }) + kill("SIGTERM") + const timeout = Symbol("timeout") + if (await Promise.race([exited.then(() => true), delay(5_000).then(() => timeout)]) === timeout) { + kill("SIGKILL") + } + await exited + // Wrangler may have started workerd as a child process. Remove any survivor + // left in Wrangler's process group after its own shutdown completes. + kill("SIGKILL") +} + +const main = async (): Promise => { + const requests: Array = [] + const upstream = createHttpServer((request, response) => { + requests.push({ + method: request.method, + url: request.url, + apiKey: typeof request.headers["api-key"] === "string" ? request.headers["api-key"] : undefined + }) + if (request.method === "GET" && request.url === "/v0/customers") { + response.writeHead(200, { "content-type": "application/json" }) + response.end(JSON.stringify({ count: 0, data: [] })) + return + } + response.writeHead(404, { "content-type": "application/json" }) + response.end(JSON.stringify({ message: "unexpected mock request" })) + }) + const stateDir = await mkdtemp(join(tmpdir(), "bridge-workerd-state-")) + let upstreamListening = false + let workerd: ReturnType | undefined + try { + const sourceConfig = JSON.parse(readFileSync(join(exampleDir, "wrangler.jsonc"), "utf8")) as { + readonly name: string + readonly compatibility_date: string + readonly vars?: Record + } + const configPath = join(stateDir, "wrangler.jsonc") + await writeFile(configPath, JSON.stringify({ + ...sourceConfig, + name: `${sourceConfig.name}-workerd-smoke`, + main: join(exampleDir, "src", "index.ts") + }, null, 2), { flag: "wx" }) + const upstreamPort = await listenOnLoopback(upstream) + upstreamListening = true + const workerPort = await reservePort() + workerd = startWrangler(workerPort, `http://${host}:${upstreamPort}/v0`, configPath, stateDir) + await waitForWorker(`http://${host}:${workerPort}/__workerd_ready`, workerd) + const response = await fetch(`http://${host}:${workerPort}/customers`, { + method: "GET", + signal: AbortSignal.timeout(15_000) + }) + assert.equal(response.status, 200) + assert.deepEqual(await response.json(), { count: 0, data: [] }) + assert.deepEqual(requests, [{ + method: "GET", + url: "/v0/customers", + apiKey: syntheticKey + }]) + console.log("Bridge workerd runtime smoke: OK (local workerd, mock upstream, synthetic key)") + } catch (error) { + throw new Error(`Bridge workerd runtime smoke failed.\n${workerd?.output ?? "Wrangler did not start."}`, { cause: error }) + } finally { + if (workerd !== undefined) await stopWrangler(workerd.child) + if (upstreamListening) { + await new Promise((resolveClose, reject) => { + upstream.close((error) => error ? reject(error) : resolveClose()) + }) + } + await rm(stateDir, { recursive: true, force: true }) + } +} + +await main() diff --git a/packages/bridge/scripts/generate.ts b/packages/bridge/scripts/generate.ts new file mode 100644 index 0000000..516591c --- /dev/null +++ b/packages/bridge/scripts/generate.ts @@ -0,0 +1,786 @@ +import * as OpenApiGenerator from "@effect/openapi-generator/OpenApiGenerator" +import * as OpenApiPatch from "@effect/openapi-generator/OpenApiPatch" +import * as Effect from "effect/Effect" +import * as Schema from "effect/Schema" +import type { OpenAPISpec } from "effect/unstable/httpapi/OpenApi" +import { mkdir, readFile, writeFile } from "node:fs/promises" +import { dirname, resolve } from "node:path" + +const packageRoot = resolve(import.meta.dir, "..") +const sourcePath = resolve(packageRoot, "openapi/bridge-2026-09-23.json") +const manifestPath = resolve(packageRoot, "openapi/operation-manifest.json") +const overlayPath = resolve(packageRoot, "openapi/normalization-overlay.json") +const warningBaselinePath = resolve(packageRoot, "openapi/generator-warnings.json") +const generatedPath = resolve(packageRoot, "src/generated/BridgeApi.ts") + +export const BRIDGE_SPEC_SHA256 = "e8aee6cee1b5518d81f384c8b718dd9d9154dd9eb55345ff73d8b8dbe88327f2" +export const BRIDGE_OPERATION_COUNT = 134 +export const BRIDGE_PATH_COUNT = 100 +export const BRIDGE_SCHEMA_COUNT = 263 + +const methods = ["get", "put", "post", "delete", "options", "head", "patch", "trace"] as const +type HttpMethod = (typeof methods)[number] + +interface OperationEntry { + readonly method: HttpMethod + readonly path: string + readonly operationId: string + readonly group: string +} + +interface OperationManifest { + readonly sourceSha256: string + readonly groups: Readonly> + readonly operations: ReadonlyArray +} + +interface GeneratorWarning { + readonly code: string + readonly message: string + readonly path?: string + readonly method?: string + readonly operationId?: string +} + +interface NormalizationOverlay { + readonly patches: unknown + readonly objectSchemas: ReadonlyArray<{ + readonly pointer: string + readonly reason: string + }> + readonly propertyObjectSchemas: { + readonly reason: string + readonly pointers: ReadonlyArray + } + readonly schemaVariants: ReadonlyArray<{ + readonly source: string + readonly input: string + readonly outputRequired?: ReadonlyArray + readonly inputRequired?: ReadonlyArray + readonly requestRefs: ReadonlyArray + readonly inputRefOverrides: ReadonlyArray<{ + readonly pointer: string + readonly schema: string + }> + readonly reason: string + }> + readonly generatedSchemaOverrides: ReadonlyArray<{ + readonly name: string + readonly fromType: string + readonly type: string + readonly fromSchema: string + readonly schema: string + readonly reason: string + }> +} + +interface WarningBaseline { + readonly items: ReadonlyArray + readonly review: Readonly> +} + +export interface BridgeGeneration { + readonly sourceHash: string + readonly operationCount: number + readonly generatedOperationCount: number + readonly pathCount: number + readonly schemaCount: number + readonly output: string + readonly warnings: ReadonlyArray +} + +const GROUP_IDS_BY_TAG: Readonly> = { + "API Keys": "apiKeys", + "Associated Persons": "associatedPersons", + "Batch Settlements": "batchSettlements", + "Bridge Wallets": "bridgeWallets", + Cards: "cards", + "Crypto Return Policies": "cryptoReturnPolicies", + Customers: "customers", + "Developer Fees": "developerFees", + Developers: "developers", + "Exchange Rates": "exchangeRates", + "External Accounts": "externalAccounts", + "Fiat Payout Configuration": "fiatPayoutConfiguration", + "Funds Requests": "fundsRequests", + "KYC Links": "kycLinks", + "Liquidation Addresses": "liquidationAddresses", + Lists: "lists", + Plaid: "plaid", + "Prefunded Accounts": "prefundedAccounts", + RFIs: "rfis", + Rewards: "rewards", + Sandbox: "sandbox", + "Static Memos": "staticMemos", + Transfers: "transfers", + "Travel Rule": "travelRule", + "Virtual Accounts": "virtualAccounts", + Webhooks: "webhooks" +} + +const OPTIONAL_CARD_PAYLOAD_UNIONS = [ + { + operationId: "postCustomersByCustomerIDCardAccountsByCardAccountIDEphemeralKeys", + requestSchema: "PostCustomersByCustomerIDCardAccountsByCardAccountIDEphemeralKeysRequestJson" + }, + { + operationId: "postCustomersByCustomerIDCardAccountsByCardAccountIDFreeze", + requestSchema: "PostCustomersByCustomerIDCardAccountsByCardAccountIDFreezeRequestJson" + }, + { + operationId: "postCustomersByCustomerIDCardAccountsByCardAccountIDUnfreeze", + requestSchema: "PostCustomersByCustomerIDCardAccountsByCardAccountIDUnfreezeRequestJson" + }, + { + operationId: "postCustomersByCustomerIDCardAccountsByCardAccountIDCreateMobileWalletProvisioningRequest", + requestSchema: "PostCustomersByCustomerIDCardAccountsByCardAccountIDCreateMobileWalletProvisioningRequestRequestJson" + } +] as const + +const isRecord = (value: unknown): value is Record => + typeof value === "object" && value !== null && !Array.isArray(value) + +const fail = (message: string): never => { + throw new Error(`[Bridge codegen] ${message}`) +} + +const sha256 = async (input: Uint8Array): Promise => { + const digestInput = new Uint8Array(input.byteLength) + digestInput.set(input) + const digest = await crypto.subtle.digest("SHA-256", digestInput) + return Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("") +} + +const parseJson = (text: string, source: string): unknown => { + try { + return JSON.parse(text) as unknown + } catch (error) { + const reason = error instanceof Error ? error.message : String(error) + return fail(`could not parse ${source}: ${reason}`) + } +} + +const readObject = async (path: string): Promise> => { + const content = await readFile(path, "utf8") + const parsed = parseJson(content, path) + if (!isRecord(parsed)) return fail(`${path} must contain a JSON object`) + return parsed +} + +const assertSourceSnapshot = async (): Promise<{ readonly text: string; readonly hash: string }> => { + const bytes = await readFile(sourcePath) + const hash = await sha256(bytes) + if (hash !== BRIDGE_SPEC_SHA256) { + return fail(`raw Bridge spec checksum mismatch: expected ${BRIDGE_SPEC_SHA256}, got ${hash}`) + } + return { text: new TextDecoder().decode(bytes), hash } +} + +const methodOrder = new Map(methods.map((method, index) => [method, index])) + +const methodIsValid = (value: unknown): value is HttpMethod => + typeof value === "string" && methods.some((method) => method === value) + +const pascalSegment = (value: string): string => { + const words = value.match(/[A-Za-z0-9]+/g) ?? [] + return words.map((word) => `${word.slice(0, 1).toUpperCase()}${word.slice(1)}`).join("") +} + +const operationIdFor = (method: HttpMethod, path: string): string => { + const suffix = path.split("/").filter(Boolean).map((segment) => { + if (segment.startsWith("{") && segment.endsWith("}")) { + return `By${pascalSegment(segment.slice(1, -1))}` + } + return pascalSegment(segment) + }).join("") + const prefix = method === "get" ? "get" : `${method.slice(0, 1).toLowerCase()}${method.slice(1)}` + return `${prefix}${suffix}` +} + +const listRawOperations = (spec: Record): ReadonlyArray<{ + readonly path: string + readonly method: HttpMethod + readonly tags: ReadonlyArray +}> => { + const paths = spec.paths + if (!isRecord(paths)) return fail("raw spec has no paths object") + const operations: Array<{ path: string; method: HttpMethod; tags: ReadonlyArray }> = [] + for (const [path, pathItem] of Object.entries(paths)) { + if (!isRecord(pathItem)) continue + for (const [methodValue, operationValue] of Object.entries(pathItem)) { + if (!methodIsValid(methodValue) || !isRecord(operationValue)) continue + const rawTags = operationValue.tags + const tags = Array.isArray(rawTags) ? rawTags.filter((tag): tag is string => typeof tag === "string") : [] + operations.push({ path, method: methodValue, tags }) + } + } + return operations.sort((left, right) => + left.path.localeCompare(right.path) || (methodOrder.get(left.method)! - methodOrder.get(right.method)!) + ) +} + +const makeOperationManifest = ( + spec: Record, + sourceHash: string +): OperationManifest => { + const operations = listRawOperations(spec) + if (operations.length !== BRIDGE_OPERATION_COUNT) { + return fail(`raw snapshot has ${operations.length} operations, expected ${BRIDGE_OPERATION_COUNT}`) + } + const groups: Record = {} + for (const operation of operations) { + if (operation.tags.length !== 1) { + return fail(`${operation.method.toUpperCase()} ${operation.path} must have exactly one upstream tag`) + } + const sourceTag = operation.tags[0]! + const group = GROUP_IDS_BY_TAG[sourceTag] + if (group === undefined) return fail(`no stable group key is defined for upstream tag ${sourceTag}`) + groups[sourceTag] = group + } + const entries: Array = operations.map(({ method, path, tags }) => ({ + method, + path, + operationId: operationIdFor(method, path), + group: GROUP_IDS_BY_TAG[tags[0]!]! + })) + const operationIds = new Set(entries.map((entry) => entry.operationId)) + if (operationIds.size !== entries.length) return fail("generated operation IDs are not unique") + return { + sourceSha256: sourceHash, + groups: Object.fromEntries(Object.entries(groups).sort(([left], [right]) => left.localeCompare(right))), + operations: entries + } +} + +const readManifest = (value: unknown): OperationManifest => { + if (!isRecord(value) || typeof value.sourceSha256 !== "string" || !isRecord(value.groups) || !Array.isArray(value.operations)) { + return fail("operation manifest must contain sourceSha256, groups, and operations") + } + const groups: Record = {} + for (const [tag, group] of Object.entries(value.groups)) { + if (typeof group !== "string" || !/^[a-z][A-Za-z0-9]*$/.test(group)) { + return fail(`invalid stable group key for ${tag}`) + } + groups[tag] = group + } + const operations: Array = [] + for (const [index, entry] of value.operations.entries()) { + if (!isRecord(entry) || !methodIsValid(entry.method) || typeof entry.path !== "string" || + typeof entry.operationId !== "string" || typeof entry.group !== "string") { + return fail(`invalid operation manifest entry at index ${index}`) + } + operations.push({ + method: entry.method, + path: entry.path, + operationId: entry.operationId, + group: entry.group + }) + } + return { sourceSha256: value.sourceSha256, groups, operations } +} + +const validateManifest = (manifest: OperationManifest, rawSpec: Record, sourceHash: string): void => { + if (manifest.sourceSha256 !== sourceHash) return fail("operation manifest is pinned to a different raw spec checksum") + if (manifest.operations.length !== BRIDGE_OPERATION_COUNT) { + return fail(`operation manifest has ${manifest.operations.length} entries, expected ${BRIDGE_OPERATION_COUNT}`) + } + const rawOperations = listRawOperations(rawSpec) + const byKey = new Map(manifest.operations.map((entry) => [`${entry.method} ${entry.path}`, entry])) + if (byKey.size !== manifest.operations.length) return fail("operation manifest contains duplicate method/path entries") + if (new Set(manifest.operations.map((entry) => entry.operationId)).size !== manifest.operations.length) { + return fail("operation manifest contains duplicate operation IDs") + } + if (rawOperations.length !== byKey.size) return fail("operation manifest does not exactly cover the raw operation surface") + for (const operation of rawOperations) { + const key = `${operation.method} ${operation.path}` + const entry = byKey.get(key) + if (entry === undefined) return fail(`operation manifest is missing ${operation.method.toUpperCase()} ${operation.path}`) + const sourceTag = operation.tags[0] + if (sourceTag === undefined || manifest.groups[sourceTag] !== entry.group) { + return fail(`operation manifest group mismatch for ${operation.method.toUpperCase()} ${operation.path}`) + } + } + const rawTags = new Set(rawOperations.flatMap((operation) => operation.tags)) + if (rawTags.size !== Object.keys(manifest.groups).length || [...rawTags].some((tag) => manifest.groups[tag] === undefined)) { + return fail("operation manifest groups do not exactly cover the upstream tags") + } + const normalizedGroups = new Set(Object.values(manifest.groups)) + if (normalizedGroups.size !== Object.values(manifest.groups).length) return fail("stable group keys must be unique") +} + +const normalizeSpec = ( + patched: Schema.Json, + manifest: OperationManifest +): Record => { + const spec: unknown = JSON.parse(JSON.stringify(patched)) as unknown + if (!isRecord(spec) || !isRecord(spec.paths)) return fail("normalized OpenAPI document has no paths object") + const entryByKey = new Map(manifest.operations.map((entry) => [`${entry.method} ${entry.path}`, entry])) + let count = 0 + for (const [path, pathItem] of Object.entries(spec.paths)) { + if (!isRecord(pathItem)) continue + for (const [methodValue, operationValue] of Object.entries(pathItem)) { + if (!methodIsValid(methodValue) || !isRecord(operationValue)) continue + const entry = entryByKey.get(`${methodValue} ${path}`) + if (entry === undefined) return fail(`normalized spec has no manifest entry for ${methodValue.toUpperCase()} ${path}`) + operationValue.operationId = entry.operationId + operationValue.tags = [entry.group] + if (operationValue["x-hidden"] === true) { + const summary = typeof operationValue.summary === "string" ? operationValue.summary : entry.operationId + operationValue.summary = `[Upstream x-hidden] ${summary}` + } else if (operationValue.deprecated === true) { + const summary = typeof operationValue.summary === "string" ? operationValue.summary : entry.operationId + operationValue.summary = `[Deprecated upstream] ${summary}` + } + count += 1 + } + } + if (count !== BRIDGE_OPERATION_COUNT) return fail(`normalized ${count} operations, expected ${BRIDGE_OPERATION_COUNT}`) + if (Array.isArray(spec.tags)) { + for (const tag of spec.tags) { + if (!isRecord(tag) || typeof tag.name !== "string") continue + const group = manifest.groups[tag.name] + if (group !== undefined) tag.name = group + } + } + return spec +} + +const readOverlay = async (): Promise => { + const parsed = await readObject(overlayPath) + if (!Array.isArray(parsed.patches)) return fail("normalization overlay must contain a patches array") + if (!Array.isArray(parsed.objectSchemas)) return fail("normalization overlay must contain objectSchemas") + const objectSchemas: Array = [] + const objectSchemaPointers = new Set() + for (const [index, value] of parsed.objectSchemas.entries()) { + if (!isRecord(value) || typeof value.pointer !== "string" || !value.pointer.startsWith("/") || + typeof value.reason !== "string" || value.reason.trim().length === 0) { + return fail(`invalid object schema normalization at index ${index}`) + } + if (objectSchemaPointers.has(value.pointer)) return fail(`duplicate object schema normalization for ${value.pointer}`) + objectSchemaPointers.add(value.pointer) + objectSchemas.push({ pointer: value.pointer, reason: value.reason }) + } + if (!isRecord(parsed.propertyObjectSchemas) || typeof parsed.propertyObjectSchemas.reason !== "string" || + parsed.propertyObjectSchemas.reason.trim().length === 0 || !Array.isArray(parsed.propertyObjectSchemas.pointers)) { + return fail("normalization overlay must contain propertyObjectSchemas with a reason and pointers") + } + const propertyObjectSchemaPointers: Array = [] + const propertyObjectSchemaPointerSet = new Set() + for (const [index, pointer] of parsed.propertyObjectSchemas.pointers.entries()) { + if (typeof pointer !== "string" || !pointer.startsWith("/")) { + return fail(`invalid property object schema pointer at index ${index}`) + } + if (propertyObjectSchemaPointerSet.has(pointer)) { + return fail(`duplicate property object schema pointer ${pointer}`) + } + propertyObjectSchemaPointerSet.add(pointer) + propertyObjectSchemaPointers.push(pointer) + } + if (JSON.stringify(propertyObjectSchemaPointers) !== JSON.stringify([...propertyObjectSchemaPointers].sort())) { + return fail("property object schema pointers must be sorted for deterministic review") + } + if (!Array.isArray(parsed.schemaVariants)) return fail("normalization overlay must contain schemaVariants") + const schemaVariants: Array = [] + const inputSchemaNames = new Set() + for (const [index, value] of parsed.schemaVariants.entries()) { + if (!isRecord(value) || typeof value.source !== "string" || typeof value.input !== "string" || + typeof value.reason !== "string" || value.reason.trim().length === 0 || !Array.isArray(value.requestRefs) || + !Array.isArray(value.inputRefOverrides)) { + return fail(`invalid schema variant at index ${index}`) + } + if (inputSchemaNames.has(value.input)) return fail(`duplicate input schema variant ${value.input}`) + inputSchemaNames.add(value.input) + const readRequired = (name: "inputRequired" | "outputRequired"): ReadonlyArray | undefined => { + const required = value[name] + if (required === undefined) return undefined + if (!Array.isArray(required) || required.some((field) => typeof field !== "string")) { + return fail(`${name} for ${value.source} must contain only property names`) + } + return required as Array + } + const requestRefs: Array = [] + for (const [refIndex, pointer] of value.requestRefs.entries()) { + if (typeof pointer !== "string" || !pointer.startsWith("/")) { + return fail(`invalid request reference pointer at ${value.source}[${refIndex}]`) + } + requestRefs.push(pointer) + } + const inputRefOverrides: Array = [] + for (const [refIndex, override] of value.inputRefOverrides.entries()) { + if (!isRecord(override) || typeof override.pointer !== "string" || !override.pointer.startsWith("/") || + typeof override.schema !== "string") { + return fail(`invalid cloned reference override at ${value.source}[${refIndex}]`) + } + inputRefOverrides.push({ pointer: override.pointer, schema: override.schema }) + } + schemaVariants.push({ + source: value.source, + input: value.input, + ...(readRequired("outputRequired") === undefined ? {} : { outputRequired: readRequired("outputRequired")! }), + ...(readRequired("inputRequired") === undefined ? {} : { inputRequired: readRequired("inputRequired")! }), + requestRefs, + inputRefOverrides, + reason: value.reason + }) + } + if (!Array.isArray(parsed.generatedSchemaOverrides)) { + return fail("normalization overlay must contain generatedSchemaOverrides") + } + const generatedSchemaOverrides: Array = [] + for (const [index, value] of parsed.generatedSchemaOverrides.entries()) { + if (!isRecord(value) || typeof value.name !== "string" || typeof value.fromType !== "string" || + typeof value.type !== "string" || typeof value.fromSchema !== "string" || + typeof value.schema !== "string" || typeof value.reason !== "string" || value.reason.trim().length === 0) { + return fail(`invalid generated schema override at index ${index}`) + } + generatedSchemaOverrides.push({ + name: value.name, + fromType: value.fromType, + type: value.type, + fromSchema: value.fromSchema, + schema: value.schema, + reason: value.reason + }) + } + return { + patches: parsed.patches, + objectSchemas, + propertyObjectSchemas: { + reason: parsed.propertyObjectSchemas.reason, + pointers: propertyObjectSchemaPointers + }, + schemaVariants, + generatedSchemaOverrides + } +} + +const pointerSegments = (pointer: string): ReadonlyArray => + pointer.split("/").slice(1).map((segment) => segment.replace(/~1/g, "/").replace(/~0/g, "~")) + +const resolvePointer = (value: unknown, pointer: string, source: string): unknown => { + let current = value + for (const segment of pointerSegments(pointer)) { + if (Array.isArray(current)) { + const index = Number(segment) + if (!Number.isInteger(index) || index < 0 || index >= current.length) return fail(`${source}: pointer ${pointer} does not resolve`) + current = current[index] + } else if (isRecord(current) && segment in current) { + current = current[segment] + } else { + return fail(`${source}: pointer ${pointer} does not resolve`) + } + } + return current +} + +const setPointer = (value: unknown, pointer: string, replacement: unknown, source: string): void => { + const segments = [...pointerSegments(pointer)] + const leaf = segments.pop() + if (leaf === undefined) return fail(`${source}: cannot replace the document root`) + const parentPointer = `/${segments.map((segment) => segment.replace(/~/g, "~0").replace(/\//g, "~1")).join("/")}` + const parent = segments.length === 0 ? value : resolvePointer(value, parentPointer, source) + if (Array.isArray(parent)) { + const index = Number(leaf) + if (!Number.isInteger(index) || index < 0 || index >= parent.length) return fail(`${source}: pointer ${pointer} does not resolve`) + parent[index] = replacement + } else if (isRecord(parent) && leaf in parent) { + parent[leaf] = replacement + } else { + return fail(`${source}: pointer ${pointer} does not resolve`) + } +} + +const collectPropertyObjectSchemaPointers = ( + rawSpec: unknown, + explicitlyNormalizedPointers: ReadonlySet +): ReadonlyArray => { + if (!isRecord(rawSpec) || !isRecord(rawSpec.components) || !isRecord(rawSpec.components.schemas)) { + return fail("raw spec components.schemas must be an object") + } + const pointers: Array = [] + const visit = (value: unknown, pointer: string): void => { + if (Array.isArray(value)) { + for (const [index, item] of value.entries()) visit(item, `${pointer}/${index}`) + return + } + if (!isRecord(value)) return + const hasObjectFields = "properties" in value || Array.isArray(value.required) + const isComposed = "allOf" in value || "oneOf" in value || "anyOf" in value + if (hasObjectFields && !("type" in value) && !isComposed && !explicitlyNormalizedPointers.has(pointer)) { + pointers.push(pointer) + } + for (const [key, nested] of Object.entries(value)) { + const escapedKey = key.replace(/~/g, "~0").replace(/\//g, "~1") + visit(nested, `${pointer}/${escapedKey}`) + } + } + for (const [name, schema] of Object.entries(rawSpec.components.schemas)) { + const escapedName = name.replace(/~/g, "~0").replace(/\//g, "~1") + visit(schema, `/components/schemas/${escapedName}`) + } + return pointers.sort() +} + +const applyOverlay = (rawSpec: unknown, overlay: NormalizationOverlay): Schema.Json => { + const document = Schema.decodeUnknownSync(Schema.Json)(rawSpec) + const explicitlyNormalizedPointers = new Set(overlay.objectSchemas.map(({ pointer }) => pointer)) + const discoveredPropertyObjectSchemaPointers = collectPropertyObjectSchemaPointers(rawSpec, explicitlyNormalizedPointers) + if (JSON.stringify(discoveredPropertyObjectSchemaPointers) !== JSON.stringify(overlay.propertyObjectSchemas.pointers)) { + return fail( + `property object schema inventory changed; found ${discoveredPropertyObjectSchemaPointers.length} pointers, overlay records ${overlay.propertyObjectSchemas.pointers.length}; review openapi/normalization-overlay.json` + ) + } + const objectSchemaPatches = overlay.objectSchemas.flatMap(({ pointer, reason }) => [ + { op: "add" as const, path: `${pointer}/type`, value: "object", description: reason }, + { op: "add" as const, path: `${pointer}/additionalProperties`, value: true, description: reason } + ]) + const propertyObjectSchemaPatches = overlay.propertyObjectSchemas.pointers.flatMap((pointer) => { + const node = resolvePointer(rawSpec, pointer, "property object schema normalization") + if (!isRecord(node)) return fail(`property object schema ${pointer} is not an object`) + return [ + { op: "add" as const, path: `${pointer}/type`, value: "object", description: overlay.propertyObjectSchemas.reason }, + ...("additionalProperties" in node ? [] : [{ + op: "add" as const, + path: `${pointer}/additionalProperties`, + value: true, + description: overlay.propertyObjectSchemas.reason + }]) + ] + }) + const patch = Schema.decodeUnknownSync(OpenApiPatch.JsonPatchDocument)([ + ...(overlay.patches as ReadonlyArray), + ...objectSchemaPatches, + ...propertyObjectSchemaPatches + ]) + const patched = Effect.runSync(OpenApiPatch.applyPatches([ + { source: "openapi/normalization-overlay.json", patch } + ], document)) + const normalized = Schema.decodeUnknownSync(Schema.Json)(patched) + const components = resolvePointer(normalized, "/components/schemas", "normalization overlay") + if (!isRecord(components)) return fail("raw spec components.schemas must be an object") + for (const variant of overlay.schemaVariants) { + const sourceSchema = components[variant.source] + if (!isRecord(sourceSchema)) return fail(`schema variant source ${variant.source} is missing or is not an object`) + if (components[variant.input] !== undefined) return fail(`schema variant ${variant.input} already exists in the raw spec`) + const inputSchema = structuredClone(sourceSchema) + if (variant.outputRequired !== undefined) { + if (!Array.isArray(sourceSchema.required)) return fail(`schema variant source ${variant.source} has no required array`) + sourceSchema.required = [...variant.outputRequired] + } + if (variant.inputRequired !== undefined) inputSchema.required = [...variant.inputRequired] + for (const override of variant.inputRefOverrides) { + setPointer(inputSchema, override.pointer, `#/components/schemas/${override.schema}`, `${variant.input} reference override`) + } + components[variant.input] = inputSchema + for (const pointer of variant.requestRefs) { + setPointer(normalized, pointer, `#/components/schemas/${variant.input}`, `${variant.input} request reference`) + } + } + return Schema.decodeUnknownSync(Schema.Json)(normalized) +} + +const generateSource = (spec: Record): { + readonly output: string + readonly warnings: ReadonlyArray +} => { + const warnings: Array = [] + const output = Effect.runSync(Effect.gen(function*() { + const generator = yield* OpenApiGenerator.OpenApiGenerator + return yield* generator.generate(spec as unknown as OpenAPISpec, { + name: "BridgeApi", + format: "httpapi", + onWarning: (warning) => { + warnings.push({ + code: warning.code, + message: warning.message, + ...(warning.path === undefined ? {} : { path: warning.path }), + ...(warning.method === undefined ? {} : { method: warning.method }), + ...(warning.operationId === undefined ? {} : { operationId: warning.operationId }) + }) + } + }) + }).pipe(Effect.provide(OpenApiGenerator.layerTransformerSchema))) + return { output: `${output.trimEnd()}\n`, warnings } +} + +const applyGeneratedSchemaOverrides = ( + output: string, + overrides: NormalizationOverlay["generatedSchemaOverrides"] +): string => { + let normalized = output + for (const override of overrides) { + const typeBefore = `export type ${override.name} = ${override.fromType}` + const typeAfter = `export type ${override.name} = ${override.type}` + const schemaBefore = `export const ${override.name} = ${override.fromSchema}` + const schemaAfter = `export const ${override.name} = ${override.schema}` + for (const [before, after] of [[typeBefore, typeAfter], [schemaBefore, schemaAfter]] as const) { + const first = normalized.indexOf(before) + if (first < 0 || normalized.indexOf(before, first + before.length) >= 0) { + return fail(`generated schema override ${override.name} did not match one exact declaration`) + } + normalized = normalized.slice(0, first) + after + normalized.slice(first + before.length) + } + } + return normalized +} + +// rc.112's union encoder can select NoContent and erase supplied JSON objects when it is first. +const applyOptionalCardPayloadUnionOrder = (output: string): string => { + const noContentFirst = /payload: \[HttpApiSchema\.NoContent,/g + const noContentFirstCount = output.match(noContentFirst)?.length ?? 0 + if (noContentFirstCount !== OPTIONAL_CARD_PAYLOAD_UNIONS.length) { + return fail(`expected ${OPTIONAL_CARD_PAYLOAD_UNIONS.length} optional card payload unions with NoContent first, found ${noContentFirstCount}`) + } + + let normalized = output + for (const { operationId, requestSchema } of OPTIONAL_CARD_PAYLOAD_UNIONS) { + const endpoint = `HttpApiEndpoint.post("${operationId}", ` + const endpointIndex = normalized.indexOf(endpoint) + if (endpointIndex < 0 || normalized.indexOf(endpoint, endpointIndex + endpoint.length) >= 0) { + return fail(`optional card payload correction did not match one exact endpoint: ${operationId}`) + } + + const lineEnd = normalized.indexOf("\n", endpointIndex) + const before = `payload: [HttpApiSchema.NoContent, ${requestSchema}]` + const after = `payload: [${requestSchema}, HttpApiSchema.NoContent]` + const payloadIndex = normalized.indexOf(before, endpointIndex) + if (payloadIndex < endpointIndex || payloadIndex + before.length > lineEnd || + normalized.indexOf(before) !== payloadIndex || normalized.indexOf(after) >= 0) { + return fail(`optional card payload correction did not match one exact payload union: ${operationId}`) + } + normalized = normalized.slice(0, payloadIndex) + after + normalized.slice(payloadIndex + before.length) + } + + if ((normalized.match(noContentFirst)?.length ?? 0) !== 0) { + return fail("optional card payload correction left a NoContent-first payload union") + } + return normalized +} + +const warningKey = (warning: GeneratorWarning): string => JSON.stringify({ + code: warning.code, + path: warning.path ?? null, + method: warning.method ?? null, + operationId: warning.operationId ?? null, + message: warning.message +}) + +const readWarningBaseline = async (): Promise => { + const parsed = await readObject(warningBaselinePath) + if (!Array.isArray(parsed.items) || !isRecord(parsed.review)) { + return fail("generator-warnings.json must contain items and review") + } + const items: Array = [] + for (const [index, warning] of parsed.items.entries()) { + if (!isRecord(warning) || typeof warning.code !== "string" || typeof warning.message !== "string") { + return fail(`invalid reviewed generator warning at index ${index}`) + } + items.push(warning as unknown as GeneratorWarning) + } + const review: Record = {} + for (const [code, explanation] of Object.entries(parsed.review)) { + if (typeof explanation !== "string" || explanation.trim().length === 0) { + return fail(`generator warning review for ${code} must explain its handling`) + } + review[code] = explanation + } + return { items, review } +} + +const assertWarningsReviewed = (warnings: ReadonlyArray, baseline: WarningBaseline): void => { + const expected = baseline.items.map(warningKey).sort() + const actual = warnings.map(warningKey).sort() + if (JSON.stringify(actual) !== JSON.stringify(expected)) { + return fail(`generator warning set changed; found ${warnings.length} warnings, baseline has ${baseline.items.length}`) + } + const codes = new Set(warnings.map((warning) => warning.code)) + for (const code of codes) { + if (baseline.review[code] === undefined) return fail(`generator warning code ${code} has no review rationale`) + } +} + +export const generateBridgeApi = async (): Promise => { + const snapshot = await assertSourceSnapshot() + const rawSpec = parseJson(snapshot.text, sourcePath) + if (!isRecord(rawSpec) || !isRecord(rawSpec.components) || !isRecord(rawSpec.components.schemas)) { + return fail("official Bridge spec is missing components.schemas") + } + if (!isRecord(rawSpec.paths) || Object.keys(rawSpec.paths).length !== BRIDGE_PATH_COUNT) { + return fail(`official Bridge spec must contain ${BRIDGE_PATH_COUNT} paths`) + } + if (Object.keys(rawSpec.components.schemas).length !== BRIDGE_SCHEMA_COUNT) { + return fail(`official Bridge spec must contain ${BRIDGE_SCHEMA_COUNT} component schemas`) + } + const manifest = readManifest(parseJson(await readFile(manifestPath, "utf8"), manifestPath)) + validateManifest(manifest, rawSpec, snapshot.hash) + const overlay = await readOverlay() + const patched = applyOverlay(rawSpec, overlay) + const normalized = normalizeSpec(patched, manifest) + const generated = generateSource(normalized) + const schemaOverrides = applyGeneratedSchemaOverrides(generated.output, overlay.generatedSchemaOverrides) + const payloadUnionOrder = applyOptionalCardPayloadUnionOrder(schemaOverrides) + // The upstream generator currently leaves trailing spaces on endpoint + // annotation lines. Normalize them here so regeneration stays deterministic + // and the committed output passes repository whitespace checks. + const output = `${payloadUnionOrder.replace(/[ \t]+$/gm, "").trimEnd()}\n` + const generatedOperationCount = (output.match(/HttpApiEndpoint\.(?:get|put|post|delete|options|head|patch|trace)\(/g) ?? []).length + if (generatedOperationCount !== BRIDGE_OPERATION_COUNT) { + return fail(`generator emitted ${generatedOperationCount} endpoints, expected ${BRIDGE_OPERATION_COUNT}`) + } + return { + sourceHash: snapshot.hash, + operationCount: manifest.operations.length, + generatedOperationCount, + pathCount: Object.keys(rawSpec.paths).length, + schemaCount: Object.keys(rawSpec.components.schemas).length, + output, + warnings: generated.warnings + } +} + +const bootstrapOperationManifest = async (): Promise => { + const snapshot = await assertSourceSnapshot() + const rawSpec = parseJson(snapshot.text, sourcePath) + if (!isRecord(rawSpec)) return fail("official Bridge spec must be an object") + const manifest = makeOperationManifest(rawSpec, snapshot.hash) + const output = `${JSON.stringify(manifest, null, 2)}\n` + await writeFile(manifestPath, output) + console.log(`Wrote ${manifest.operations.length} stable operation IDs across ${Object.keys(manifest.groups).length} groups.`) +} + +const writeWarningBaseline = async (warnings: ReadonlyArray): Promise => { + const prior = await readWarningBaseline().catch(() => ({ items: [], review: {} })) + const output = `${JSON.stringify({ items: warnings, review: prior.review }, null, 2)}\n` + await writeFile(warningBaselinePath, output) + console.log(`Recorded ${warnings.length} generator warning instances for review.`) +} + +const main = async (): Promise => { + const args = new Set(process.argv.slice(2)) + if (args.has("--write-operation-manifest")) { + await bootstrapOperationManifest() + return + } + const checkOnly = args.has("--check") + const updateWarnings = args.has("--update-warning-baseline") + const generation = await generateBridgeApi() + if (updateWarnings) { + await writeWarningBaseline(generation.warnings) + } else { + const baseline = await readWarningBaseline() + assertWarningsReviewed(generation.warnings, baseline) + } + const current = await Bun.file(generatedPath).text().catch(() => "") + if (checkOnly) { + if (current !== generation.output) return fail("src/generated/BridgeApi.ts is stale; run `bun run generate`") + console.log(`Bridge API generation is current (${generation.generatedOperationCount} endpoints, ${generation.schemaCount} schemas).`) + return + } + await mkdir(dirname(generatedPath), { recursive: true }) + await writeFile(generatedPath, generation.output) + console.log(`Generated Bridge API (${generation.generatedOperationCount} endpoints, ${generation.schemaCount} schemas).`) +} + +if (import.meta.main) { + await main() +} diff --git a/packages/bridge/src/Bridge.ts b/packages/bridge/src/Bridge.ts new file mode 100644 index 0000000..9b68164 --- /dev/null +++ b/packages/bridge/src/Bridge.ts @@ -0,0 +1,164 @@ +import * as Context from "effect/Context" +import * as Effect from "effect/Effect" +import * as Layer from "effect/Layer" +import * as Schema from "effect/Schema" +import * as Stream from "effect/Stream" +import * as HttpApi from "effect/unstable/httpapi/HttpApi" +import * as HttpApiClient from "effect/unstable/httpapi/HttpApiClient" +import * as HttpApiEndpoint from "effect/unstable/httpapi/HttpApiEndpoint" +import * as HttpApiGroup from "effect/unstable/httpapi/HttpApiGroup" +import * as HttpApiSchema from "effect/unstable/httpapi/HttpApiSchema" +import * as HttpClient from "effect/unstable/http/HttpClient" +import * as HttpClientResponse from "effect/unstable/http/HttpClientResponse" +import * as UrlParams from "effect/unstable/http/UrlParams" +import * as FetchHttpClient from "effect/unstable/http/FetchHttpClient" +import * as Headers from "effect/unstable/http/Headers" + +import { BridgeApi } from "./generated/BridgeApi.js" +import { BridgeConfigurationError, BridgeSchemaError, type BridgeClientError } from "./Errors.js" +import { resolveConfig, type BridgeConfig } from "./Config.js" +import { + apiKeyClientLayer, + defaultRedactedHeaderNames, + sanitizeClientErrors, + sanitizeHttpClient +} from "./internal/http.js" + +type ApiGroups = typeof BridgeApi extends HttpApi.HttpApi ? Groups : never + +type ClientResponseMode = HttpApiEndpoint.ClientResponseMode + +/** A response facade whose deferred body failures use the same safe SDK errors. */ +export type BridgeHttpClientResponse = Omit< + HttpClientResponse.HttpClientResponse, + "json" | "text" | "urlParamsBody" | "arrayBuffer" | "formData" | "stream" +> & { + readonly json: Effect.Effect + readonly text: Effect.Effect + readonly urlParamsBody: Effect.Effect + readonly arrayBuffer: Effect.Effect + readonly formData: Effect.Effect + readonly stream: Stream.Stream +} + +type ResponseType = [Mode] extends ["decoded-and-response"] + ? [Success, BridgeHttpClientResponse] + : [Mode] extends ["response-only"] ? BridgeHttpClientResponse + : Success + +type SuccessType = Success extends HttpApiSchema.WithHeaders< + infer Inner, + infer ResponseHeaders +> ? HttpApiSchema.withHeaders, ResponseHeaders["Type"]> + : Success["Type"] + +type SuccessDecodingServices = Success extends HttpApiSchema.WithHeaders< + infer Inner, + infer _ResponseHeaders +> ? SuccessDecodingServices + : Success["DecodingServices"] + +type EndpointServices = + | Endpoint["~Params"]["EncodingServices"] + | Endpoint["~Query"]["EncodingServices"] + | Endpoint["~Payload"]["EncodingServices"] + | Endpoint["~Headers"]["EncodingServices"] + | ([Mode] extends ["response-only"] ? never + : SuccessDecodingServices) + +type Method = < + Mode extends ClientResponseMode = "decoded-only" +>( + request: HttpApiEndpoint.ClientRequest< + Endpoint["~Params"], + Endpoint["~Query"], + Endpoint["~Payload"], + Endpoint["~Headers"], + Mode + > +) => Effect.Effect< + ResponseType, Mode>, + BridgeClientError, + EndpointServices +> + +type GroupClient = { + readonly [EndpointName in keyof Group["endpoints"]]: Group["endpoints"][EndpointName] extends HttpApiEndpoint.ConstraintRequest + ? Method + : never +} + +/** + * Typed groups and methods derived from the generated `BridgeApi`. Transport + * and schema failures use safe Bridge error types. Non-2xx Bridge response + * bodies are not decoded into public errors. + */ +export type BridgeClient = { + readonly [Group in ApiGroups as HttpApiGroup.Identifier]: GroupClient +} + +/** + * The authenticated Bridge client. The consumer owns the Effect runtime and + * supplies `HttpClient` through a Layer, or uses `layerFetch` for Fetch. + */ +export class Bridge extends Context.Service()("@misofm/bridge/Bridge") { + static make(config: BridgeConfig): Effect.Effect { + return makeBridgeClient(config) + } + + static layer(config: BridgeConfig): Layer.Layer { + return bridgeLayer(config) + } + + static layerFetch(config: BridgeConfig): Layer.Layer { + return bridgeFetchLayer(config) + } +} + +/** + * Build a typed client from the `HttpClient` service in the Effect context. + * This does not run a runtime and does not issue a request. + */ +export const makeBridgeClient = ( + config: BridgeConfig +): Effect.Effect => + Effect.gen(function*() { + const resolved = yield* Effect.fromResult(resolveConfig(config)) + const httpClient = yield* HttpClient.HttpClient + const redactedHeaderNames = defaultRedactedHeaderNames(yield* Headers.CurrentRedactedNames) + const apiClient = yield* HttpApiClient.makeWith(BridgeApi, { + httpClient: sanitizeHttpClient(httpClient), + baseUrl: resolved.baseUrl, + transformResponse: (effect) => + Effect.mapError(effect, (error) => { + if (Schema.isSchemaError(error)) { + return new BridgeSchemaError({ phase: "response" }) + } + return error + }) + }).pipe(Effect.provide(apiKeyClientLayer(resolved.apiKey))) + return sanitizeClientErrors(apiClient, { + timeoutMs: resolved.timeoutMs, + redactedHeaderNames + }) as unknown as BridgeClient + }) + +/** A layer that uses an injected `HttpClient.HttpClient` implementation. */ +export const bridgeLayer = ( + config: BridgeConfig +): Layer.Layer => + Layer.effect(Bridge, makeBridgeClient(config)) + +/** + * Fetch implementation with redirects disabled. A redirect is returned to the + * caller as a response, so the `Api-Key` header is never forwarded to a new URL. + */ +export const bridgeFetchLayer = (config: BridgeConfig): Layer.Layer => + bridgeLayer(config).pipe( + Layer.provideMerge( + Layer.mergeAll( + FetchHttpClient.layer, + Layer.succeed(FetchHttpClient.RequestInit, { redirect: "manual" }) + ) + ) + ) diff --git a/packages/bridge/src/Config.ts b/packages/bridge/src/Config.ts new file mode 100644 index 0000000..ab12e73 --- /dev/null +++ b/packages/bridge/src/Config.ts @@ -0,0 +1,73 @@ +import * as Result from "effect/Result" +import * as Schema from "effect/Schema" +import * as Redacted from "effect/Redacted" + +import { BridgeConfigurationError } from "./Errors.js" + +export type BridgeEnvironment = "production" | "sandbox" + +/** + * Configuration for one Bridge API client. Keys must be wrapped with + * `Redacted.make` (or read with `Config.Redacted`) before they enter the SDK. + */ +export interface BridgeConfig { + readonly apiKey: Redacted.Redacted + readonly environment?: BridgeEnvironment | undefined + /** An absolute API root, for example `https://bridge.example.test/v0`. */ + readonly baseUrl?: string | URL | undefined + /** Optional per-request timeout, in milliseconds. */ + readonly timeoutMs?: number | undefined +} + +export interface ResolvedBridgeConfig { + readonly apiKey: Redacted.Redacted + readonly baseUrl: string + readonly timeoutMs?: number | undefined +} + +export const productionBaseUrl = "https://api.bridge.xyz/v0" +export const sandboxBaseUrl = "https://api.sandbox.bridge.xyz/v0" + +const ConfigInput = Schema.Struct({ + apiKey: Schema.Redacted(Schema.NonEmptyString), + environment: Schema.optionalKey(Schema.Literals(["production", "sandbox"])), + baseUrl: Schema.optionalKey(Schema.Union([Schema.String, Schema.instanceOf(URL)])), + timeoutMs: Schema.optionalKey(Schema.Number.check(Schema.isFinite()).check(Schema.isGreaterThan(0))) +}) + +/** + * Validates and normalizes public configuration without including user-supplied + * key or URL values in failures. + */ +export const resolveConfig = (input: BridgeConfig): Result.Result => { + const decoded = Schema.decodeUnknownResult(ConfigInput)(input) + if (Result.isFailure(decoded)) { + return Result.fail(new BridgeConfigurationError({ field: "configuration" })) + } + + const config = decoded.success + const rawBaseUrl = config.baseUrl ?? (config.environment === "sandbox" ? sandboxBaseUrl : productionBaseUrl) + let baseUrl: URL + try { + baseUrl = new URL(rawBaseUrl) + } catch { + return Result.fail(new BridgeConfigurationError({ field: "baseUrl" })) + } + + if ( + (baseUrl.protocol !== "https:" && baseUrl.protocol !== "http:") || + baseUrl.username.length > 0 || + baseUrl.password.length > 0 || + baseUrl.search.length > 0 || + baseUrl.hash.length > 0 + ) { + return Result.fail(new BridgeConfigurationError({ field: "baseUrl" })) + } + + baseUrl.pathname = baseUrl.pathname.replace(/\/+$/, "") + return Result.succeed({ + apiKey: config.apiKey, + baseUrl: baseUrl.toString().replace(/\/$/, ""), + timeoutMs: config.timeoutMs + }) +} diff --git a/packages/bridge/src/Errors.ts b/packages/bridge/src/Errors.ts new file mode 100644 index 0000000..e34b08c --- /dev/null +++ b/packages/bridge/src/Errors.ts @@ -0,0 +1,30 @@ +import * as Schema from "effect/Schema" + +export class BridgeConfigurationError extends Schema.TaggedError()( + "BridgeConfigurationError", + { field: Schema.Literals(["configuration", "apiKey", "baseUrl", "timeoutMs"]) } +) {} + +export class BridgeHttpError extends Schema.TaggedError()("BridgeHttpError", { + status: Schema.Number, + method: Schema.String, + requestId: Schema.optionalKey(Schema.String) +}) {} + +export class BridgeTransportError extends Schema.TaggedError()("BridgeTransportError", { + kind: Schema.Literals(["TransportError", "InvalidUrlError", "EncodeError", "DecodeError", "EmptyBodyError", "Unknown"]), + method: Schema.optionalKey(Schema.String) +}) {} + +export class BridgeSchemaError extends Schema.TaggedError()("BridgeSchemaError", { + phase: Schema.Literals(["request", "response"]), + status: Schema.optionalKey(Schema.Number), + method: Schema.optionalKey(Schema.String), + requestId: Schema.optionalKey(Schema.String) +}) {} + +export class BridgeTimeoutError extends Schema.TaggedError()("BridgeTimeoutError", { + timeoutMs: Schema.Number +}) {} + +export type BridgeClientError = BridgeHttpError | BridgeTransportError | BridgeSchemaError | BridgeTimeoutError diff --git a/packages/bridge/src/Pagination.ts b/packages/bridge/src/Pagination.ts new file mode 100644 index 0000000..448a09b --- /dev/null +++ b/packages/bridge/src/Pagination.ts @@ -0,0 +1,322 @@ +import * as Effect from "effect/Effect" +import * as Option from "effect/Option" +import * as Schema from "effect/Schema" +import * as Stream from "effect/Stream" + +/** The two cursor directions supported by standard Bridge list endpoints. */ +export type BridgeCursorDirection = "starting_after" | "ending_before" + +/** Pagination fields accepted by a standard Bridge list endpoint. */ +export interface BridgeCursorQuery { + readonly limit?: number + readonly starting_after?: string + readonly ending_before?: string +} + +/** A response page from a standard Bridge list endpoint. */ +export interface BridgeCursorPage { + readonly data?: ReadonlyArray | undefined + readonly has_more?: boolean | undefined +} + +/** Pagination fields accepted by the stablecoin rewards history endpoint. */ +export interface BridgeRewardsCursorQuery { + readonly limit?: number + readonly cursor?: string +} + +/** A response page from the stablecoin rewards history endpoint. */ +export interface BridgeRewardsCursorPage { + readonly data?: ReadonlyArray | undefined + readonly pagination?: { + readonly has_more?: boolean | undefined + readonly next_cursor?: string | null | undefined + } | undefined +} + +/** Options for the standard `starting_after` / `ending_before` paginator. */ +export interface BridgeCursorOptions { + /** Overrides the query's `limit`; defaults to its value or 100. Larger values are capped at 100. */ + readonly limit?: number + /** Overrides the query direction. If omitted, a query cursor selects the direction; otherwise `starting_after` is used. */ + readonly direction?: BridgeCursorDirection + /** Overrides a cursor in the query for the selected direction. */ + readonly cursor?: string + /** Extracts the stable resource ID used by Bridge as the page cursor. */ + readonly getId: (item: Item) => string | undefined +} + +/** Options for the stablecoin rewards paginator. */ +export interface BridgeRewardsCursorOptions { + /** Overrides the query's `limit`; defaults to its value or 90. Larger values are capped at 90. */ + readonly limit?: number + /** Overrides the query's initial `cursor`. */ + readonly cursor?: string +} + +/** + * Invalid page sizes fail when the stream is consumed. Values above the + * endpoint maximum are capped; values below one or non-integers are rejected. + */ +export class BridgePaginationLimitError extends Schema.TaggedError()( + "BridgePaginationLimitError", + { + maximum: Schema.Number, + received: Schema.String + } +) {} + +/** Invalid cursor configuration or a cursor contract violation. */ +export class BridgePaginationCursorError extends Schema.TaggedError()( + "BridgePaginationCursorError", + { + contract: Schema.Literals(["standard", "rewards"]), + kind: Schema.Literals(["conflicting_directions", "missing_cursor", "missing_next_cursor", "cursor_cycle"]), + cursor: Schema.optionalKey(Schema.String) + } +) {} + +type StandardCursorRequest = Omit & { + readonly limit: number + readonly starting_after?: string + readonly ending_before?: string +} + +type RewardsCursorRequest = Omit & { + readonly limit: number + readonly cursor?: string +} + +interface CursorState { + readonly cursor: string | undefined + readonly seen: ReadonlySet + readonly failure: BridgePaginationCursorError | undefined +} + +const cursorState = (cursor: string | undefined): CursorState => ({ + cursor, + seen: cursor === undefined ? new Set() : new Set([cursor]), + failure: undefined +}) + +const failedCursorState = (state: CursorState, failure: BridgePaginationCursorError): CursorState => ({ + ...state, + failure +}) + +const nextCursorState = (state: CursorState, cursor: string): CursorState => { + const seen = new Set(state.seen) + seen.add(cursor) + return { cursor, seen, failure: undefined } +} + +type StandardCursorSelection = { + readonly direction: BridgeCursorDirection + readonly cursor: string | undefined +} + +const selectStandardCursor = ( + filters: BridgeCursorQuery, + options: Pick, "direction" | "cursor"> +): StandardCursorSelection | BridgePaginationCursorError => { + const hasStartingAfter = filters.starting_after !== undefined + const hasEndingBefore = filters.ending_before !== undefined + if (hasStartingAfter && hasEndingBefore) { + return new BridgePaginationCursorError({ contract: "standard", kind: "conflicting_directions" }) + } + + const filterDirection = hasStartingAfter ? "starting_after" : hasEndingBefore ? "ending_before" : undefined + if (options.direction !== undefined && filterDirection !== undefined && options.direction !== filterDirection) { + return new BridgePaginationCursorError({ + contract: "standard", + kind: "conflicting_directions" + }) + } + + const direction = options.direction ?? filterDirection ?? "starting_after" + const cursor = options.cursor ?? filters[direction] + return { direction, cursor } +} + +const normalizeLimit = ( + requested: number | undefined, + maximum: number +): number | BridgePaginationLimitError => { + if (requested === undefined) return maximum + if (!Number.isInteger(requested) || requested < 1) { + return new BridgePaginationLimitError({ maximum, received: String(requested) }) + } + return Math.min(requested, maximum) +} + +const standardFiltersWithoutPagination = ( + filters: Filters & BridgeCursorQuery +): Omit => { + const { limit, starting_after, ending_before, ...rest } = filters + void [limit, starting_after, ending_before] + return rest +} + +const rewardsFiltersWithoutPagination = ( + filters: Filters & BridgeRewardsCursorQuery +): Omit => { + const { limit, cursor, ...rest } = filters + void [limit, cursor] + return rest +} + +/** + * Lazily streams items from a standard Bridge list endpoint. The supplied + * filters are carried to every request, and only the selected cursor is sent. + * Each page's first or last item ID is used according to the direction. An + * empty page or `has_more: false` ends traversal. The stream can be stopped + * early by its consumer; later pages are not requested. Supply `getId` to + * extract each item's stable Bridge ID; this also supports generated response + * schemas where `id` is optional in the TypeScript type. + * Query `limit` and cursor values are used unless the matching option overrides + * them. Supplying both query cursor directions, or selecting a direction that + * conflicts with a query cursor, fails with `BridgePaginationCursorError`. + * + * Pending card authorizations are explicitly unpaginated by Bridge and must + * not be passed to this helper. + */ +export const paginateBridge = < + Filters extends object, + Item, + E, + R +>( + filters: Filters & BridgeCursorQuery, + fetchPage: (query: StandardCursorRequest>) => Effect.Effect, E, R>, + options: BridgeCursorOptions +): Stream.Stream => { + const selection = selectStandardCursor(filters, options) + if (selection instanceof BridgePaginationCursorError) return Stream.fail(selection) + + const limit = normalizeLimit(options.limit ?? filters.limit, 100) + if (limit instanceof BridgePaginationLimitError) return Stream.fail(limit) + + const { direction, cursor: initialCursor } = selection + const baseFilters = standardFiltersWithoutPagination(filters) + const makeQuery = (cursor: string | undefined): StandardCursorRequest => { + if (direction === "starting_after") { + return cursor === undefined + ? { ...baseFilters, limit } + : { ...baseFilters, limit, starting_after: cursor } + } + return cursor === undefined + ? { ...baseFilters, limit } + : { ...baseFilters, limit, ending_before: cursor } + } + + return Stream.paginate(cursorState(initialCursor), (state) => { + if (state.failure !== undefined) return Effect.fail(state.failure) + return Effect.map(fetchPage(makeQuery(state.cursor)), (page) => { + const items: ReadonlyArray = page.data ?? [] + if (items.length === 0 || page.has_more === false) { + return [items, Option.none()] as const + } + + const boundaryItem = direction === "starting_after" + ? items[items.length - 1] + : items[0] + const nextCursor = boundaryItem === undefined ? undefined : options.getId(boundaryItem) + if (nextCursor === undefined || nextCursor.length === 0) { + const failure = new BridgePaginationCursorError({ contract: "standard", kind: "missing_cursor" }) + return [items, Option.some(failedCursorState(state, failure))] as const + } + if (state.seen.has(nextCursor)) { + const failure = new BridgePaginationCursorError({ + contract: "standard", + kind: "cursor_cycle", + cursor: nextCursor + }) + return [items, Option.some(failedCursorState(state, failure))] as const + } + return [items, Option.some(nextCursorState(state, nextCursor))] as const + }) + }) +} + +/** Collects the standard Bridge item stream into an array. */ +export const paginateBridgeEffect = < + Filters extends object, + Item, + E, + R +>( + filters: Filters & BridgeCursorQuery, + fetchPage: (query: StandardCursorRequest>) => Effect.Effect, E, R>, + options: BridgeCursorOptions +): Effect.Effect, E | BridgePaginationLimitError | BridgePaginationCursorError, R> => + Stream.runCollect(paginateBridge(filters, fetchPage, options)) + +/** + * Lazily streams daily reward records using Bridge's separate `cursor` / + * `pagination.next_cursor` contract. The supplied query filters are carried to + * every request. Query `limit` and initial `cursor` values are used unless the + * matching option overrides them. Empty data or `has_more: false` ends + * traversal. A repeated cursor, or `has_more: true` without a next cursor, + * fails with `BridgePaginationCursorError`. The endpoint's page size is capped + * at 90. + */ +export const paginateBridgeRewards = < + Filters extends object, + Item, + E, + R +>( + filters: Filters & BridgeRewardsCursorQuery, + fetchPage: (query: RewardsCursorRequest>) => Effect.Effect, E, R>, + options: BridgeRewardsCursorOptions = {} +): Stream.Stream => { + const limit = normalizeLimit(options.limit ?? filters.limit, 90) + if (limit instanceof BridgePaginationLimitError) return Stream.fail(limit) + + const initialCursor = options.cursor ?? filters.cursor + const baseFilters = rewardsFiltersWithoutPagination(filters) + const makeQuery = (cursor: string | undefined): RewardsCursorRequest => + cursor === undefined + ? { ...baseFilters, limit } + : { ...baseFilters, limit, cursor } + + return Stream.paginate(cursorState(initialCursor), (state) => { + if (state.failure !== undefined) return Effect.fail(state.failure) + return Effect.map(fetchPage(makeQuery(state.cursor)), (page) => { + const items: ReadonlyArray = page.data ?? [] + const nextCursor = page.pagination?.next_cursor + if (items.length === 0 || page.pagination?.has_more === false) { + return [items, Option.none()] as const + } + if (nextCursor == null || nextCursor.length === 0) { + if (page.pagination?.has_more === true) { + const failure = new BridgePaginationCursorError({ contract: "rewards", kind: "missing_next_cursor" }) + return [items, Option.some(failedCursorState(state, failure))] as const + } + return [items, Option.none()] as const + } + if (state.seen.has(nextCursor)) { + const failure = new BridgePaginationCursorError({ + contract: "rewards", + kind: "cursor_cycle", + cursor: nextCursor + }) + return [items, Option.some(failedCursorState(state, failure))] as const + } + return [items, Option.some(nextCursorState(state, nextCursor))] as const + }) + }) +} + +/** Collects the Bridge rewards item stream into an array. */ +export const paginateBridgeRewardsEffect = < + Filters extends object, + Item, + E, + R +>( + filters: Filters & BridgeRewardsCursorQuery, + fetchPage: (query: RewardsCursorRequest>) => Effect.Effect, E, R>, + options: BridgeRewardsCursorOptions = {} +): Effect.Effect, E | BridgePaginationLimitError | BridgePaginationCursorError, R> => + Stream.runCollect(paginateBridgeRewards(filters, fetchPage, options)) diff --git a/packages/bridge/src/Webhooks.ts b/packages/bridge/src/Webhooks.ts new file mode 100644 index 0000000..88288e2 --- /dev/null +++ b/packages/bridge/src/Webhooks.ts @@ -0,0 +1,314 @@ +// Copyright (c) Miso Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +import { Clock, Data, Effect } from "effect"; + +/** Bridge's signature header name. */ +export const BRIDGE_WEBHOOK_SIGNATURE_HEADER = "X-Webhook-Signature"; + +/** Bridge recommends rejecting webhook deliveries older than ten minutes. */ +export const WEBHOOK_MAX_AGE_MILLISECONDS = 10 * 60 * 1_000; + +/** By default, a signature timestamp may not be ahead of the active Effect Clock. */ +export const WEBHOOK_MAX_FUTURE_SKEW_MILLISECONDS = 0; + +/** Event categories currently listed in Bridge's event structure guide. */ +export const BRIDGE_WEBHOOK_EVENT_CATEGORIES = [ + "customer", + "kyc_link", + "liquidation_address.drain", + "static_memo.activity", + "transfer", + "virtual_account.activity", + "bridge_wallet.activity", + "card_account", + "card_transaction", + "posted_card_account_transaction", + "card_withdrawal", + // Preserve the spelling in Bridge's event structure guide. + "external_acccount", + "rfi", +] as const; + +export type KnownWebhookEventCategory = (typeof BRIDGE_WEBHOOK_EVENT_CATEGORIES)[number]; + +/** + * A known category, or any future category Bridge may add. Callers should + * preserve and deliberately handle unknown strings instead of rejecting them. + */ +export type WebhookEventCategory = KnownWebhookEventCategory | (string & {}); + +/** + * The stable envelope documented by Bridge. Event type is deliberately a + * string: Bridge's examples use both qualified and unqualified values. + */ +export interface WebhookEventEnvelope { + readonly api_version: string; + readonly event_id: string; + readonly event_category: WebhookEventCategory; + readonly event_type: string; + readonly event_object_id?: string; + readonly event_object_status?: string; + readonly event_object: EventObject; + readonly event_object_changes?: unknown; + readonly event_created_at: string; +} + +export function isKnownWebhookEventCategory(value: string): value is KnownWebhookEventCategory { + return (BRIDGE_WEBHOOK_EVENT_CATEGORIES as readonly string[]).includes(value); +} + +export type WebhookErrorCode = + | "invalid_signature_header" + | "invalid_timestamp" + | "timestamp_expired" + | "timestamp_in_future" + | "invalid_base64" + | "invalid_public_key" + | "invalid_signature" + | "web_crypto_unavailable" + | "crypto_operation_failed" + | "invalid_json"; + +/** Safe, structured webhook validation failure. It never includes payloads or keys. */ +export class WebhookError extends Data.TaggedError("WebhookError")<{ + readonly code: WebhookErrorCode; +}> { + override get message(): string { + switch (this.code) { + case "invalid_signature_header": + return "Bridge webhook signature header is malformed."; + case "invalid_timestamp": + return "Bridge webhook timestamp is invalid."; + case "timestamp_expired": + return "Bridge webhook timestamp is outside the allowed age."; + case "timestamp_in_future": + return "Bridge webhook timestamp is too far in the future."; + case "invalid_base64": + return "Bridge webhook signature is not canonical base64."; + case "invalid_public_key": + return "Bridge webhook public key is invalid."; + case "invalid_signature": + return "Bridge webhook signature does not match the raw body."; + case "web_crypto_unavailable": + return "This runtime does not provide Web Crypto SubtleCrypto."; + case "crypto_operation_failed": + return "Bridge webhook cryptographic verification failed."; + case "invalid_json": + return "Verified Bridge webhook body is not valid UTF-8 JSON."; + } + } +} + +export type WebhookPublicKey = string | CryptoKey; + +export interface VerifyWebhookSignatureOptions { + /** The exact request body bytes before any text or JSON decoding. */ + readonly rawBody: Uint8Array; + readonly signatureHeader: string; + /** PEM SubjectPublicKeyInfo, or a Web Crypto RSA-SHA256 public CryptoKey. */ + readonly publicKey: WebhookPublicKey; + /** Defaults to Bridge's recommended ten minutes. */ + readonly maxAgeMilliseconds?: number; + /** Defaults to zero; set explicitly only for a known clock-skew policy. */ + readonly maxFutureSkewMilliseconds?: number; +} + +export interface VerifyAndDecodeWebhookEventOptions extends + VerifyWebhookSignatureOptions +{ + /** + * A schema decoder such as `Schema.decodeUnknownEffect(BridgeWebhookEvent)`. + * It runs only after the signature over `rawBody` has passed verification. + */ + readonly decode: (input: unknown) => Effect.Effect; +} + +interface ParsedSignature { + readonly timestampText: string; + readonly timestampMilliseconds: number; + readonly signature: Uint8Array; +} + +const BASE64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +const BASE64_PATTERN = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/; +const SIGNATURE_HEADER_PATTERN = /^t=([^,]+),v0=([^,]*)$/; +const PEM_PUBLIC_KEY_PATTERN = /^-----BEGIN PUBLIC KEY-----[\t\r\n ]*([A-Za-z0-9+/=\t\r\n ]+)[\t\r\n ]*-----END PUBLIC KEY-----$/; + +function encodeBase64(bytes: Uint8Array): string { + let output = ""; + for (let index = 0; index < bytes.length; index += 3) { + const first = bytes[index]!; + const second = bytes[index + 1]; + const third = bytes[index + 2]; + output += BASE64_ALPHABET[first >>> 2]; + output += BASE64_ALPHABET[((first & 0b00000011) << 4) | ((second ?? 0) >>> 4)]; + output += second === undefined + ? "==" + : third === undefined + ? `${BASE64_ALPHABET[(second & 0b00001111) << 2]}=` + : `${BASE64_ALPHABET[((second & 0b00001111) << 2) | (third >>> 6)]}${BASE64_ALPHABET[third & 0b00111111]}`; + } + return output; +} + +function decodeBase64Strict(value: string): Uint8Array | undefined { + if (value.length === 0 || value.length % 4 !== 0 || !BASE64_PATTERN.test(value)) return undefined; + + const padding = value.endsWith("==") ? 2 : value.endsWith("=") ? 1 : 0; + const output = new Uint8Array((value.length / 4) * 3 - padding); + let outputIndex = 0; + + for (let index = 0; index < value.length; index += 4) { + const first = BASE64_ALPHABET.indexOf(value[index]!); + const second = BASE64_ALPHABET.indexOf(value[index + 1]!); + const thirdChar = value[index + 2]!; + const fourthChar = value[index + 3]!; + const third = thirdChar === "=" ? 0 : BASE64_ALPHABET.indexOf(thirdChar); + const fourth = fourthChar === "=" ? 0 : BASE64_ALPHABET.indexOf(fourthChar); + + output[outputIndex++] = (first << 2) | (second >>> 4); + if (thirdChar !== "=") output[outputIndex++] = ((second & 0b00001111) << 4) | (third >>> 2); + if (fourthChar !== "=") output[outputIndex++] = ((third & 0b00000011) << 6) | fourth; + } + + // Re-encoding also rejects nonzero unused padding bits. + return encodeBase64(output) === value ? output : undefined; +} + +function parseSignatureHeader(header: string): ParsedSignature | WebhookError { + const match = SIGNATURE_HEADER_PATTERN.exec(header); + if (!match) return new WebhookError({ code: "invalid_signature_header" }); + + const timestampText = match[1]!; + if (!/^(?:0|[1-9][0-9]*)$/.test(timestampText)) { + return new WebhookError({ code: "invalid_timestamp" }); + } + const timestampMilliseconds = Number(timestampText); + if (!Number.isSafeInteger(timestampMilliseconds)) { + return new WebhookError({ code: "invalid_timestamp" }); + } + + const signature = decodeBase64Strict(match[2]!); + if (!signature) return new WebhookError({ code: "invalid_base64" }); + + return { timestampText, timestampMilliseconds, signature }; +} + +function pemToSpki(publicKey: string): Uint8Array | undefined { + const match = PEM_PUBLIC_KEY_PATTERN.exec(publicKey.trim()); + if (!match) return undefined; + return decodeBase64Strict(match[1]!.replace(/[\t\r\n ]/g, "")); +} + +function isWebhookError(value: ParsedSignature | WebhookError): value is WebhookError { + return value instanceof WebhookError; +} + +function validWindow(value: number): boolean { + return Number.isSafeInteger(value) && value >= 0; +} + +function isCompatibleCryptoKey(key: CryptoKey): boolean { + const algorithm = key.algorithm as CryptoKey["algorithm"] & { + readonly hash?: { readonly name?: unknown }; + }; + return key.type === "public" && + key.algorithm.name === "RSASSA-PKCS1-v1_5" && + algorithm.hash?.name === "SHA-256" && + key.usages.includes("verify"); +} + +/** + * Verify the Bridge webhook header against the byte-exact request body. + * Bridge hashes `timestamp + "." + rawBody`, then uses RSA PKCS#1 v1.5 with + * SHA-256 to verify that digest. Web Crypto hashes its verification input, so + * passing the first digest intentionally reproduces Bridge's published + * double-hash behavior. + */ +export const verifyWebhookSignature = Effect.fn("Bridge.Webhooks.verifySignature")( + function* ( + options: VerifyWebhookSignatureOptions, + ): Effect.fn.Return { + const rawBody = new Uint8Array(options.rawBody); + const parsed = parseSignatureHeader(options.signatureHeader); + if (isWebhookError(parsed)) return yield* parsed; + + const maxAgeMilliseconds = options.maxAgeMilliseconds ?? WEBHOOK_MAX_AGE_MILLISECONDS; + const maxFutureSkewMilliseconds = options.maxFutureSkewMilliseconds ?? WEBHOOK_MAX_FUTURE_SKEW_MILLISECONDS; + if (!validWindow(maxAgeMilliseconds) || !validWindow(maxFutureSkewMilliseconds)) { + return yield* new WebhookError({ code: "invalid_timestamp" }); + } + + const now = yield* Clock.currentTimeMillis; + if (parsed.timestampMilliseconds < now - maxAgeMilliseconds) { + return yield* new WebhookError({ code: "timestamp_expired" }); + } + if (parsed.timestampMilliseconds > now + maxFutureSkewMilliseconds) { + return yield* new WebhookError({ code: "timestamp_in_future" }); + } + + const subtle = globalThis.crypto?.subtle; + if (!subtle) return yield* new WebhookError({ code: "web_crypto_unavailable" }); + + let publicKey: CryptoKey; + if (typeof options.publicKey === "string") { + const spki = pemToSpki(options.publicKey); + if (!spki) return yield* new WebhookError({ code: "invalid_public_key" }); + const spkiBuffer = new ArrayBuffer(spki.length); + new Uint8Array(spkiBuffer).set(spki); + publicKey = yield* Effect.tryPromise({ + try: () => subtle.importKey( + "spki", + spkiBuffer, + { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" }, + false, + ["verify"], + ), + catch: () => new WebhookError({ code: "invalid_public_key" }), + }); + } else { + if (!isCompatibleCryptoKey(options.publicKey)) { + return yield* new WebhookError({ code: "invalid_public_key" }); + } + publicKey = options.publicKey; + } + + const timestampBytes = new TextEncoder().encode(parsed.timestampText); + const signedBytes = new Uint8Array(timestampBytes.length + 1 + rawBody.length); + signedBytes.set(timestampBytes, 0); + signedBytes[timestampBytes.length] = 0x2e; + signedBytes.set(rawBody, timestampBytes.length + 1); + + const digest = yield* Effect.tryPromise({ + try: () => subtle.digest("SHA-256", signedBytes), + catch: () => new WebhookError({ code: "crypto_operation_failed" }), + }); + const signatureBuffer = new ArrayBuffer(parsed.signature.length); + new Uint8Array(signatureBuffer).set(parsed.signature); + const verified = yield* Effect.tryPromise({ + try: () => subtle.verify("RSASSA-PKCS1-v1_5", publicKey, signatureBuffer, digest), + catch: () => new WebhookError({ code: "crypto_operation_failed" }), + }); + if (!verified) return yield* new WebhookError({ code: "invalid_signature" }); + }, +); + +/** + * Verify first, then decode the authenticated JSON through a caller-supplied + * Effect Schema decoder. The raw-body snapshot is used for both verification + * and JSON parsing, so later caller mutations cannot change the decoded event. + */ +export function verifyAndDecodeWebhookEvent( + options: VerifyAndDecodeWebhookEventOptions, +): Effect.Effect { + const rawBody = new Uint8Array(options.rawBody); + return Effect.gen(function* () { + yield* verifyWebhookSignature({ ...options, rawBody }); + const input = yield* Effect.try({ + try: () => JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(rawBody)) as unknown, + catch: () => new WebhookError({ code: "invalid_json" }), + }); + return yield* options.decode(input); + }); +} diff --git a/packages/bridge/src/generated/BridgeApi.ts b/packages/bridge/src/generated/BridgeApi.ts new file mode 100644 index 0000000..57e1b49 --- /dev/null +++ b/packages/bridge/src/generated/BridgeApi.ts @@ -0,0 +1,2396 @@ +import * as Schema from "effect/Schema" +import { HttpApi, HttpApiEndpoint, HttpApiGroup, HttpApiMiddleware, HttpApiSchema, HttpApiSecurity, OpenApi } from "effect/unstable/httpapi" +// non-recursive definitions +export type BridgeWalletsList = { readonly "count": number, readonly "data": ReadonlyArray<{ readonly "chain": "base" | "ethereum" | "linea" | "solana" | "tempo" | "tron" | "xdc", readonly "id"?: string, readonly "address"?: string, readonly "initiation_required"?: boolean, readonly "created_at"?: string, readonly "updated_at"?: string } & { readonly [x: string]: Schema.Json }> } +export const BridgeWalletsList = Schema.Struct({ "count": Schema.Number.annotate({ "description": "total number of items in data" }).check(Schema.isInt().annotate({ "expected": "an integer" })), "data": Schema.Array(Schema.StructWithRest(Schema.Struct({ "chain": Schema.Union([Schema.Literal("base").annotate({ "description": "The chain of the Bridge Wallet", "readOnly": true }), Schema.Literal("ethereum").annotate({ "description": "The chain of the Bridge Wallet", "readOnly": true }), Schema.Literal("linea").annotate({ "description": "The chain of the Bridge Wallet", "readOnly": true }), Schema.Literal("solana").annotate({ "description": "The chain of the Bridge Wallet", "readOnly": true }), Schema.Literal("tempo").annotate({ "description": "The chain of the Bridge Wallet", "readOnly": true }), Schema.Literal("tron").annotate({ "description": "The chain of the Bridge Wallet", "readOnly": true }), Schema.Literal("xdc").annotate({ "description": "The chain of the Bridge Wallet", "readOnly": true })]), "id": Schema.optionalKey(Schema.String.annotate({ "description": "A UUID that uniquely identifies a resource", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "address": Schema.optionalKey(Schema.String.annotate({ "description": "The blockchain address of the Bridge Wallet", "readOnly": true })), "initiation_required": Schema.optionalKey(Schema.Boolean.annotate({ "description": "When present, transfers sourced from this wallet must include an `initiation` object on the create request. Omitted for wallets that do not require initiation data.", "readOnly": true })), "created_at": Schema.optionalKey(Schema.String.annotate({ "description": "Time of creation of the Bridge Wallet", "readOnly": true, "format": "date-time" })), "updated_at": Schema.optionalKey(Schema.String.annotate({ "description": "Time of most recent update of the Bridge Wallet", "readOnly": true, "format": "date-time" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))])).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" })) }).annotate({ "identifier": "BridgeWalletsList" }) +export type Error = { readonly "code": string, readonly "message": string, readonly "source"?: { readonly "location": "path" | "query" | "body" | "header", readonly "key": string } & { readonly [x: string]: Schema.Json } } & { readonly [x: string]: Schema.Json } +export const Error = Schema.StructWithRest(Schema.Struct({ "code": Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" })), "message": Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(512).annotate({ "expected": "a value with a length of at most 512" })), "source": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "location": Schema.Literals(["path", "query", "body", "header"]), "key": Schema.String.annotate({ "description": "Comma separated names of the properties or parameters causing the error" }) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "title": "ErrorSource" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "identifier": "Error" }) +export type BridgeWalletTotalBalance = { readonly "balance": string, readonly "currency": "usdb" | "usdc" | "usdt" | "usdl_linea" | "usd" | "pyusd", readonly "chain": "base" | "ethereum" | "linea" | "solana" | "tempo" | "tron" | "xdc", readonly "contract_address"?: string } +export const BridgeWalletTotalBalance = Schema.Struct({ "balance": Schema.String.annotate({ "description": "The total balance of wallets in the given currency ex. \"10.95\"", "readOnly": true }), "currency": Schema.Literals(["usdb", "usdc", "usdt", "usdl_linea", "usd", "pyusd"]).annotate({ "description": "The currency of the total balance", "readOnly": true }), "chain": Schema.Literals(["base", "ethereum", "linea", "solana", "tempo", "tron", "xdc"]).annotate({ "description": "The chain of the total balance", "readOnly": true }), "contract_address": Schema.optionalKey(Schema.String.annotate({ "description": "The contract address of the currency, or null if it is a native currency", "readOnly": true })) }).annotate({ "description": "The total balance across all Bridge wallets for a given currency", "identifier": "BridgeWalletTotalBalance" }) +export type Id = string +export const Id = Schema.String.annotate({ "description": "A UUID that uniquely identifies a resource" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*", "identifier": "Id" })) +export type BridgeWalletWithBalances = { readonly "chain": "base" | "ethereum" | "linea" | "solana" | "tempo" | "tron" | "xdc", readonly "id"?: string, readonly "address"?: string, readonly "initiation_required"?: boolean, readonly "created_at"?: string, readonly "updated_at"?: string, readonly "balances"?: ReadonlyArray<{ readonly "balance": string, readonly "currency": "usdb" | "usdc" | "usdt" | "usdl_linea" | "usd" | "pyusd", readonly "chain": "base" | "ethereum" | "linea" | "solana" | "tempo" | "tron" | "xdc", readonly "contract_address"?: string }> } & { readonly [x: string]: Schema.Json } +export const BridgeWalletWithBalances = Schema.StructWithRest(Schema.Struct({ "chain": Schema.Union([Schema.Literal("base").annotate({ "description": "The chain of the Bridge Wallet", "readOnly": true }), Schema.Literal("ethereum").annotate({ "description": "The chain of the Bridge Wallet", "readOnly": true }), Schema.Literal("linea").annotate({ "description": "The chain of the Bridge Wallet", "readOnly": true }), Schema.Literal("solana").annotate({ "description": "The chain of the Bridge Wallet", "readOnly": true }), Schema.Literal("tempo").annotate({ "description": "The chain of the Bridge Wallet", "readOnly": true }), Schema.Literal("tron").annotate({ "description": "The chain of the Bridge Wallet", "readOnly": true }), Schema.Literal("xdc").annotate({ "description": "The chain of the Bridge Wallet", "readOnly": true })]), "id": Schema.optionalKey(Schema.String.annotate({ "description": "A UUID that uniquely identifies a resource", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "address": Schema.optionalKey(Schema.String.annotate({ "description": "The blockchain address of the Bridge Wallet", "readOnly": true })), "initiation_required": Schema.optionalKey(Schema.Boolean.annotate({ "description": "When present, transfers sourced from this wallet must include an `initiation` object on the create request. Omitted for wallets that do not require initiation data.", "readOnly": true })), "created_at": Schema.optionalKey(Schema.String.annotate({ "description": "Time of creation of the Bridge Wallet", "readOnly": true, "format": "date-time" })), "updated_at": Schema.optionalKey(Schema.String.annotate({ "description": "Time of most recent update of the Bridge Wallet", "readOnly": true, "format": "date-time" })), "balances": Schema.optionalKey(Schema.Array(Schema.Struct({ "balance": Schema.String.annotate({ "description": "The balance in the given currency. ex. \"10.95\"", "readOnly": true }), "currency": Schema.Literals(["usdb", "usdc", "usdt", "usdl_linea", "usd", "pyusd"]).annotate({ "description": "The currency of the balance", "readOnly": true }), "chain": Schema.Literals(["base", "ethereum", "linea", "solana", "tempo", "tron", "xdc"]).annotate({ "description": "The chain of the balance", "readOnly": true }), "contract_address": Schema.optionalKey(Schema.String.annotate({ "description": "The contract address of the currency, or null if it is a native currency", "readOnly": true })) }).annotate({ "description": "The balance of a Bridge Wallet for a given currency" })).annotate({ "readOnly": true })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "identifier": "BridgeWalletWithBalances" }) +export type BridgeWalletEventResponse = { readonly "id": string, readonly "bridge_wallet_id": string, readonly "amount": string, readonly "available_balance": string, readonly "currency": "usdb" | "usdc" | "usdt" | "usdl_linea" | "usd" | "pyusd", readonly "type": "deposit" | "direct_deposit" | "withdrawal" | "return" | "undeliverable" | "card_spend" | "card_refund", readonly "source": { readonly "currency"?: "usdb" | "usdc" | "usdt" | "usdl_linea" | "usd" | "pyusd", readonly "payment_rail"?: string, readonly "from_address"?: string | null }, readonly "destination": { readonly "currency"?: "usdb" | "usdc" | "usdt" | "usdl_linea" | "usd" | "pyusd", readonly "payment_rail"?: string, readonly "tx_hash"?: string | null, readonly "from_address"?: string | null }, readonly "payment_route"?: { readonly "type"?: "transfer" | "liquidation_address" | "virtual_account" | "card_spend", readonly "customer_id"?: string, readonly "transfer_id"?: string | null, readonly "card_crypto_transaction_id"?: string | null, readonly "issuing_authorization_id"?: string | null, readonly "issuing_transaction_id"?: string | null } & { readonly [x: string]: Schema.Json } | null, readonly "created_at": string } +export const BridgeWalletEventResponse = Schema.Struct({ "id": Schema.String.annotate({ "description": "A UUID that uniquely identifies a resource" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" })), "bridge_wallet_id": Schema.String.annotate({ "description": "A UUID that uniquely identifies a resource" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" })), "amount": Schema.String.annotate({ "description": "Amount of the transaction, represented as a decimal string. Examples include \"100.250000\", \"0.100000\", \"1.234567\" etc." }), "available_balance": Schema.String.annotate({ "description": "Available balance of the wallet after this event, represented as a decimal string." }), "currency": Schema.Literals(["usdb", "usdc", "usdt", "usdl_linea", "usd", "pyusd"]), "type": Schema.Literals(["deposit", "direct_deposit", "withdrawal", "return", "undeliverable", "card_spend", "card_refund"]).annotate({ "description": "The type of wallet event." }), "source": Schema.Struct({ "currency": Schema.optionalKey(Schema.Literals(["usdb", "usdc", "usdt", "usdl_linea", "usd", "pyusd"])), "payment_rail": Schema.optionalKey(Schema.String), "from_address": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) }).annotate({ "description": "The source of the transfer, which could be an external bank account, a bridge account, or a crypto wallet address." }), "destination": Schema.Struct({ "currency": Schema.optionalKey(Schema.Literals(["usdb", "usdc", "usdt", "usdl_linea", "usd", "pyusd"])), "payment_rail": Schema.optionalKey(Schema.String), "tx_hash": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), "from_address": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])) }).annotate({ "description": "The destination of the transfer, which could be an external bank account, a bridge account, or a crypto wallet address." }), "payment_route": Schema.optionalKey(Schema.Union([Schema.StructWithRest(Schema.Struct({ "type": Schema.optionalKey(Schema.Literals(["transfer", "liquidation_address", "virtual_account", "card_spend"]).annotate({ "description": "The type of payment route." })), "customer_id": Schema.optionalKey(Schema.String.annotate({ "description": "A UUID that uniquely identifies a resource" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "transfer_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null])), "card_crypto_transaction_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "The ID of the card crypto transaction that initiated this event. Present on card_spend and card_refund events when the event is linked to a specific on-chain card transaction." })), "issuing_authorization_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "The Stripe Issuing authorization ID associated with this card event." })), "issuing_transaction_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "The Stripe Issuing transaction ID associated with this card event." })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]), Schema.Null]).annotate({ "description": "Details about the Bridge payment route that initiated this event, such as a transfer, liquidation address drain, virtual account deposit, or card spend. Not present on direct deposits." })), "created_at": Schema.String.annotate({ "format": "date-time" }) }).annotate({ "description": "Shared fields present on every bridge wallet history event.", "identifier": "BridgeWalletEventResponse" }) +export type Customer = { readonly "id"?: string, readonly "first_name"?: string, readonly "middle_name"?: string | null, readonly "last_name"?: string | null, readonly "email"?: string, readonly "status"?: "active" | "awaiting_questionnaire" | "awaiting_ubo" | "deposits_restricted" | "incomplete" | "not_started" | "offboarded" | "paused" | "rejected" | "under_review", readonly "capabilities"?: { readonly "payin_crypto"?: "pending" | "active" | "inactive" | "rejected", readonly "payout_crypto"?: "pending" | "active" | "inactive" | "rejected", readonly "payin_fiat"?: "pending" | "active" | "inactive" | "rejected", readonly "payout_fiat"?: "pending" | "active" | "inactive" | "rejected" }, readonly "future_requirements_due"?: ReadonlyArray<"id_verification">, readonly "requirements_due"?: ReadonlyArray<"external_account" | "id_verification">, readonly "created_at"?: string, readonly "updated_at"?: string, readonly "rejection_reasons"?: ReadonlyArray<{ readonly "developer_reason"?: string, readonly "reason"?: string, readonly "created_at"?: string | null } & { readonly [x: string]: Schema.Json }>, readonly "has_accepted_terms_of_service"?: boolean, readonly "client_reference_id"?: string, readonly "endorsements"?: ReadonlyArray<{ readonly "name": "base" | "cards" | "cop" | "faster_payments" | "pix" | "pix_onramp" | "pix_offramp" | "sepa" | "spei", readonly "status": "incomplete" | "approved" | "revoked", readonly "additional_requirements"?: ReadonlyArray<"kyc_approval" | "tos_acceptance" | "kyc_with_proof_of_address" | "tos_v2_acceptance">, readonly "requirements"?: { readonly "complete": ReadonlyArray }>, readonly "pending": ReadonlyArray, readonly "missing": { readonly [x: string]: Schema.Json } | null, readonly "issues": ReadonlyArray }, readonly "future_requirements"?: ReadonlyArray<{ readonly "effective_date": string, readonly "verification_stage": "automatic_review" | "manual_review" | "post_review" | "complete" | "not_applicable", readonly "pending": ReadonlyArray, readonly "missing": { readonly [x: string]: Schema.Json } | null, readonly "issues": ReadonlyArray }> } & { readonly [x: string]: Schema.Json }> } & { readonly [x: string]: Schema.Json } +export const Customer = Schema.StructWithRest(Schema.Struct({ "id": Schema.optionalKey(Schema.String.annotate({ "description": "A UUID that uniquely identifies a resource", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "first_name": Schema.optionalKey(Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" }))), "middle_name": Schema.optionalKey(Schema.Union([Schema.String.check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" })), Schema.Null])), "last_name": Schema.optionalKey(Schema.Union([Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" })), Schema.Null])), "email": Schema.optionalKey(Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" }))), "status": Schema.optionalKey(Schema.Literals(["active", "awaiting_questionnaire", "awaiting_ubo", "deposits_restricted", "incomplete", "not_started", "offboarded", "paused", "rejected", "under_review"]).annotate({ "description": "`offboarded`: represents a customer's account that was internally reviewed and closed due to suspicious activity.\n`paused`: represents a customer's account that is currently under review because of activity on the platform.\n`deposits_restricted`: represents a customer's account that is currently restricted from making new deposits because of activity on the platform.\n" })), "capabilities": Schema.optionalKey(Schema.Struct({ "payin_crypto": Schema.optionalKey(Schema.Literals(["pending", "active", "inactive", "rejected"]).annotate({ "description": "State of the customer capability" })), "payout_crypto": Schema.optionalKey(Schema.Literals(["pending", "active", "inactive", "rejected"]).annotate({ "description": "State of the customer capability" })), "payin_fiat": Schema.optionalKey(Schema.Literals(["pending", "active", "inactive", "rejected"]).annotate({ "description": "State of the customer capability" })), "payout_fiat": Schema.optionalKey(Schema.Literals(["pending", "active", "inactive", "rejected"]).annotate({ "description": "State of the customer capability" })) })), "future_requirements_due": Schema.optionalKey(Schema.Array(Schema.Literal("id_verification")).annotate({ "description": "This field is deprecated. See endorsements.missing instead.", "readOnly": true }).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" }))), "requirements_due": Schema.optionalKey(Schema.Array(Schema.Literals(["external_account", "id_verification"])).annotate({ "description": "KYC requirements still needed to be completed. Please consult our KYC guide on how to resolve each requirement.", "readOnly": true }).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" }))), "created_at": Schema.optionalKey(Schema.String.annotate({ "description": "Time of creation of the customer", "readOnly": true, "format": "date-time" })), "updated_at": Schema.optionalKey(Schema.String.annotate({ "description": "Time of last update of the customer", "readOnly": true, "format": "date-time" })), "rejection_reasons": Schema.optionalKey(Schema.Array(Schema.StructWithRest(Schema.Struct({ "developer_reason": Schema.optionalKey(Schema.String.annotate({ "description": "Developer information for why a customer was rejected. Not to be shared with the customer." })), "reason": Schema.optionalKey(Schema.String.annotate({ "description": "Reason for why a customer was rejected. To be shared with the customer." })), "created_at": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Time of creation of the rejection reason" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Reason why the kyc_status was rejected" })).annotate({ "description": "Reasons why a customer KYC was rejected", "readOnly": true }).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" }))), "has_accepted_terms_of_service": Schema.optionalKey(Schema.Boolean.annotate({ "description": "Whether the customer has accepted the terms of service.", "readOnly": true })), "client_reference_id": Schema.optionalKey(Schema.String.annotate({ "description": "Caller-provided identifier used to correlate this customer with your internal records. Returned in API and webhook responses." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" }))), "endorsements": Schema.optionalKey(Schema.Array(Schema.StructWithRest(Schema.Struct({ "name": Schema.Literals(["base", "cards", "cop", "faster_payments", "pix", "pix_onramp", "pix_offramp", "sepa", "spei"]).annotate({ "description": "The endorsement type." }), "status": Schema.Literals(["incomplete", "approved", "revoked"]), "additional_requirements": Schema.optionalKey(Schema.Array(Schema.Literals(["kyc_approval", "tos_acceptance", "kyc_with_proof_of_address", "tos_v2_acceptance"])).annotate({ "description": "This field is deprecated. See endorsements.missing instead." }).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" }))), "requirements": Schema.optionalKey(Schema.Struct({ "complete": Schema.Array(Schema.Union([Schema.String, Schema.Struct({ "associated_person": Schema.String, "items": Schema.Array(Schema.String) })], { mode: "oneOf" })).annotate({ "description": "an array of requirements that have already been completed for this endorsement." }).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" })), "pending": Schema.Array(Schema.String).annotate({ "description": "an array of requirements that are pending review for this endorsement." }).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" })), "missing": Schema.Union([Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" })), Schema.Null]).annotate({ "description": "an object that will specify an indepth breakdown of what items are missing for this endorsement." }), "issues": Schema.Array(Schema.Union([Schema.String, Schema.Record(Schema.String, Schema.String)], { mode: "oneOf" })).annotate({ "description": "An array of issues preventing this endorsement from being approved. Values in this array can be either a string such as `endorsement_not_available_in_customers_region` or an object that correlates the issue to a particular field such as `{ id_front_photo: \"id_expired\" }`\n" }).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" })) }).annotate({ "description": "This object aims to replace the `additional_requirements` attribute as it gives a more comprehensive view into what items are already `complete` or `pending` and which are `missing` or have `issues`.\n" })), "future_requirements": Schema.optionalKey(Schema.Array(Schema.Struct({ "effective_date": Schema.String.annotate({ "format": "date" }), "verification_stage": Schema.Literals(["automatic_review", "manual_review", "post_review", "complete", "not_applicable"]).annotate({ "description": "The verification stage this future requirement is currently at." }), "pending": Schema.Array(Schema.String), "missing": Schema.Union([Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" })), Schema.Null]), "issues": Schema.Array(Schema.Union([Schema.String, Schema.Record(Schema.String, Schema.String)], { mode: "oneOf" })) })).annotate({ "description": "An array of upcoming requirements that will become active on their effective_date.\nEach entry has the same structure as the current requirements object, plus an\neffective_date indicating when the requirement takes effect.\n" }).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" }))) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))])).annotate({ "description": "A summary of whether the customer has received approvals to complete onboarding or use certain products/services offered by Bridge.", "readOnly": true }).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" }))) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "identifier": "Customer" }) +export type CreateIndividualCustomerPayload = { readonly "type": "individual", readonly "first_name"?: string, readonly "middle_name"?: string, readonly "last_name"?: string, readonly "transliterated_first_name"?: string, readonly "transliterated_middle_name"?: string, readonly "transliterated_last_name"?: string, readonly "email"?: string, readonly "phone"?: string, readonly "residential_address"?: { readonly "street_line_1": string, readonly "street_line_2"?: string, readonly "city": string, readonly "subdivision"?: string, readonly "postal_code"?: string, readonly "country": string } & { readonly [x: string]: Schema.Json }, readonly "transliterated_residential_address"?: { readonly "street_line_1": string, readonly "street_line_2"?: string, readonly "city": string, readonly "subdivision"?: string, readonly "postal_code"?: string, readonly "country": string } & { readonly [x: string]: Schema.Json }, readonly "birth_date"?: string, readonly "signed_agreement_id"?: string, readonly "endorsements"?: ReadonlyArray<"base" | "cards" | "cop" | "faster_payments" | "pix" | "pix_onramp" | "pix_offramp" | "sepa" | "spei">, readonly "account_purpose"?: "charitable_donations" | "ecommerce_retail_payments" | "investment_purposes" | "operating_a_company" | "other" | "payments_to_friends_or_family_abroad" | "personal_or_living_expenses" | "protect_wealth" | "purchase_goods_and_services" | "receive_payment_for_freelancing" | "receive_salary", readonly "account_purpose_other"?: string, readonly "employment_status"?: "employed" | "homemaker" | "retired" | "self_employed" | "student" | "unemployed", readonly "expected_monthly_payments_usd"?: "0_4999" | "5000_9999" | "10000_49999" | "50000_plus", readonly "acting_as_intermediary"?: boolean, readonly "most_recent_occupation"?: string, readonly "source_of_funds"?: "company_funds" | "ecommerce_reseller" | "gambling_proceeds" | "gifts" | "government_benefits" | "inheritance" | "investments_loans" | "pension_retirement" | "salary" | "sale_of_assets_real_estate" | "savings" | "someone_elses_funds", readonly "nationality"?: string, readonly "nationalities"?: ReadonlyArray, readonly "place_of_birth"?: { readonly "country"?: string, readonly "city"?: string }, readonly "verified_database_at"?: string, readonly "verified_govid_at"?: string, readonly "verified_selfie_at"?: string, readonly "liveness_check_selfies"?: ReadonlyArray<{ readonly "image": string }>, readonly "identifying_information"?: ReadonlyArray<{ readonly "type": "drivers_license" | "matriculate_id" | "military_id" | "national_id" | "passport" | "permanent_residency_id" | "state_or_provincial_id" | "visa" | "abn" | "acn" | "ahv" | "ak" | "aom" | "arbn" | "avs" | "bc" | "bce" | "bin" | "bir" | "bp" | "brn" | "bsn" | "bvn" | "cc" | "cdi" | "cedula_juridica" | "cf" | "cif" | "cin" | "cipc" | "cn" | "cnp" | "cnpj" | "cpf" | "cpr" | "crc" | "crib" | "crn" | "cro" | "cui" | "cuil" | "curp" | "cuit" | "cvr" | "edrpou" | "ein" | "embg" | "emirates_id" | "en" | "fin" | "fn" | "gstin" | "gui" | "hetu" | "hkid" | "hn" | "ic" | "ico" | "id" | "id_broj" | "idno" | "idnp" | "idnr" | "if" | "iin" | "ik" | "inn" | "ird" | "itin" | "itr" | "iva" | "jmbg" | "kbo" | "kvk" | "matricule" | "mf" | "mn" | "ms" | "mst" | "nic" | "nicn" | "nie" | "nif" | "nin" | "nino" | "nip" | "nipc" | "nipt" | "nit" | "npwp" | "nric" | "nrn" | "nrt" | "ntn" | "nuit" | "nzbn" | "oib" | "orgnr" | "other" | "pan" | "partita_iva" | "pesel" | "pib" | "pin" | "pk" | "ppsn" | "qid" | "rc" | "regon" | "rfc" | "ricn" | "rif" | "rn" | "rnc" | "rnokpp" | "rp" | "rrn" | "rtn" | "ruc" | "rut" | "si" | "sin" | "siren" | "siret" | "spi" | "ssm" | "ssn" | "steuer_id" | "strn" | "tckn" | "tfn" | "tin" | "tpin" | "trn" | "ucn" | "uen" | "uic" | "uid" | "usc" | "ust_idnr" | "utr" | "vat" | "vkn" | "voen" | "y_tunnus", readonly "issuing_country": string, readonly "number"?: string, readonly "description"?: string, readonly "expiration"?: string, readonly "image_front"?: string, readonly "image_back"?: string }>, readonly "documents"?: ReadonlyArray<{ readonly "purposes": ReadonlyArray<"proof_of_account_purpose" | "proof_of_address" | "proof_of_individual_name_change" | "proof_of_relationship" | "proof_of_source_of_funds" | "proof_of_source_of_wealth" | "proof_of_tax_identification" | "other">, readonly "file": string, readonly "description"?: string }>, readonly "client_reference_id"?: string } & { readonly [x: string]: Schema.Json } +export const CreateIndividualCustomerPayload = Schema.StructWithRest(Schema.Struct({ "type": Schema.Literal("individual").annotate({ "description": "Type of the customer (individual vs. business)." }), "first_name": Schema.optionalKey(Schema.String.annotate({ "description": "The first name of the individual." }).check(Schema.isMinLength(2).annotate({ "expected": "a value with a length of at least 2" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" }))), "middle_name": Schema.optionalKey(Schema.String.annotate({ "description": "The middle name of the individual." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" }))), "last_name": Schema.optionalKey(Schema.String.annotate({ "description": "The last name of the individual." }).check(Schema.isMinLength(2).annotate({ "expected": "a value with a length of at least 2" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" }))), "transliterated_first_name": Schema.optionalKey(Schema.String.annotate({ "description": "Required when the `first_name` includes any non Latin-1 characters. Acceptable characters - Latin-1 Unicode Character Range: À-ÖØ-ßà-öø-ÿ; Standard Unicode Character Range: -~" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" }))), "transliterated_middle_name": Schema.optionalKey(Schema.String.annotate({ "description": "Required when the `middle_name` includes any non Latin-1 characters. Acceptable characters - Latin-1 Unicode Character Range: À-ÖØ-ßà-öø-ÿ; Standard Unicode Character Range: -~" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" }))), "transliterated_last_name": Schema.optionalKey(Schema.String.annotate({ "description": "Required when the `last_name` includes any non Latin-1 characters. Acceptable characters - Latin-1 Unicode Character Range: À-ÖØ-ßà-öø-ÿ; Standard Unicode Character Range: -~" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" }))), "email": Schema.optionalKey(Schema.String.annotate({ "description": "The individuals primary email address" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" }))), "phone": Schema.optionalKey(Schema.String.annotate({ "description": "The individuals primary phone number in format \"+12223334444\"" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" }))), "residential_address": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "street_line_1": Schema.String.check(Schema.isMinLength(4).annotate({ "expected": "a value with a length of at least 4" })), "street_line_2": Schema.optionalKey(Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "city": Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "subdivision": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-2 subdivision code. Must be supplied for US addresses." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))), "postal_code": Schema.optionalKey(Schema.String.annotate({ "description": "Must be supplied for countries that use postal codes." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "country": Schema.String.annotate({ "description": "Three-letter alpha-3 country code as defined in the ISO 3166-1 spec." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "The residential address of the individual. This must be a physical address, not a PO Box.", "writeOnly": true })), "transliterated_residential_address": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "street_line_1": Schema.String.check(Schema.isMinLength(4).annotate({ "expected": "a value with a length of at least 4" })), "street_line_2": Schema.optionalKey(Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "city": Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "subdivision": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-2 subdivision code. Must be supplied for US addresses." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))), "postal_code": Schema.optionalKey(Schema.String.annotate({ "description": "Must be supplied for countries that use postal codes." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "country": Schema.String.annotate({ "description": "Three-letter alpha-3 country code as defined in the ISO 3166-1 spec." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Required when any part of the `residential_address` includes any non Latin-1 characters. Acceptable characters - Latin-1 Unicode Character Range: À-ÖØ-ßà-öø-ÿ; Standard Unicode Character Range: -~", "writeOnly": true })), "birth_date": Schema.optionalKey(Schema.String.annotate({ "description": "Date of birth in format yyyy-mm-dd. Must be at least 18 years old." }).check(Schema.isMinLength(10).annotate({ "expected": "a value with a length of at least 10" })).check(Schema.isMaxLength(10).annotate({ "expected": "a value with a length of at most 10" }))), "signed_agreement_id": Schema.optionalKey(Schema.String.annotate({ "description": "The ID of the signed agreement that the customer completed. You can get a signed agreement id for a _new_ customer by following this guide [here](https://apidocs.bridge.xyz/docs/terms-of-service#tos-acceptance-for-a-new-customer).\n", "writeOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" }))), "endorsements": Schema.optionalKey(Schema.Array(Schema.Literals(["base", "cards", "cop", "faster_payments", "pix", "pix_onramp", "pix_offramp", "sepa", "spei"]).annotate({ "description": "The type of endorsement. Note: `pix_onramp` (BRL deposits via PIX) and `pix_offramp` (BRL withdrawals via PIX) can be requested individually for granular access. Requesting `pix` grants both directional endorsements. `pix_onramp` is not supported for non-BR individuals; if requested (or requested via `pix`) it will remain in an `endorsement_not_available_in_customers_region` state and no action is required.\n" })).annotate({ "description": "List of endorsements to request for this customer. If omitted, we'll attempt to grant `base` and `sepa`.\n", "writeOnly": true })), "account_purpose": Schema.optionalKey(Schema.Literals(["charitable_donations", "ecommerce_retail_payments", "investment_purposes", "operating_a_company", "other", "payments_to_friends_or_family_abroad", "personal_or_living_expenses", "protect_wealth", "purchase_goods_and_services", "receive_payment_for_freelancing", "receive_salary"]).annotate({ "description": "What is the primary purpose of the customer's account?\n\n_Required for high risk customers. More information found [here](https://apidocs.bridge.xyz/docs/individuals)._\n\n**EEA / BBSA in-scope individuals:** also required under program rules (not for associated persons). See [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#account-purpose-and-employment-status).\n" })), "account_purpose_other": Schema.optionalKey(Schema.String.annotate({ "description": "A supplemental description of the `account_purpose`.\n\n_Required if the `account_purpose` is `other`._\n" })), "employment_status": Schema.optionalKey(Schema.Literals(["employed", "homemaker", "retired", "self_employed", "student", "unemployed"]).annotate({ "description": "What is the customer's current employment status?\n\n_Required for high risk customers. More information found [here](https://apidocs.bridge.xyz/docs/individuals)._\n\n**EEA / BBSA in-scope individuals:** also required under program rules (not for associated persons). See [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#account-purpose-and-employment-status).\n" })), "expected_monthly_payments_usd": Schema.optionalKey(Schema.Literals(["0_4999", "5000_9999", "10000_49999", "50000_plus"]).annotate({ "description": "What is the expected monthly volume of payments the customer will be sending or receiving?\n\n_Required for high risk customers. More information found [here](https://apidocs.bridge.xyz/docs/individuals)_\n" })), "acting_as_intermediary": Schema.optionalKey(Schema.Boolean.annotate({ "description": "Is the customer acting as an intermediary for a third party?\n\n_Required for high risk customers. More information found [here](https://apidocs.bridge.xyz/docs/individuals)_\n" })), "most_recent_occupation": Schema.optionalKey(Schema.String.annotate({ "description": "What is the customer's most recent occupation? Specify the relevant alphanumeric occupation code. See the [list of occupations](https://apidocs.bridge.xyz/page/sof-eu-most-recent-occupation-list) for the complete list of valid occupations and codes. _Required for Restricted countries._\n\n_Required for high risk customers. More information found [here](https://apidocs.bridge.xyz/docs/individuals)_\n" })), "source_of_funds": Schema.optionalKey(Schema.Literals(["company_funds", "ecommerce_reseller", "gambling_proceeds", "gifts", "government_benefits", "inheritance", "investments_loans", "pension_retirement", "salary", "sale_of_assets_real_estate", "savings", "someone_elses_funds"]).annotate({ "description": "The individuals source of funds, e.g. government_benefits, investments_loans, salary, etc.\n\n_Required for high risk customers. More information found [here](https://apidocs.bridge.xyz/docs/individuals)_\n" })), "nationality": Schema.optionalKey(Schema.String.annotate({ "description": "Legacy single nationality as ISO 3166-1 alpha-3. Prefer `nationalities` to send **all** nationalities. During migration Bridge honors either field; `nationality` will be deprecated after migration. **EEA / BBSA program:** see [Nationalities](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#nationalities).\n", "writeOnly": true })), "nationalities": Schema.optionalKey(Schema.Array(Schema.String.check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))).annotate({ "description": "All nationalities held by the customer (ISO 3166-1 alpha-3 codes). **EEA / BBSA in-scope individuals:** required. See [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#nationalities).\n", "writeOnly": true })), "place_of_birth": Schema.optionalKey(Schema.Struct({ "country": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-1 alpha-3 country code for the place of birth." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))), "city": Schema.optionalKey(Schema.String.annotate({ "description": "City of birth (recommended for EEA)." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))) }).annotate({ "description": "Country (and optionally city) of birth. **EEA / BBSA in-scope customers:** supply when onboarding individuals or associated persons under the [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#country-of-birth-and-city-of-birth). This is a sparse address — no street address. At least `country` should be present when the object is sent; `city` is recommended and will be required by EU law in 2027.\n", "writeOnly": true })), "verified_database_at": Schema.optionalKey(Schema.String.annotate({ "description": "Write-only ISO 8601 timestamp. For **EEA in-scope** customers on **reliance** (`TWO_FORMS_OF_ID_RELIANCE` in `eea_requirements.rb`), may stand in for a database identity check together with `verified_govid_at`. See [EEA updated requirements — identity](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements).\n", "writeOnly": true, "format": "date-time" })), "verified_govid_at": Schema.optionalKey(Schema.String.annotate({ "description": "Write-only ISO 8601 timestamp. For **EEA in-scope** customers on **reliance**, use with a second factor (`verified_selfie_at` or `verified_database_at`) per `TWO_FORMS_OF_ID_RELIANCE`. See [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements).\n", "writeOnly": true, "format": "date-time" })), "verified_selfie_at": Schema.optionalKey(Schema.String.annotate({ "description": "Write-only ISO 8601 timestamp. For **EEA in-scope** customers on **reliance**, pairs with `verified_govid_at` or `verified_database_at` under `TWO_FORMS_OF_ID_RELIANCE`.\n", "writeOnly": true, "format": "date-time" })), "liveness_check_selfies": Schema.optionalKey(Schema.Array(Schema.Struct({ "image": Schema.String.annotate({ "description": "Base64 encoded image* of the selfie, following the data-uri scheme i.e. data:image/[type];base64,[base_64_encoded_file_contents], with a minimum size of 200px x 200px \n\n*Maximum File Size: 15MB\n\n*Valid file types: .jpeg, .jpg, .png, .heic, .heif, .tif, .tiff" }) })).annotate({ "description": "Selfie images to submit for Bridge's liveness verification. Use this when you are collecting the customer's selfie on behalf of Bridge.\n\n**EEA in-scope** customers: selfies submitted via this field are not sufficient. The selfie must be collected through the Persona hosted flow (via a KYC link). See [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements).\n", "writeOnly": true })), "identifying_information": Schema.optionalKey(Schema.Array(Schema.Struct({ "type": Schema.Literals(["drivers_license", "matriculate_id", "military_id", "national_id", "passport", "permanent_residency_id", "state_or_provincial_id", "visa", "abn", "acn", "ahv", "ak", "aom", "arbn", "avs", "bc", "bce", "bin", "bir", "bp", "brn", "bsn", "bvn", "cc", "cdi", "cedula_juridica", "cf", "cif", "cin", "cipc", "cn", "cnp", "cnpj", "cpf", "cpr", "crc", "crib", "crn", "cro", "cui", "cuil", "curp", "cuit", "cvr", "edrpou", "ein", "embg", "emirates_id", "en", "fin", "fn", "gstin", "gui", "hetu", "hkid", "hn", "ic", "ico", "id", "id_broj", "idno", "idnp", "idnr", "if", "iin", "ik", "inn", "ird", "itin", "itr", "iva", "jmbg", "kbo", "kvk", "matricule", "mf", "mn", "ms", "mst", "nic", "nicn", "nie", "nif", "nin", "nino", "nip", "nipc", "nipt", "nit", "npwp", "nric", "nrn", "nrt", "ntn", "nuit", "nzbn", "oib", "orgnr", "other", "pan", "partita_iva", "pesel", "pib", "pin", "pk", "ppsn", "qid", "rc", "regon", "rfc", "ricn", "rif", "rn", "rnc", "rnokpp", "rp", "rrn", "rtn", "ruc", "rut", "si", "sin", "siren", "siret", "spi", "ssm", "ssn", "steuer_id", "strn", "tckn", "tfn", "tin", "tpin", "trn", "ucn", "uen", "uic", "uid", "usc", "ust_idnr", "utr", "vat", "vkn", "voen", "y_tunnus"]).annotate({ "description": "Tax identification number type or government-issued ID document type (see enum). Country-specific tax and national ID lists: [Individuals](https://apidocs.bridge.xyz/docs/individual-tax-identification-numbers-by-country), [Businesses](https://apidocs.bridge.xyz/docs/business-tax-identification-numbers-by-country).\n\n**EEA / BBSA (policy in `eea_requirements.rb`):** In-scope individuals and UBOs need **both** a valid national-ID-type entry and a valid TIN per [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements). In-scope businesses need business registration **and** business tax ID types per country tables there. **TIN issuing country** must match residence (individuals) or incorporation (businesses). **Foreign tax** outside the incorporation country: set `has_foreign_tax_registration` on the business customer and add TIN objects per jurisdiction ([foreign tax / tax residency](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#tax-residency-status-foreign-tax-registry)).\n" }), "issuing_country": Schema.String.annotate({ "description": "The ISO 3166-1 (three-character) country code that issued the provided document." }), "number": Schema.optionalKey(Schema.String.annotate({ "description": "The unique identifier of the document. Required if this document is being used as a tax identification number (e.g., you are providing a passport or national_id with no other identification)." })), "description": Schema.optionalKey(Schema.String.annotate({ "description": "A description describing the provided document. This field is required when `other` is selected." })), "expiration": Schema.optionalKey(Schema.String.annotate({ "description": "The expiration date of the given document in yyyy-mm-dd format." })), "image_front": Schema.optionalKey(Schema.String.annotate({ "description": "This field is optionally accepted for tax_id types, but required for government_id types. Base64 encoded image* of the front side of the provided document, following the data-uri scheme i.e. data:image/[type];base64,[base_64_encoded_file_contents], with a minimum size of 200px x 200px \\n\\n*Maximum File Size: 15MB\\n\\n*Valid file types: .pdf, .jpeg, .jpg, .png, .heic, .tif\n\n_Note: When combined with an `image_back`, the combined size of both images must not exceed 24MB._\n" })), "image_back": Schema.optionalKey(Schema.String.annotate({ "description": "Base64 encoded image* of the back side of the provided document, following the data-uri scheme i.e. data:image/[type];base64,[base_64_encoded_file_contents], with a minimum size of 200px x 200px \\n\\n*Maximum File Size: 15MB\\n\\n*Valid file types: .pdf, .jpeg, .jpg, .png, .heic, .tif\n\n_Note: When combined with an `image_front`, the combined size of both images must not exceed 24MB._\n" })) })).annotate({ "title": "Identification Information", "writeOnly": true })), "documents": Schema.optionalKey(Schema.Array(Schema.Struct({ "purposes": Schema.Array(Schema.Literals(["proof_of_account_purpose", "proof_of_address", "proof_of_individual_name_change", "proof_of_relationship", "proof_of_source_of_funds", "proof_of_source_of_wealth", "proof_of_tax_identification", "other"])).annotate({ "description": "A list of purposes that the given document serves. Click \"ADD STRING\" to see common document purposes for individuals, or view the full list of possible values [here](https://apidocs.bridge.xyz/docs/supported-documents)." }), "file": Schema.String.annotate({ "description": "Base64 encoded image* of the provided document, following the data-uri scheme i.e. data:image/[type];base64,[base_64_encoded_file_contents], with a minimum size of 200px x 200px \n\n*Maximum File Size: 24MB\n\n*Valid file types: .pdf, .jpeg, .jpg, .png, .heic, .tif" }), "description": Schema.optionalKey(Schema.String.annotate({ "description": "A description describing the provided document. This field is required when `other` is provided as one of the purposes." })) })).annotate({ "title": "Documents", "description": "Please click \"ADD OBJECT\" for more information.", "writeOnly": true })), "client_reference_id": Schema.optionalKey(Schema.String.annotate({ "description": "Caller-provided identifier used to correlate this customer with your internal records. Returned in API and webhook responses." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" }))) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "title": "Individual Customer", "identifier": "CreateIndividualCustomerPayload" }) +export type CreateBusinessCustomerPayload = { readonly "type"?: "business", readonly "business_legal_name"?: string, readonly "transliterated_business_legal_name"?: string, readonly "business_trade_name"?: string, readonly "transliterated_business_trade_name"?: string, readonly "business_description"?: string, readonly "has_foreign_tax_registration"?: boolean, readonly "email"?: string, readonly "phone"?: string, readonly "business_type"?: "cooperative" | "corporation" | "llc" | "other" | "partnership" | "sole_prop" | "trust", readonly "primary_website"?: string, readonly "other_websites"?: ReadonlyArray, readonly "registered_address"?: { readonly "street_line_1": string, readonly "street_line_2"?: string, readonly "city": string, readonly "subdivision"?: string, readonly "postal_code"?: string, readonly "country": string } & { readonly [x: string]: Schema.Json }, readonly "transliterated_registered_address"?: { readonly "street_line_1": string, readonly "street_line_2"?: string, readonly "city": string, readonly "subdivision"?: string, readonly "postal_code"?: string, readonly "country": string } & { readonly [x: string]: Schema.Json }, readonly "physical_address"?: { readonly "street_line_1": string, readonly "street_line_2"?: string, readonly "city": string, readonly "subdivision"?: string, readonly "postal_code"?: string, readonly "country": string } & { readonly [x: string]: Schema.Json }, readonly "transliterated_physical_address"?: { readonly "street_line_1": string, readonly "street_line_2"?: string, readonly "city": string, readonly "subdivision"?: string, readonly "postal_code"?: string, readonly "country": string } & { readonly [x: string]: Schema.Json }, readonly "signed_agreement_id"?: string, readonly "is_dao"?: boolean, readonly "compliance_screening_explanation"?: string, readonly "associated_persons"?: ReadonlyArray<{ readonly "first_name": string, readonly "middle_name"?: string, readonly "last_name": string, readonly "transliterated_first_name"?: string, readonly "transliterated_middle_name"?: string, readonly "transliterated_last_name"?: string, readonly "email": string, readonly "phone"?: string, readonly "residential_address": { readonly "street_line_1": string, readonly "street_line_2"?: string, readonly "city": string, readonly "subdivision"?: string, readonly "postal_code"?: string, readonly "country": string } & { readonly [x: string]: Schema.Json }, readonly "transliterated_residential_address"?: { readonly "street_line_1": string, readonly "street_line_2"?: string, readonly "city": string, readonly "subdivision"?: string, readonly "postal_code"?: string, readonly "country": string } & { readonly [x: string]: Schema.Json }, readonly "birth_date": string, readonly "nationality"?: string, readonly "nationalities"?: ReadonlyArray, readonly "place_of_birth"?: { readonly "country"?: string, readonly "city"?: string }, readonly "verified_database_at"?: string, readonly "has_ownership": boolean, readonly "has_control": boolean, readonly "is_signer": boolean, readonly "is_director"?: boolean, readonly "title"?: string, readonly "ownership_percentage"?: number, readonly "attested_ownership_structure_at"?: string, readonly "verified_account_authorization_at"?: string, readonly "relationship_established_at"?: string, readonly "verified_govid_at"?: string, readonly "verified_selfie_at"?: string, readonly "identifying_information": ReadonlyArray<{ readonly "type": "drivers_license" | "matriculate_id" | "military_id" | "national_id" | "passport" | "permanent_residency_id" | "state_or_provincial_id" | "visa" | "abn" | "acn" | "ahv" | "ak" | "aom" | "arbn" | "avs" | "bc" | "bce" | "bin" | "bir" | "bp" | "brn" | "bsn" | "bvn" | "cc" | "cdi" | "cedula_juridica" | "cf" | "cif" | "cin" | "cipc" | "cn" | "cnp" | "cnpj" | "cpf" | "cpr" | "crc" | "crib" | "crn" | "cro" | "cui" | "cuil" | "curp" | "cuit" | "cvr" | "edrpou" | "ein" | "embg" | "emirates_id" | "en" | "fin" | "fn" | "gstin" | "gui" | "hetu" | "hkid" | "hn" | "ic" | "ico" | "id" | "id_broj" | "idno" | "idnp" | "idnr" | "if" | "iin" | "ik" | "inn" | "ird" | "itin" | "itr" | "iva" | "jmbg" | "kbo" | "kvk" | "matricule" | "mf" | "mn" | "ms" | "mst" | "nic" | "nicn" | "nie" | "nif" | "nin" | "nino" | "nip" | "nipc" | "nipt" | "nit" | "npwp" | "nric" | "nrn" | "nrt" | "ntn" | "nuit" | "nzbn" | "oib" | "orgnr" | "other" | "pan" | "partita_iva" | "pesel" | "pib" | "pin" | "pk" | "ppsn" | "qid" | "rc" | "regon" | "rfc" | "ricn" | "rif" | "rn" | "rnc" | "rnokpp" | "rp" | "rrn" | "rtn" | "ruc" | "rut" | "si" | "sin" | "siren" | "siret" | "spi" | "ssm" | "ssn" | "steuer_id" | "strn" | "tckn" | "tfn" | "tin" | "tpin" | "trn" | "ucn" | "uen" | "uic" | "uid" | "usc" | "ust_idnr" | "utr" | "vat" | "vkn" | "voen" | "y_tunnus", readonly "issuing_country": string, readonly "number"?: string, readonly "description"?: string, readonly "expiration"?: string, readonly "image_front"?: string, readonly "image_back"?: string }>, readonly "documents"?: ReadonlyArray<{ readonly "purposes": ReadonlyArray<"proof_of_account_purpose" | "proof_of_address" | "proof_of_individual_name_change" | "proof_of_relationship" | "proof_of_source_of_funds" | "proof_of_source_of_wealth" | "proof_of_tax_identification" | "other">, readonly "file": string, readonly "description"?: string }> } & { readonly [x: string]: Schema.Json }>, readonly "endorsements"?: ReadonlyArray<"base" | "cards" | "cop" | "faster_payments" | "pix" | "pix_onramp" | "pix_offramp" | "sepa" | "spei">, readonly "business_industry"?: ReadonlyArray, readonly "publicly_traded_listings"?: ReadonlyArray<{ readonly "market_identifier_code": string, readonly "stock_number": string, readonly "ticker": string }>, readonly "ownership_threshold"?: number, readonly "has_material_intermediary_ownership"?: boolean, readonly "estimated_annual_revenue_usd"?: "0_99999" | "100000_999999" | "1000000_9999999" | "10000000_49999999" | "50000000_249999999" | "250000000_plus", readonly "expected_monthly_payments_usd"?: number, readonly "expected_monthly_swift_transaction_volume"?: number, readonly "operates_in_prohibited_countries"?: boolean, readonly "account_purpose"?: "charitable_donations" | "ecommerce_retail_payments" | "investment_purposes" | "other" | "payments_to_friends_or_family_abroad" | "payroll" | "personal_or_living_expenses" | "protect_wealth" | "purchase_goods_and_services" | "receive_payments_for_goods_and_services" | "tax_optimization" | "third_party_money_transmission" | "treasury_management", readonly "account_purpose_other"?: string, readonly "high_risk_activities_explanation"?: string, readonly "high_risk_activities"?: ReadonlyArray<"adult_entertainment" | "gambling" | "hold_client_funds" | "investment_services" | "lending_banking" | "marijuana_or_related_services" | "money_services" | "nicotine_tobacco_or_related_services" | "operate_foreign_exchange_virtual_currencies_brokerage_otc" | "pharmaceuticals" | "precious_metals_precious_stones_jewelry" | "safe_deposit_box_rentals" | "third_party_payment_processing" | "weapons_firearms_and_explosives" | "none_of_the_above">, readonly "source_of_funds"?: "business_loans" | "grants" | "inter_company_funds" | "investment_proceeds" | "legal_settlement" | "owners_capital" | "pension_retirement" | "sale_of_assets" | "sales_of_goods_and_services" | "third_party_funds" | "treasury_reserves", readonly "source_of_funds_description"?: string, readonly "conducts_money_services"?: boolean, readonly "conducts_money_services_using_bridge"?: boolean, readonly "conducts_money_services_description"?: string, readonly "identifying_information"?: ReadonlyArray<{ readonly "type": "drivers_license" | "matriculate_id" | "military_id" | "national_id" | "passport" | "permanent_residency_id" | "state_or_provincial_id" | "visa" | "abn" | "acn" | "ahv" | "ak" | "aom" | "arbn" | "avs" | "bc" | "bce" | "bin" | "bir" | "bp" | "brn" | "bsn" | "bvn" | "cc" | "cdi" | "cedula_juridica" | "cf" | "cif" | "cin" | "cipc" | "cn" | "cnp" | "cnpj" | "cpf" | "cpr" | "crc" | "crib" | "crn" | "cro" | "cui" | "cuil" | "curp" | "cuit" | "cvr" | "edrpou" | "ein" | "embg" | "emirates_id" | "en" | "fin" | "fn" | "gstin" | "gui" | "hetu" | "hkid" | "hn" | "ic" | "ico" | "id" | "id_broj" | "idno" | "idnp" | "idnr" | "if" | "iin" | "ik" | "inn" | "ird" | "itin" | "itr" | "iva" | "jmbg" | "kbo" | "kvk" | "matricule" | "mf" | "mn" | "ms" | "mst" | "nic" | "nicn" | "nie" | "nif" | "nin" | "nino" | "nip" | "nipc" | "nipt" | "nit" | "npwp" | "nric" | "nrn" | "nrt" | "ntn" | "nuit" | "nzbn" | "oib" | "orgnr" | "other" | "pan" | "partita_iva" | "pesel" | "pib" | "pin" | "pk" | "ppsn" | "qid" | "rc" | "regon" | "rfc" | "ricn" | "rif" | "rn" | "rnc" | "rnokpp" | "rp" | "rrn" | "rtn" | "ruc" | "rut" | "si" | "sin" | "siren" | "siret" | "spi" | "ssm" | "ssn" | "steuer_id" | "strn" | "tckn" | "tfn" | "tin" | "tpin" | "trn" | "ucn" | "uen" | "uic" | "uid" | "usc" | "ust_idnr" | "utr" | "vat" | "vkn" | "voen" | "y_tunnus", readonly "issuing_country": string, readonly "number"?: string, readonly "description"?: string, readonly "expiration"?: string, readonly "image_front"?: string, readonly "image_back"?: string }>, readonly "documents"?: ReadonlyArray<{ readonly "purposes": ReadonlyArray<"aml_comfort_letter" | "business_formation" | "directors_registry" | "e_signature_certificate" | "evidence_of_good_standing" | "flow_of_funds" | "marketing_materials" | "ownership_chart" | "ownership_information" | "proof_of_account_purpose" | "proof_of_address" | "proof_of_entity_name_change" | "proof_of_nature_of_business" | "proof_of_signatory_authority" | "proof_of_source_of_funds" | "proof_of_source_of_wealth" | "proof_of_tax_identification" | "shareholder_register" | "other">, readonly "file": string, readonly "description"?: string }>, readonly "incorporation_date"?: string, readonly "verified_business_formation_at"?: string, readonly "verified_business_registry_at"?: string, readonly "verified_evidence_of_good_standing_at"?: string, readonly "verified_ownership_at"?: string, readonly "regulated_activity"?: { readonly "regulated_activities_description": string, readonly "primary_regulatory_authority_country": string, readonly "primary_regulatory_authority_name": string, readonly "license_number": string }, readonly "acting_as_intermediary"?: boolean, readonly "client_reference_id"?: string } & { readonly [x: string]: Schema.Json } +export const CreateBusinessCustomerPayload = Schema.StructWithRest(Schema.Struct({ "type": Schema.optionalKey(Schema.Literal("business").annotate({ "description": "Type of the customer (individual vs. business)" })), "business_legal_name": Schema.optionalKey(Schema.String.annotate({ "description": "The official registered name of the business as documented with government authorities." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" }))), "transliterated_business_legal_name": Schema.optionalKey(Schema.String.annotate({ "description": "Required if `business_legal_name` includes any non Latin-1 characters. Acceptable characters - Latin-1 Unicode Character Range: À-ÖØ-ßà-öø-ÿ; Standard Unicode Character Range: -~" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" }))), "business_trade_name": Schema.optionalKey(Schema.String.annotate({ "description": "The trading name or DBA (Doing Business As) name under which the business operates publicly." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" }))), "transliterated_business_trade_name": Schema.optionalKey(Schema.String.annotate({ "description": "Required if `business_trade` includes any non Latin-1 characters. Acceptable characters - Latin-1 Unicode Character Range: À-ÖØ-ßà-öø-ÿ; Standard Unicode Character Range: -~" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" }))), "business_description": Schema.optionalKey(Schema.String.annotate({ "description": "A brief summary of the business" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" }))), "has_foreign_tax_registration": Schema.optionalKey(Schema.Boolean.annotate({ "description": "Whether the business is registered for tax in any jurisdiction **outside** its country of incorporation. When `true`, provide additional tax identifiers in `identifying_information` whose `issuing_country` reflects each foreign registration, per [EEA tax residency](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#tax-residency-status-foreign-tax-registry).\n" })), "email": Schema.optionalKey(Schema.String.annotate({ "description": "The business's primary email address" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" }))), "phone": Schema.optionalKey(Schema.String.annotate({ "description": "The business's primary phone number in format \"+12223334444\"" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" }))), "business_type": Schema.optionalKey(Schema.Literals(["cooperative", "corporation", "llc", "other", "partnership", "sole_prop", "trust"]).annotate({ "description": "How the business is legally registered" })), "primary_website": Schema.optionalKey(Schema.String.annotate({ "description": "The business's primary website/web presence. A document with purpose 'proof_of_nature_of_business' is required if this is not provided" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" }))), "other_websites": Schema.optionalKey(Schema.Array(Schema.String).annotate({ "description": "The business's other websites and social media handles" })), "registered_address": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "street_line_1": Schema.String.check(Schema.isMinLength(4).annotate({ "expected": "a value with a length of at least 4" })), "street_line_2": Schema.optionalKey(Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "city": Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "subdivision": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-2 subdivision code. Must be supplied for US addresses." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))), "postal_code": Schema.optionalKey(Schema.String.annotate({ "description": "Must be supplied for countries that use postal codes." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "country": Schema.String.annotate({ "description": "Three-letter alpha-3 country code as defined in the ISO 3166-1 spec." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "The official registered address of the business.", "writeOnly": true })), "transliterated_registered_address": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "street_line_1": Schema.String.check(Schema.isMinLength(4).annotate({ "expected": "a value with a length of at least 4" })), "street_line_2": Schema.optionalKey(Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "city": Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "subdivision": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-2 subdivision code. Must be supplied for US addresses." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))), "postal_code": Schema.optionalKey(Schema.String.annotate({ "description": "Must be supplied for countries that use postal codes." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "country": Schema.String.annotate({ "description": "Three-letter alpha-3 country code as defined in the ISO 3166-1 spec." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Required if any part of the `registered_address` includes any non Latin-1 characters. Acceptable characters - Latin-1 Unicode Character Range: À-ÖØ-ßà-öø-ÿ; Standard Unicode Character Range: -~", "writeOnly": true })), "physical_address": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "street_line_1": Schema.String.check(Schema.isMinLength(4).annotate({ "expected": "a value with a length of at least 4" })), "street_line_2": Schema.optionalKey(Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "city": Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "subdivision": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-2 subdivision code. Must be supplied for US addresses." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))), "postal_code": Schema.optionalKey(Schema.String.annotate({ "description": "Must be supplied for countries that use postal codes." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "country": Schema.String.annotate({ "description": "Three-letter alpha-3 country code as defined in the ISO 3166-1 spec." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "The physical address for the primary place of business. This must be a physical address and cannot be a PO Box.", "writeOnly": true })), "transliterated_physical_address": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "street_line_1": Schema.String.check(Schema.isMinLength(4).annotate({ "expected": "a value with a length of at least 4" })), "street_line_2": Schema.optionalKey(Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "city": Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "subdivision": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-2 subdivision code. Must be supplied for US addresses." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))), "postal_code": Schema.optionalKey(Schema.String.annotate({ "description": "Must be supplied for countries that use postal codes." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "country": Schema.String.annotate({ "description": "Three-letter alpha-3 country code as defined in the ISO 3166-1 spec." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Required if any part of the `physical_address` includes any non Latin-1 characters. Acceptable characters - Latin-1 Unicode Character Range: À-ÖØ-ßà-öø-ÿ; Standard Unicode Character Range: -~", "writeOnly": true })), "signed_agreement_id": Schema.optionalKey(Schema.String.annotate({ "description": "The ID of the signed agreement that the customer completed. You can get a signed agreement id for a _new_ customer by following [this guide](https://apidocs.bridge.xyz/docs/terms-of-service#tos-acceptance-for-a-new-customer).\n", "writeOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" }))), "is_dao": Schema.optionalKey(Schema.Boolean.annotate({ "description": "Whether the business is a DAO (Decentralized Autonomous Organization)" })), "compliance_screening_explanation": Schema.optionalKey(Schema.String.annotate({ "description": "Required if `conducts_money_services` is true. A detailed description of the business's compliance and anti-money laundering controls and practices." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" }))), "associated_persons": Schema.optionalKey(Schema.Array(Schema.StructWithRest(Schema.Struct({ "first_name": Schema.String.annotate({ "description": "The first name of the associated person" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" })), "middle_name": Schema.optionalKey(Schema.String.annotate({ "description": "The middle name of the associated person" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" }))), "last_name": Schema.String.annotate({ "description": "The last name of the associated person" }).check(Schema.isMinLength(2).annotate({ "expected": "a value with a length of at least 2" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" })), "transliterated_first_name": Schema.optionalKey(Schema.String.annotate({ "description": "Required when the `first_name` includes any non Latin-1 characters. Acceptable characters - Latin-1 Unicode Character Range: À-ÖØ-ßà-öø-ÿ; Standard Unicode Character Range: -~" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" }))), "transliterated_middle_name": Schema.optionalKey(Schema.String.annotate({ "description": "Required when the `middle_name` includes any non Latin-1 characters. Acceptable characters - Latin-1 Unicode Character Range: À-ÖØ-ßà-öø-ÿ; Standard Unicode Character Range: -~" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" }))), "transliterated_last_name": Schema.optionalKey(Schema.String.annotate({ "description": "Required when the `last_name` includes any non Latin-1 characters. Acceptable characters - Latin-1 Unicode Character Range: À-ÖØ-ßà-öø-ÿ; Standard Unicode Character Range: -~" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" }))), "email": Schema.String.annotate({ "description": "The persons primary email address" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" })), "phone": Schema.optionalKey(Schema.String.annotate({ "description": "The persons phone in format \"+12223334444\"" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" }))), "residential_address": Schema.StructWithRest(Schema.Struct({ "street_line_1": Schema.String.check(Schema.isMinLength(4).annotate({ "expected": "a value with a length of at least 4" })), "street_line_2": Schema.optionalKey(Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "city": Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "subdivision": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-2 subdivision code. Must be supplied for US addresses." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))), "postal_code": Schema.optionalKey(Schema.String.annotate({ "description": "Must be supplied for countries that use postal codes." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "country": Schema.String.annotate({ "description": "Three-letter alpha-3 country code as defined in the ISO 3166-1 spec." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "The residential address of the associated person. This must be a physical address and cannot be a PO Box.", "writeOnly": true }), "transliterated_residential_address": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "street_line_1": Schema.String.check(Schema.isMinLength(4).annotate({ "expected": "a value with a length of at least 4" })), "street_line_2": Schema.optionalKey(Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "city": Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "subdivision": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-2 subdivision code. Must be supplied for US addresses." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))), "postal_code": Schema.optionalKey(Schema.String.annotate({ "description": "Must be supplied for countries that use postal codes." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "country": Schema.String.annotate({ "description": "Three-letter alpha-3 country code as defined in the ISO 3166-1 spec." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Required when any part of the `residential_address` includes any non Latin-1 characters. Acceptable characters - Latin-1 Unicode Character Range: À-ÖØ-ßà-öø-ÿ; Standard Unicode Character Range: -~", "writeOnly": true })), "birth_date": Schema.String.annotate({ "description": "Date of birth in format yyyy-mm-dd. Must be at least 18 years old." }).check(Schema.isMinLength(10).annotate({ "expected": "a value with a length of at least 10" })).check(Schema.isMaxLength(10).annotate({ "expected": "a value with a length of at most 10" })), "nationality": Schema.optionalKey(Schema.String.annotate({ "description": "Legacy single nationality (ISO 3166-1 alpha-3). Prefer `nationalities` for all nationalities. See individual customer `nationality` / `nationalities` and [EEA nationalities](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#nationalities).\n", "writeOnly": true })), "nationalities": Schema.optionalKey(Schema.Array(Schema.String.check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))).annotate({ "description": "All nationalities for this associated person (ISO 3166-1 alpha-3). **EEA / BBSA in-scope businesses:** required on each UBO / associated person where policy applies.\n", "writeOnly": true })), "place_of_birth": Schema.optionalKey(Schema.Struct({ "country": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-1 alpha-3 country code for the place of birth." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))), "city": Schema.optionalKey(Schema.String.annotate({ "description": "City of birth (recommended for EEA)." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))) }).annotate({ "description": "Country (and optionally city) of birth. **EEA / BBSA in-scope customers:** supply when onboarding individuals or associated persons under the [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#country-of-birth-and-city-of-birth). This is a sparse address — no street address. At least `country` should be present when the object is sent; `city` is recommended and will be required by EU law in 2027.\n", "writeOnly": true })), "verified_database_at": Schema.optionalKey(Schema.String.annotate({ "description": "Write-only ISO 8601 timestamp. For **EEA in-scope** associated persons on **reliance**, second factor with `verified_govid_at` under `TWO_FORMS_OF_ID_RELIANCE`.\n", "writeOnly": true, "format": "date-time" })), "has_ownership": Schema.Boolean.annotate({ "description": "True if this person has at least 25% ownership of the business." }), "has_control": Schema.Boolean.annotate({ "description": "True if this is the control person of the company, having significant responsibility to control, manage or influence the activities of the business entity. At least one control person must be specified. " }), "is_signer": Schema.Boolean.annotate({ "description": "True if this person is able to authorize transactions on behalf of the business. At least one signer must be specified." }), "is_director": Schema.optionalKey(Schema.Boolean.annotate({ "description": "True if this person is an appointed director of the company. **EEA / BBSA in-scope businesses:** must be set for every associated person (complete director list). See [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#complete-director-list)." })), "title": Schema.optionalKey(Schema.String.annotate({ "description": "The title of this associated person at the company, e.g. CEO, CFO, etc. Required if has_control is true." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" }))), "ownership_percentage": Schema.optionalKey(Schema.Number.annotate({ "description": "Ultimate ownership percentage of the business. **EEA / BBSA in-scope businesses:** required when `has_ownership` is true for UBOs at or above the configured threshold (default 25%). See [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#ownership-percentage-per-ubo).\n", "writeOnly": true }).check(Schema.isInt().annotate({ "expected": "an integer" }))), "attested_ownership_structure_at": Schema.optionalKey(Schema.String.annotate({ "description": "The date or timestamp when this individual attested to the correctness of the ownership structure provided to Bridge. If provided by at least one control person, ownership documents for the business are not required.", "writeOnly": true })), "verified_account_authorization_at": Schema.optionalKey(Schema.String.annotate({ "description": "Write-only ISO 8601 timestamp. For **EEA in-scope** businesses on **reliance**, may satisfy signatory authority for signers who are not owner, director, or control person (`signature_authority_requirement(for_reliance: true)`); alternative is `documents` with purpose `proof_of_signatory_authority`. See [EEA updated requirements — LOA](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#letter-of-authority-loa).\n", "writeOnly": true, "format": "date-time" })), "relationship_established_at": Schema.optionalKey(Schema.String.annotate({ "description": "The date or timestamp when the associated person relationship was established in format yyyy-mm-dd." })), "verified_govid_at": Schema.optionalKey(Schema.String.annotate({ "description": "Write-only ISO 8601 timestamp. For **EEA in-scope** associated persons on **reliance**, use with `verified_selfie_at` or `verified_database_at` under `TWO_FORMS_OF_ID_RELIANCE`.\n", "writeOnly": true, "format": "date-time" })), "verified_selfie_at": Schema.optionalKey(Schema.String.annotate({ "description": "Write-only ISO 8601 timestamp. For **EEA in-scope** associated persons on **reliance**, pairs with `verified_govid_at` or `verified_database_at` under `TWO_FORMS_OF_ID_RELIANCE`.\n", "writeOnly": true, "format": "date-time" })), "identifying_information": Schema.Array(Schema.Struct({ "type": Schema.Literals(["drivers_license", "matriculate_id", "military_id", "national_id", "passport", "permanent_residency_id", "state_or_provincial_id", "visa", "abn", "acn", "ahv", "ak", "aom", "arbn", "avs", "bc", "bce", "bin", "bir", "bp", "brn", "bsn", "bvn", "cc", "cdi", "cedula_juridica", "cf", "cif", "cin", "cipc", "cn", "cnp", "cnpj", "cpf", "cpr", "crc", "crib", "crn", "cro", "cui", "cuil", "curp", "cuit", "cvr", "edrpou", "ein", "embg", "emirates_id", "en", "fin", "fn", "gstin", "gui", "hetu", "hkid", "hn", "ic", "ico", "id", "id_broj", "idno", "idnp", "idnr", "if", "iin", "ik", "inn", "ird", "itin", "itr", "iva", "jmbg", "kbo", "kvk", "matricule", "mf", "mn", "ms", "mst", "nic", "nicn", "nie", "nif", "nin", "nino", "nip", "nipc", "nipt", "nit", "npwp", "nric", "nrn", "nrt", "ntn", "nuit", "nzbn", "oib", "orgnr", "other", "pan", "partita_iva", "pesel", "pib", "pin", "pk", "ppsn", "qid", "rc", "regon", "rfc", "ricn", "rif", "rn", "rnc", "rnokpp", "rp", "rrn", "rtn", "ruc", "rut", "si", "sin", "siren", "siret", "spi", "ssm", "ssn", "steuer_id", "strn", "tckn", "tfn", "tin", "tpin", "trn", "ucn", "uen", "uic", "uid", "usc", "ust_idnr", "utr", "vat", "vkn", "voen", "y_tunnus"]).annotate({ "description": "Tax identification number type or government-issued ID document type (see enum). Country-specific tax and national ID lists: [Individuals](https://apidocs.bridge.xyz/docs/individual-tax-identification-numbers-by-country), [Businesses](https://apidocs.bridge.xyz/docs/business-tax-identification-numbers-by-country).\n\n**EEA / BBSA (policy in `eea_requirements.rb`):** In-scope individuals and UBOs need **both** a valid national-ID-type entry and a valid TIN per [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements). In-scope businesses need business registration **and** business tax ID types per country tables there. **TIN issuing country** must match residence (individuals) or incorporation (businesses). **Foreign tax** outside the incorporation country: set `has_foreign_tax_registration` on the business customer and add TIN objects per jurisdiction ([foreign tax / tax residency](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#tax-residency-status-foreign-tax-registry)).\n" }), "issuing_country": Schema.String.annotate({ "description": "The ISO 3166-1 (three-character) country code that issued the provided document." }), "number": Schema.optionalKey(Schema.String.annotate({ "description": "The unique identifier of the document. Required if this document is being used as a tax identification number (e.g., you are providing a passport or national_id with no other identification)." })), "description": Schema.optionalKey(Schema.String.annotate({ "description": "A description describing the provided document. This field is required when `other` is selected." })), "expiration": Schema.optionalKey(Schema.String.annotate({ "description": "The expiration date of the given document in yyyy-mm-dd format." })), "image_front": Schema.optionalKey(Schema.String.annotate({ "description": "This field is optionally accepted for tax_id types, but required for government_id types. Base64 encoded image* of the front side of the provided document, following the data-uri scheme i.e. data:image/[type];base64,[base_64_encoded_file_contents], with a minimum size of 200px x 200px \\n\\n*Maximum File Size: 15MB\\n\\n*Valid file types: .pdf, .jpeg, .jpg, .png, .heic, .tif\n\n_Note: When combined with an `image_back`, the combined size of both images must not exceed 24MB._\n" })), "image_back": Schema.optionalKey(Schema.String.annotate({ "description": "Base64 encoded image* of the back side of the provided document, following the data-uri scheme i.e. data:image/[type];base64,[base_64_encoded_file_contents], with a minimum size of 200px x 200px \\n\\n*Maximum File Size: 15MB\\n\\n*Valid file types: .pdf, .jpeg, .jpg, .png, .heic, .tif\n\n_Note: When combined with an `image_front`, the combined size of both images must not exceed 24MB._\n" })) })).annotate({ "title": "Identification Information", "writeOnly": true }), "documents": Schema.optionalKey(Schema.Array(Schema.Struct({ "purposes": Schema.Array(Schema.Literals(["proof_of_account_purpose", "proof_of_address", "proof_of_individual_name_change", "proof_of_relationship", "proof_of_source_of_funds", "proof_of_source_of_wealth", "proof_of_tax_identification", "other"])).annotate({ "description": "A list of purposes that the given document serves. Click \"ADD STRING\" to see common document purposes for individuals, or view the full list of possible values [here](https://apidocs.bridge.xyz/docs/supported-documents)." }), "file": Schema.String.annotate({ "description": "Base64 encoded image* of the provided document, following the data-uri scheme i.e. data:image/[type];base64,[base_64_encoded_file_contents], with a minimum size of 200px x 200px \n\n*Maximum File Size: 24MB\n\n*Valid file types: .pdf, .jpeg, .jpg, .png, .heic, .tif" }), "description": Schema.optionalKey(Schema.String.annotate({ "description": "A description describing the provided document. This field is required when `other` is provided as one of the purposes." })) })).annotate({ "title": "Documents", "description": "Please click \"ADD OBJECT\" for more information.", "writeOnly": true })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))])).annotate({ "description": "List of notable people associated with the business such as UBOs." })), "endorsements": Schema.optionalKey(Schema.Array(Schema.Literals(["base", "cards", "cop", "faster_payments", "pix", "pix_onramp", "pix_offramp", "sepa", "spei"]).annotate({ "description": "The type of endorsement. Note: `pix_onramp` (BRL deposits via PIX) and `pix_offramp` (BRL withdrawals via PIX) can be requested individually for granular access. Requesting `pix` grants both directional endorsements. `pix_onramp` is not supported for non-BR individuals; if requested (or requested via `pix`) it will remain in an `endorsement_not_available_in_customers_region` state and no action is required.\n" })).annotate({ "description": "List of endorsements to request for this customer. If omitted, we'll attempt to grant `base` and `sepa`.\n", "writeOnly": true })), "business_industry": Schema.optionalKey(Schema.Array(Schema.String).annotate({ "description": "The industry in which this business operates. Click [here](https://apidocs.bridge.xyz/page/business-industry-list-updated-2022-naics-codes) for the complete list of valid industries and codes." })), "publicly_traded_listings": Schema.optionalKey(Schema.Array(Schema.Struct({ "market_identifier_code": Schema.String.annotate({ "description": "The 4-digit Market Identifier Code (MIC) (ISO 10383) for the venue where the business is publicly listed and traded." }), "stock_number": Schema.String.annotate({ "description": "The 12-digit International Securities Identification Number (ISIN) of the company without dashes (-)." }), "ticker": Schema.String.annotate({ "description": "The ticker for the business's publicly traded listing." }) })).annotate({ "description": "A list of public exchanges that the company is traded on if applicable.", "writeOnly": true })), "ownership_threshold": Schema.optionalKey(Schema.Number.annotate({ "description": "The applicable beneficial ownership threshold for the submitted `associated_persons` information. Valid values are between 5 to 25. Default value is 25." }).check(Schema.isInt().annotate({ "expected": "an integer" }))), "has_material_intermediary_ownership": Schema.optionalKey(Schema.Boolean.annotate({ "description": "The business has at least one intermediate legal entity owner with 25% or more ownership" })), "estimated_annual_revenue_usd": Schema.optionalKey(Schema.Literals(["0_99999", "100000_999999", "1000000_9999999", "10000000_49999999", "50000000_249999999", "250000000_plus"]).annotate({ "description": "Estimated annual revenue in USD\n\n_Required for high risk customers. More information found [here](https://apidocs.bridge.xyz/docs/business-accounts)_\n" })), "expected_monthly_payments_usd": Schema.optionalKey(Schema.Number.annotate({ "description": "Expected monthly payments in USD\n\n_Required for high risk customers. More information found [here](https://apidocs.bridge.xyz/docs/business-accounts)_\n" }).check(Schema.isInt().annotate({ "expected": "an integer" }))), "expected_monthly_swift_transaction_volume": Schema.optionalKey(Schema.Number.annotate({ "description": "Expected monthly SWIFT transaction volume in USD.\n\n_Deprecated: no longer required for the SWIFT endorsement._\n" }).check(Schema.isInt().annotate({ "expected": "an integer" }))), "operates_in_prohibited_countries": Schema.optionalKey(Schema.Boolean.annotate({ "description": "Does the business operate in any prohibited countries?\n\n_Required for high risk customers. More information found [here](https://apidocs.bridge.xyz/docs/business-accounts)_\n" })), "account_purpose": Schema.optionalKey(Schema.Literals(["charitable_donations", "ecommerce_retail_payments", "investment_purposes", "other", "payments_to_friends_or_family_abroad", "payroll", "personal_or_living_expenses", "protect_wealth", "purchase_goods_and_services", "receive_payments_for_goods_and_services", "tax_optimization", "third_party_money_transmission", "treasury_management"]).annotate({ "description": "What is the primary purpose of the business account?" })), "account_purpose_other": Schema.optionalKey(Schema.String.annotate({ "description": "Required if the primary purpose is 'other'." })), "high_risk_activities_explanation": Schema.optionalKey(Schema.String.annotate({ "description": "An explanation of the high risk activities that the business performs. \n\n_Required if `high_risk_activities` contains entries other than `none_of_the_above`_\n" })), "high_risk_activities": Schema.optionalKey(Schema.Array(Schema.Literals(["adult_entertainment", "gambling", "hold_client_funds", "investment_services", "lending_banking", "marijuana_or_related_services", "money_services", "nicotine_tobacco_or_related_services", "operate_foreign_exchange_virtual_currencies_brokerage_otc", "pharmaceuticals", "precious_metals_precious_stones_jewelry", "safe_deposit_box_rentals", "third_party_payment_processing", "weapons_firearms_and_explosives", "none_of_the_above"])).annotate({ "description": "List of high-risk activities the business is involved in.\n\n_Required for high risk customers. More information found [here](https://apidocs.bridge.xyz/docs/business-accounts)_\n" })), "source_of_funds": Schema.optionalKey(Schema.Literals(["business_loans", "grants", "inter_company_funds", "investment_proceeds", "legal_settlement", "owners_capital", "pension_retirement", "sale_of_assets", "sales_of_goods_and_services", "third_party_funds", "treasury_reserves"]).annotate({ "description": "The source of funds for the business, e.g. profits, income, venture capital, etc." })), "source_of_funds_description": Schema.optionalKey(Schema.String.annotate({ "description": "Description of the source of funds for the business' account.\n\n_Required for high risk customers. More information found [here](https://apidocs.bridge.xyz/docs/business-accounts)_\n" })), "conducts_money_services": Schema.optionalKey(Schema.Boolean.annotate({ "description": "The business offers money services, investment products, and/or other financial services.\n\n_Required for high risk customers. More information found [here](https://apidocs.bridge.xyz/docs/business-accounts)_\n" })), "conducts_money_services_using_bridge": Schema.optionalKey(Schema.Boolean.annotate({ "description": "The business plans to conduct money services, investment products, and/or other financial services using its Bridge account. A document with purpose 'flow_of_funds' is required if this is true.\n\n_Required if `conducts_money_services` is true_\n" })), "conducts_money_services_description": Schema.optionalKey(Schema.String.annotate({ "description": "Description of the money services offered by the business.\n\n_Required if `conducts_money_services` is true_\n" })), "identifying_information": Schema.optionalKey(Schema.Array(Schema.Struct({ "type": Schema.Literals(["drivers_license", "matriculate_id", "military_id", "national_id", "passport", "permanent_residency_id", "state_or_provincial_id", "visa", "abn", "acn", "ahv", "ak", "aom", "arbn", "avs", "bc", "bce", "bin", "bir", "bp", "brn", "bsn", "bvn", "cc", "cdi", "cedula_juridica", "cf", "cif", "cin", "cipc", "cn", "cnp", "cnpj", "cpf", "cpr", "crc", "crib", "crn", "cro", "cui", "cuil", "curp", "cuit", "cvr", "edrpou", "ein", "embg", "emirates_id", "en", "fin", "fn", "gstin", "gui", "hetu", "hkid", "hn", "ic", "ico", "id", "id_broj", "idno", "idnp", "idnr", "if", "iin", "ik", "inn", "ird", "itin", "itr", "iva", "jmbg", "kbo", "kvk", "matricule", "mf", "mn", "ms", "mst", "nic", "nicn", "nie", "nif", "nin", "nino", "nip", "nipc", "nipt", "nit", "npwp", "nric", "nrn", "nrt", "ntn", "nuit", "nzbn", "oib", "orgnr", "other", "pan", "partita_iva", "pesel", "pib", "pin", "pk", "ppsn", "qid", "rc", "regon", "rfc", "ricn", "rif", "rn", "rnc", "rnokpp", "rp", "rrn", "rtn", "ruc", "rut", "si", "sin", "siren", "siret", "spi", "ssm", "ssn", "steuer_id", "strn", "tckn", "tfn", "tin", "tpin", "trn", "ucn", "uen", "uic", "uid", "usc", "ust_idnr", "utr", "vat", "vkn", "voen", "y_tunnus"]).annotate({ "description": "Tax identification number type or government-issued ID document type (see enum). Country-specific tax and national ID lists: [Individuals](https://apidocs.bridge.xyz/docs/individual-tax-identification-numbers-by-country), [Businesses](https://apidocs.bridge.xyz/docs/business-tax-identification-numbers-by-country).\n\n**EEA / BBSA (policy in `eea_requirements.rb`):** In-scope individuals and UBOs need **both** a valid national-ID-type entry and a valid TIN per [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements). In-scope businesses need business registration **and** business tax ID types per country tables there. **TIN issuing country** must match residence (individuals) or incorporation (businesses). **Foreign tax** outside the incorporation country: set `has_foreign_tax_registration` on the business customer and add TIN objects per jurisdiction ([foreign tax / tax residency](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#tax-residency-status-foreign-tax-registry)).\n" }), "issuing_country": Schema.String.annotate({ "description": "The ISO 3166-1 (three-character) country code that issued the provided document." }), "number": Schema.optionalKey(Schema.String.annotate({ "description": "The unique identifier of the document. Required if this document is being used as a tax identification number (e.g., you are providing a passport or national_id with no other identification)." })), "description": Schema.optionalKey(Schema.String.annotate({ "description": "A description describing the provided document. This field is required when `other` is selected." })), "expiration": Schema.optionalKey(Schema.String.annotate({ "description": "The expiration date of the given document in yyyy-mm-dd format." })), "image_front": Schema.optionalKey(Schema.String.annotate({ "description": "This field is optionally accepted for tax_id types, but required for government_id types. Base64 encoded image* of the front side of the provided document, following the data-uri scheme i.e. data:image/[type];base64,[base_64_encoded_file_contents], with a minimum size of 200px x 200px \\n\\n*Maximum File Size: 15MB\\n\\n*Valid file types: .pdf, .jpeg, .jpg, .png, .heic, .tif\n\n_Note: When combined with an `image_back`, the combined size of both images must not exceed 24MB._\n" })), "image_back": Schema.optionalKey(Schema.String.annotate({ "description": "Base64 encoded image* of the back side of the provided document, following the data-uri scheme i.e. data:image/[type];base64,[base_64_encoded_file_contents], with a minimum size of 200px x 200px \\n\\n*Maximum File Size: 15MB\\n\\n*Valid file types: .pdf, .jpeg, .jpg, .png, .heic, .tif\n\n_Note: When combined with an `image_front`, the combined size of both images must not exceed 24MB._\n" })) })).annotate({ "title": "Identification Information", "writeOnly": true })), "documents": Schema.optionalKey(Schema.Array(Schema.Struct({ "purposes": Schema.Array(Schema.Literals(["aml_comfort_letter", "business_formation", "directors_registry", "e_signature_certificate", "evidence_of_good_standing", "flow_of_funds", "marketing_materials", "ownership_chart", "ownership_information", "proof_of_account_purpose", "proof_of_address", "proof_of_entity_name_change", "proof_of_nature_of_business", "proof_of_signatory_authority", "proof_of_source_of_funds", "proof_of_source_of_wealth", "proof_of_tax_identification", "shareholder_register", "other"])).annotate({ "description": "**EEA / BBSA (business KYB):** purposes used in [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements) include `business_formation`, `evidence_of_good_standing`, `ownership_information`, and `proof_of_signatory_authority` (letter of authorization). See supported-documents for the full enum [here](https://apidocs.bridge.xyz/docs/supported-documents).\n\nFor **non-reliance** EEA in-scope businesses, `business_formation`, `evidence_of_good_standing`, and `ownership_information` are evaluated **independently** in CPU policy: each may be satisfied by an uploaded/Persona-backed document **or**, when Stripe business-registry verification passes with the required checks and provider metadata, by that verification alone for that document slot (see `BUSINESS_REGISTRY_CHECK` and `BUSINESS_OWNERSHIP` in `eea_requirements.rb`).\n" }), "file": Schema.String.annotate({ "description": "Base64 encoded image of the provided document, following the data-uri scheme i.e. data:image/[type];base64,[base_64_encoded_file_contents], with a minimum size of 200px x 200px \n\n*Maximum File Size: 24MB\n\n*Valid file types: .pdf, .jpeg, .jpg, .png, .heic, .tif" }), "description": Schema.optionalKey(Schema.String.annotate({ "description": "A description describing the provided document. This field is required when `other` is provided as one of the purposes." })) })).annotate({ "title": "Documents", "description": "Please click \"ADD OBJECT\" for more information.", "writeOnly": true })), "incorporation_date": Schema.optionalKey(Schema.String.annotate({ "description": "The date the business was incorporated, in ISO 8601 format (YYYY-MM-DD).", "format": "date" })), "verified_business_formation_at": Schema.optionalKey(Schema.String.annotate({ "description": "Write-only ISO 8601 timestamp. For **EEA in-scope** businesses on **reliance**, may satisfy `BUSINESS_REGISTRY_CHECK_RELIANCE` together with good-standing/registry evidence (or use document purpose `business_formation`). See [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#evidence-of-good-standing).\n", "writeOnly": true, "format": "date-time" })), "verified_business_registry_at": Schema.optionalKey(Schema.String.annotate({ "description": "Write-only ISO 8601 timestamp. For **EEA in-scope** businesses on **reliance**, registry-side evidence for `BUSINESS_REGISTRY_CHECK_RELIANCE`. Use `verified_evidence_of_good_standing_at` when the artifact maps to purpose `evidence_of_good_standing`.\n", "writeOnly": true, "format": "date-time" })), "verified_evidence_of_good_standing_at": Schema.optionalKey(Schema.String.annotate({ "description": "Write-only ISO 8601 timestamp. For **EEA in-scope** businesses on **reliance**, evidence-of-good-standing path (`evidence_of_good_standing`) under `BUSINESS_REGISTRY_CHECK_RELIANCE`.\n", "writeOnly": true, "format": "date-time" })), "verified_ownership_at": Schema.optionalKey(Schema.String.annotate({ "description": "Write-only ISO 8601 timestamp. For **EEA in-scope** businesses on **reliance**, may satisfy `BUSINESS_OWNERSHIP_RELIANCE` (ownership / cap-table documentation). See [EEA updated requirements — ownership document](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#ownership-document-always-required).\n", "writeOnly": true, "format": "date-time" })), "regulated_activity": Schema.optionalKey(Schema.Struct({ "regulated_activities_description": Schema.String.annotate({ "description": "A detailed description of the regulated activities the business is licensed to conduct." }), "primary_regulatory_authority_country": Schema.String.annotate({ "description": "The ISO 3166-1 (three-character) country code." }), "primary_regulatory_authority_name": Schema.String.annotate({ "description": "The name of the primary regulatory authority that oversees the business's regulated activities." }), "license_number": Schema.String.annotate({ "description": "The license number or registration number assigned by the business's primary regulator." }) })), "acting_as_intermediary": Schema.optionalKey(Schema.Boolean.annotate({ "description": "Is the customer acting as an intermediary for a third party?\n\n_Required for high risk customers. More information found [here](https://apidocs.bridge.xyz/docs/business-accounts)_\n" })), "client_reference_id": Schema.optionalKey(Schema.String.annotate({ "description": "Caller-provided identifier used to correlate this customer with your internal records. Returned in API and webhook responses." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" }))) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "title": "Business Customer", "identifier": "CreateBusinessCustomerPayload" }) +export type UpdateIndividualCustomerPayload = { readonly "type"?: "individual", readonly "first_name"?: string, readonly "middle_name"?: string, readonly "last_name"?: string, readonly "transliterated_first_name"?: string, readonly "transliterated_middle_name"?: string, readonly "transliterated_last_name"?: string, readonly "email"?: string, readonly "phone"?: string, readonly "residential_address"?: { readonly "street_line_1": string, readonly "street_line_2"?: string, readonly "city": string, readonly "subdivision"?: string, readonly "postal_code"?: string, readonly "country": string } & { readonly [x: string]: Schema.Json }, readonly "transliterated_residential_address"?: { readonly "street_line_1": string, readonly "street_line_2"?: string, readonly "city": string, readonly "subdivision"?: string, readonly "postal_code"?: string, readonly "country": string } & { readonly [x: string]: Schema.Json }, readonly "birth_date"?: string, readonly "signed_agreement_id"?: string, readonly "endorsements"?: ReadonlyArray<"base" | "cards" | "cop" | "faster_payments" | "pix" | "pix_onramp" | "pix_offramp" | "sepa" | "spei">, readonly "account_purpose"?: "charitable_donations" | "ecommerce_retail_payments" | "investment_purposes" | "operating_a_company" | "other" | "payments_to_friends_or_family_abroad" | "personal_or_living_expenses" | "protect_wealth" | "purchase_goods_and_services" | "receive_payment_for_freelancing" | "receive_salary", readonly "account_purpose_other"?: string, readonly "employment_status"?: "employed" | "homemaker" | "retired" | "self_employed" | "student" | "unemployed", readonly "expected_monthly_payments_usd"?: "0_4999" | "5000_9999" | "10000_49999" | "50000_plus", readonly "acting_as_intermediary"?: boolean, readonly "most_recent_occupation"?: string, readonly "source_of_funds"?: "company_funds" | "ecommerce_reseller" | "gambling_proceeds" | "gifts" | "government_benefits" | "inheritance" | "investments_loans" | "pension_retirement" | "salary" | "sale_of_assets_real_estate" | "savings" | "someone_elses_funds", readonly "nationality"?: string, readonly "nationalities"?: ReadonlyArray, readonly "place_of_birth"?: { readonly "country"?: string, readonly "city"?: string }, readonly "verified_database_at"?: string, readonly "verified_govid_at"?: string, readonly "verified_selfie_at"?: string, readonly "liveness_check_selfies"?: ReadonlyArray<{ readonly "image": string }>, readonly "identifying_information"?: ReadonlyArray<{ readonly "type": "drivers_license" | "matriculate_id" | "military_id" | "national_id" | "passport" | "permanent_residency_id" | "state_or_provincial_id" | "visa" | "abn" | "acn" | "ahv" | "ak" | "aom" | "arbn" | "avs" | "bc" | "bce" | "bin" | "bir" | "bp" | "brn" | "bsn" | "bvn" | "cc" | "cdi" | "cedula_juridica" | "cf" | "cif" | "cin" | "cipc" | "cn" | "cnp" | "cnpj" | "cpf" | "cpr" | "crc" | "crib" | "crn" | "cro" | "cui" | "cuil" | "curp" | "cuit" | "cvr" | "edrpou" | "ein" | "embg" | "emirates_id" | "en" | "fin" | "fn" | "gstin" | "gui" | "hetu" | "hkid" | "hn" | "ic" | "ico" | "id" | "id_broj" | "idno" | "idnp" | "idnr" | "if" | "iin" | "ik" | "inn" | "ird" | "itin" | "itr" | "iva" | "jmbg" | "kbo" | "kvk" | "matricule" | "mf" | "mn" | "ms" | "mst" | "nic" | "nicn" | "nie" | "nif" | "nin" | "nino" | "nip" | "nipc" | "nipt" | "nit" | "npwp" | "nric" | "nrn" | "nrt" | "ntn" | "nuit" | "nzbn" | "oib" | "orgnr" | "other" | "pan" | "partita_iva" | "pesel" | "pib" | "pin" | "pk" | "ppsn" | "qid" | "rc" | "regon" | "rfc" | "ricn" | "rif" | "rn" | "rnc" | "rnokpp" | "rp" | "rrn" | "rtn" | "ruc" | "rut" | "si" | "sin" | "siren" | "siret" | "spi" | "ssm" | "ssn" | "steuer_id" | "strn" | "tckn" | "tfn" | "tin" | "tpin" | "trn" | "ucn" | "uen" | "uic" | "uid" | "usc" | "ust_idnr" | "utr" | "vat" | "vkn" | "voen" | "y_tunnus", readonly "issuing_country": string, readonly "number"?: string, readonly "description"?: string, readonly "expiration"?: string, readonly "image_front"?: string, readonly "image_back"?: string }>, readonly "documents"?: ReadonlyArray<{ readonly "purposes": ReadonlyArray<"proof_of_account_purpose" | "proof_of_address" | "proof_of_individual_name_change" | "proof_of_relationship" | "proof_of_source_of_funds" | "proof_of_source_of_wealth" | "proof_of_tax_identification" | "other">, readonly "file": string, readonly "description"?: string }>, readonly "client_reference_id"?: string } & { readonly [x: string]: Schema.Json } +export const UpdateIndividualCustomerPayload = Schema.StructWithRest(Schema.Struct({ "type": Schema.optionalKey(Schema.Literal("individual").annotate({ "description": "Type of the customer (individual vs. business)." })), "first_name": Schema.optionalKey(Schema.String.annotate({ "description": "The first name of the individual." }).check(Schema.isMinLength(2).annotate({ "expected": "a value with a length of at least 2" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" }))), "middle_name": Schema.optionalKey(Schema.String.annotate({ "description": "The middle name of the individual." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" }))), "last_name": Schema.optionalKey(Schema.String.annotate({ "description": "The last name of the individual." }).check(Schema.isMinLength(2).annotate({ "expected": "a value with a length of at least 2" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" }))), "transliterated_first_name": Schema.optionalKey(Schema.String.annotate({ "description": "Required when the `first_name` includes any non Latin-1 characters. Acceptable characters - Latin-1 Unicode Character Range: À-ÖØ-ßà-öø-ÿ; Standard Unicode Character Range: -~" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" }))), "transliterated_middle_name": Schema.optionalKey(Schema.String.annotate({ "description": "Required when the `middle_name` includes any non Latin-1 characters. Acceptable characters - Latin-1 Unicode Character Range: À-ÖØ-ßà-öø-ÿ; Standard Unicode Character Range: -~" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" }))), "transliterated_last_name": Schema.optionalKey(Schema.String.annotate({ "description": "Required when the `last_name` includes any non Latin-1 characters. Acceptable characters - Latin-1 Unicode Character Range: À-ÖØ-ßà-öø-ÿ; Standard Unicode Character Range: -~" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" }))), "email": Schema.optionalKey(Schema.String.annotate({ "description": "The individuals primary email address" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" }))), "phone": Schema.optionalKey(Schema.String.annotate({ "description": "The individuals primary phone number in format \"+12223334444\"" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" }))), "residential_address": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "street_line_1": Schema.String.check(Schema.isMinLength(4).annotate({ "expected": "a value with a length of at least 4" })), "street_line_2": Schema.optionalKey(Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "city": Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "subdivision": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-2 subdivision code. Must be supplied for US addresses." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))), "postal_code": Schema.optionalKey(Schema.String.annotate({ "description": "Must be supplied for countries that use postal codes." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "country": Schema.String.annotate({ "description": "Three-letter alpha-3 country code as defined in the ISO 3166-1 spec." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "The residential address of the individual. This must be a physical address, not a PO Box.", "writeOnly": true })), "transliterated_residential_address": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "street_line_1": Schema.String.check(Schema.isMinLength(4).annotate({ "expected": "a value with a length of at least 4" })), "street_line_2": Schema.optionalKey(Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "city": Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "subdivision": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-2 subdivision code. Must be supplied for US addresses." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))), "postal_code": Schema.optionalKey(Schema.String.annotate({ "description": "Must be supplied for countries that use postal codes." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "country": Schema.String.annotate({ "description": "Three-letter alpha-3 country code as defined in the ISO 3166-1 spec." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Required when any part of the `residential_address` includes any non Latin-1 characters. Acceptable characters - Latin-1 Unicode Character Range: À-ÖØ-ßà-öø-ÿ; Standard Unicode Character Range: -~", "writeOnly": true })), "birth_date": Schema.optionalKey(Schema.String.annotate({ "description": "Date of birth in format yyyy-mm-dd. Must be at least 18 years old." }).check(Schema.isMinLength(10).annotate({ "expected": "a value with a length of at least 10" })).check(Schema.isMaxLength(10).annotate({ "expected": "a value with a length of at most 10" }))), "signed_agreement_id": Schema.optionalKey(Schema.String.annotate({ "description": "The ID of the signed agreement that the customer completed. You can get a signed agreement id for a _new_ customer by following this guide [here](https://apidocs.bridge.xyz/docs/terms-of-service#tos-acceptance-for-a-new-customer).\n", "writeOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" }))), "endorsements": Schema.optionalKey(Schema.Array(Schema.Literals(["base", "cards", "cop", "faster_payments", "pix", "pix_onramp", "pix_offramp", "sepa", "spei"]).annotate({ "description": "The type of endorsement. Note: `pix_onramp` (BRL deposits via PIX) and `pix_offramp` (BRL withdrawals via PIX) can be requested individually for granular access. Requesting `pix` grants both directional endorsements. `pix_onramp` is not supported for non-BR individuals; if requested (or requested via `pix`) it will remain in an `endorsement_not_available_in_customers_region` state and no action is required.\n" })).annotate({ "description": "List of endorsements to request for this customer. If omitted, we'll attempt to grant `base` and `sepa`.\n", "writeOnly": true })), "account_purpose": Schema.optionalKey(Schema.Literals(["charitable_donations", "ecommerce_retail_payments", "investment_purposes", "operating_a_company", "other", "payments_to_friends_or_family_abroad", "personal_or_living_expenses", "protect_wealth", "purchase_goods_and_services", "receive_payment_for_freelancing", "receive_salary"]).annotate({ "description": "What is the primary purpose of the customer's account?\n\n_Required for high risk customers. More information found [here](https://apidocs.bridge.xyz/docs/individuals)._\n\n**EEA / BBSA in-scope individuals:** also required under program rules (not for associated persons). See [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#account-purpose-and-employment-status).\n" })), "account_purpose_other": Schema.optionalKey(Schema.String.annotate({ "description": "A supplemental description of the `account_purpose`.\n\n_Required if the `account_purpose` is `other`._\n" })), "employment_status": Schema.optionalKey(Schema.Literals(["employed", "homemaker", "retired", "self_employed", "student", "unemployed"]).annotate({ "description": "What is the customer's current employment status?\n\n_Required for high risk customers. More information found [here](https://apidocs.bridge.xyz/docs/individuals)._\n\n**EEA / BBSA in-scope individuals:** also required under program rules (not for associated persons). See [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#account-purpose-and-employment-status).\n" })), "expected_monthly_payments_usd": Schema.optionalKey(Schema.Literals(["0_4999", "5000_9999", "10000_49999", "50000_plus"]).annotate({ "description": "What is the expected monthly volume of payments the customer will be sending or receiving?\n\n_Required for high risk customers. More information found [here](https://apidocs.bridge.xyz/docs/individuals)_\n" })), "acting_as_intermediary": Schema.optionalKey(Schema.Boolean.annotate({ "description": "Is the customer acting as an intermediary for a third party?\n\n_Required for high risk customers. More information found [here](https://apidocs.bridge.xyz/docs/individuals)_\n" })), "most_recent_occupation": Schema.optionalKey(Schema.String.annotate({ "description": "What is the customer's most recent occupation? Specify the relevant alphanumeric occupation code. See the [list of occupations](https://apidocs.bridge.xyz/page/sof-eu-most-recent-occupation-list) for the complete list of valid occupations and codes. _Required for Restricted countries._\n\n_Required for high risk customers. More information found [here](https://apidocs.bridge.xyz/docs/individuals)_\n" })), "source_of_funds": Schema.optionalKey(Schema.Literals(["company_funds", "ecommerce_reseller", "gambling_proceeds", "gifts", "government_benefits", "inheritance", "investments_loans", "pension_retirement", "salary", "sale_of_assets_real_estate", "savings", "someone_elses_funds"]).annotate({ "description": "The individuals source of funds, e.g. government_benefits, investments_loans, salary, etc.\n\n_Required for high risk customers. More information found [here](https://apidocs.bridge.xyz/docs/individuals)_\n" })), "nationality": Schema.optionalKey(Schema.String.annotate({ "description": "Legacy single nationality as ISO 3166-1 alpha-3. Prefer `nationalities` to send **all** nationalities. During migration Bridge honors either field; `nationality` will be deprecated after migration. **EEA / BBSA program:** see [Nationalities](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#nationalities).\n", "writeOnly": true })), "nationalities": Schema.optionalKey(Schema.Array(Schema.String.check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))).annotate({ "description": "All nationalities held by the customer (ISO 3166-1 alpha-3 codes). **EEA / BBSA in-scope individuals:** required. See [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#nationalities).\n", "writeOnly": true })), "place_of_birth": Schema.optionalKey(Schema.Struct({ "country": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-1 alpha-3 country code for the place of birth." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))), "city": Schema.optionalKey(Schema.String.annotate({ "description": "City of birth (recommended for EEA)." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))) }).annotate({ "description": "Country (and optionally city) of birth. **EEA / BBSA in-scope customers:** supply when onboarding individuals or associated persons under the [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#country-of-birth-and-city-of-birth). This is a sparse address — no street address. At least `country` should be present when the object is sent; `city` is recommended and will be required by EU law in 2027.\n", "writeOnly": true })), "verified_database_at": Schema.optionalKey(Schema.String.annotate({ "description": "Write-only ISO 8601 timestamp. For **EEA in-scope** customers on **reliance** (`TWO_FORMS_OF_ID_RELIANCE` in `eea_requirements.rb`), may stand in for a database identity check together with `verified_govid_at`. See [EEA updated requirements — identity](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements).\n", "writeOnly": true, "format": "date-time" })), "verified_govid_at": Schema.optionalKey(Schema.String.annotate({ "description": "Write-only ISO 8601 timestamp. For **EEA in-scope** customers on **reliance**, use with a second factor (`verified_selfie_at` or `verified_database_at`) per `TWO_FORMS_OF_ID_RELIANCE`. See [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements).\n", "writeOnly": true, "format": "date-time" })), "verified_selfie_at": Schema.optionalKey(Schema.String.annotate({ "description": "Write-only ISO 8601 timestamp. For **EEA in-scope** customers on **reliance**, pairs with `verified_govid_at` or `verified_database_at` under `TWO_FORMS_OF_ID_RELIANCE`.\n", "writeOnly": true, "format": "date-time" })), "liveness_check_selfies": Schema.optionalKey(Schema.Array(Schema.Struct({ "image": Schema.String.annotate({ "description": "Base64 encoded image* of the selfie, following the data-uri scheme i.e. data:image/[type];base64,[base_64_encoded_file_contents], with a minimum size of 200px x 200px \n\n*Maximum File Size: 15MB\n\n*Valid file types: .jpeg, .jpg, .png, .heic, .heif, .tif, .tiff" }) })).annotate({ "description": "Selfie images to submit for Bridge's liveness verification. Use this when you are collecting the customer's selfie on behalf of Bridge.\n\n**EEA in-scope** customers: selfies submitted via this field are not sufficient. The selfie must be collected through the Persona hosted flow (via a KYC link). See [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements).\n", "writeOnly": true })), "identifying_information": Schema.optionalKey(Schema.Array(Schema.Struct({ "type": Schema.Literals(["drivers_license", "matriculate_id", "military_id", "national_id", "passport", "permanent_residency_id", "state_or_provincial_id", "visa", "abn", "acn", "ahv", "ak", "aom", "arbn", "avs", "bc", "bce", "bin", "bir", "bp", "brn", "bsn", "bvn", "cc", "cdi", "cedula_juridica", "cf", "cif", "cin", "cipc", "cn", "cnp", "cnpj", "cpf", "cpr", "crc", "crib", "crn", "cro", "cui", "cuil", "curp", "cuit", "cvr", "edrpou", "ein", "embg", "emirates_id", "en", "fin", "fn", "gstin", "gui", "hetu", "hkid", "hn", "ic", "ico", "id", "id_broj", "idno", "idnp", "idnr", "if", "iin", "ik", "inn", "ird", "itin", "itr", "iva", "jmbg", "kbo", "kvk", "matricule", "mf", "mn", "ms", "mst", "nic", "nicn", "nie", "nif", "nin", "nino", "nip", "nipc", "nipt", "nit", "npwp", "nric", "nrn", "nrt", "ntn", "nuit", "nzbn", "oib", "orgnr", "other", "pan", "partita_iva", "pesel", "pib", "pin", "pk", "ppsn", "qid", "rc", "regon", "rfc", "ricn", "rif", "rn", "rnc", "rnokpp", "rp", "rrn", "rtn", "ruc", "rut", "si", "sin", "siren", "siret", "spi", "ssm", "ssn", "steuer_id", "strn", "tckn", "tfn", "tin", "tpin", "trn", "ucn", "uen", "uic", "uid", "usc", "ust_idnr", "utr", "vat", "vkn", "voen", "y_tunnus"]).annotate({ "description": "Tax identification number type or government-issued ID document type (see enum). Country-specific tax and national ID lists: [Individuals](https://apidocs.bridge.xyz/docs/individual-tax-identification-numbers-by-country), [Businesses](https://apidocs.bridge.xyz/docs/business-tax-identification-numbers-by-country).\n\n**EEA / BBSA (policy in `eea_requirements.rb`):** In-scope individuals and UBOs need **both** a valid national-ID-type entry and a valid TIN per [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements). In-scope businesses need business registration **and** business tax ID types per country tables there. **TIN issuing country** must match residence (individuals) or incorporation (businesses). **Foreign tax** outside the incorporation country: set `has_foreign_tax_registration` on the business customer and add TIN objects per jurisdiction ([foreign tax / tax residency](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#tax-residency-status-foreign-tax-registry)).\n" }), "issuing_country": Schema.String.annotate({ "description": "The ISO 3166-1 (three-character) country code that issued the provided document." }), "number": Schema.optionalKey(Schema.String.annotate({ "description": "The unique identifier of the document. Required if this document is being used as a tax identification number (e.g., you are providing a passport or national_id with no other identification)." })), "description": Schema.optionalKey(Schema.String.annotate({ "description": "A description describing the provided document. This field is required when `other` is selected." })), "expiration": Schema.optionalKey(Schema.String.annotate({ "description": "The expiration date of the given document in yyyy-mm-dd format." })), "image_front": Schema.optionalKey(Schema.String.annotate({ "description": "This field is optionally accepted for tax_id types, but required for government_id types. Base64 encoded image* of the front side of the provided document, following the data-uri scheme i.e. data:image/[type];base64,[base_64_encoded_file_contents], with a minimum size of 200px x 200px \\n\\n*Maximum File Size: 15MB\\n\\n*Valid file types: .pdf, .jpeg, .jpg, .png, .heic, .tif\n\n_Note: When combined with an `image_back`, the combined size of both images must not exceed 24MB._\n" })), "image_back": Schema.optionalKey(Schema.String.annotate({ "description": "Base64 encoded image* of the back side of the provided document, following the data-uri scheme i.e. data:image/[type];base64,[base_64_encoded_file_contents], with a minimum size of 200px x 200px \\n\\n*Maximum File Size: 15MB\\n\\n*Valid file types: .pdf, .jpeg, .jpg, .png, .heic, .tif\n\n_Note: When combined with an `image_front`, the combined size of both images must not exceed 24MB._\n" })) })).annotate({ "title": "Identification Information", "writeOnly": true })), "documents": Schema.optionalKey(Schema.Array(Schema.Struct({ "purposes": Schema.Array(Schema.Literals(["proof_of_account_purpose", "proof_of_address", "proof_of_individual_name_change", "proof_of_relationship", "proof_of_source_of_funds", "proof_of_source_of_wealth", "proof_of_tax_identification", "other"])).annotate({ "description": "A list of purposes that the given document serves. Click \"ADD STRING\" to see common document purposes for individuals, or view the full list of possible values [here](https://apidocs.bridge.xyz/docs/supported-documents)." }), "file": Schema.String.annotate({ "description": "Base64 encoded image* of the provided document, following the data-uri scheme i.e. data:image/[type];base64,[base_64_encoded_file_contents], with a minimum size of 200px x 200px \n\n*Maximum File Size: 24MB\n\n*Valid file types: .pdf, .jpeg, .jpg, .png, .heic, .tif" }), "description": Schema.optionalKey(Schema.String.annotate({ "description": "A description describing the provided document. This field is required when `other` is provided as one of the purposes." })) })).annotate({ "title": "Documents", "description": "Please click \"ADD OBJECT\" for more information.", "writeOnly": true })), "client_reference_id": Schema.optionalKey(Schema.String.annotate({ "description": "Caller-provided identifier used to correlate this customer with your internal records. Returned in API and webhook responses." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" }))) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "title": "Individual Customer", "identifier": "UpdateIndividualCustomerPayload" }) +export type UpdateBusinessCustomerPayload = { readonly "type"?: "business", readonly "business_legal_name"?: string, readonly "transliterated_business_legal_name"?: string, readonly "business_trade_name"?: string, readonly "transliterated_business_trade_name"?: string, readonly "business_description"?: string, readonly "has_foreign_tax_registration"?: boolean, readonly "email"?: string, readonly "phone"?: string, readonly "business_type"?: "cooperative" | "corporation" | "llc" | "other" | "partnership" | "sole_prop" | "trust", readonly "primary_website"?: string, readonly "other_websites"?: ReadonlyArray, readonly "registered_address"?: { readonly "street_line_1": string, readonly "street_line_2"?: string, readonly "city": string, readonly "subdivision"?: string, readonly "postal_code"?: string, readonly "country": string } & { readonly [x: string]: Schema.Json }, readonly "transliterated_registered_address"?: { readonly "street_line_1": string, readonly "street_line_2"?: string, readonly "city": string, readonly "subdivision"?: string, readonly "postal_code"?: string, readonly "country": string } & { readonly [x: string]: Schema.Json }, readonly "physical_address"?: { readonly "street_line_1": string, readonly "street_line_2"?: string, readonly "city": string, readonly "subdivision"?: string, readonly "postal_code"?: string, readonly "country": string } & { readonly [x: string]: Schema.Json }, readonly "transliterated_physical_address"?: { readonly "street_line_1": string, readonly "street_line_2"?: string, readonly "city": string, readonly "subdivision"?: string, readonly "postal_code"?: string, readonly "country": string } & { readonly [x: string]: Schema.Json }, readonly "signed_agreement_id"?: string, readonly "is_dao"?: boolean, readonly "compliance_screening_explanation"?: string, readonly "associated_persons"?: ReadonlyArray<{ readonly "first_name": string, readonly "middle_name"?: string, readonly "last_name": string, readonly "transliterated_first_name"?: string, readonly "transliterated_middle_name"?: string, readonly "transliterated_last_name"?: string, readonly "email": string, readonly "phone"?: string, readonly "residential_address": { readonly "street_line_1": string, readonly "street_line_2"?: string, readonly "city": string, readonly "subdivision"?: string, readonly "postal_code"?: string, readonly "country": string } & { readonly [x: string]: Schema.Json }, readonly "transliterated_residential_address"?: { readonly "street_line_1": string, readonly "street_line_2"?: string, readonly "city": string, readonly "subdivision"?: string, readonly "postal_code"?: string, readonly "country": string } & { readonly [x: string]: Schema.Json }, readonly "birth_date": string, readonly "nationality"?: string, readonly "nationalities"?: ReadonlyArray, readonly "place_of_birth"?: { readonly "country"?: string, readonly "city"?: string }, readonly "verified_database_at"?: string, readonly "has_ownership": boolean, readonly "has_control": boolean, readonly "is_signer": boolean, readonly "is_director"?: boolean, readonly "title"?: string, readonly "ownership_percentage"?: number, readonly "attested_ownership_structure_at"?: string, readonly "verified_account_authorization_at"?: string, readonly "relationship_established_at"?: string, readonly "verified_govid_at"?: string, readonly "verified_selfie_at"?: string, readonly "identifying_information": ReadonlyArray<{ readonly "type": "drivers_license" | "matriculate_id" | "military_id" | "national_id" | "passport" | "permanent_residency_id" | "state_or_provincial_id" | "visa" | "abn" | "acn" | "ahv" | "ak" | "aom" | "arbn" | "avs" | "bc" | "bce" | "bin" | "bir" | "bp" | "brn" | "bsn" | "bvn" | "cc" | "cdi" | "cedula_juridica" | "cf" | "cif" | "cin" | "cipc" | "cn" | "cnp" | "cnpj" | "cpf" | "cpr" | "crc" | "crib" | "crn" | "cro" | "cui" | "cuil" | "curp" | "cuit" | "cvr" | "edrpou" | "ein" | "embg" | "emirates_id" | "en" | "fin" | "fn" | "gstin" | "gui" | "hetu" | "hkid" | "hn" | "ic" | "ico" | "id" | "id_broj" | "idno" | "idnp" | "idnr" | "if" | "iin" | "ik" | "inn" | "ird" | "itin" | "itr" | "iva" | "jmbg" | "kbo" | "kvk" | "matricule" | "mf" | "mn" | "ms" | "mst" | "nic" | "nicn" | "nie" | "nif" | "nin" | "nino" | "nip" | "nipc" | "nipt" | "nit" | "npwp" | "nric" | "nrn" | "nrt" | "ntn" | "nuit" | "nzbn" | "oib" | "orgnr" | "other" | "pan" | "partita_iva" | "pesel" | "pib" | "pin" | "pk" | "ppsn" | "qid" | "rc" | "regon" | "rfc" | "ricn" | "rif" | "rn" | "rnc" | "rnokpp" | "rp" | "rrn" | "rtn" | "ruc" | "rut" | "si" | "sin" | "siren" | "siret" | "spi" | "ssm" | "ssn" | "steuer_id" | "strn" | "tckn" | "tfn" | "tin" | "tpin" | "trn" | "ucn" | "uen" | "uic" | "uid" | "usc" | "ust_idnr" | "utr" | "vat" | "vkn" | "voen" | "y_tunnus", readonly "issuing_country": string, readonly "number"?: string, readonly "description"?: string, readonly "expiration"?: string, readonly "image_front"?: string, readonly "image_back"?: string }>, readonly "documents"?: ReadonlyArray<{ readonly "purposes": ReadonlyArray<"proof_of_account_purpose" | "proof_of_address" | "proof_of_individual_name_change" | "proof_of_relationship" | "proof_of_source_of_funds" | "proof_of_source_of_wealth" | "proof_of_tax_identification" | "other">, readonly "file": string, readonly "description"?: string }> } & { readonly [x: string]: Schema.Json }>, readonly "endorsements"?: ReadonlyArray<"base" | "cards" | "cop" | "faster_payments" | "pix" | "pix_onramp" | "pix_offramp" | "sepa" | "spei">, readonly "business_industry"?: ReadonlyArray, readonly "publicly_traded_listings"?: ReadonlyArray<{ readonly "market_identifier_code": string, readonly "stock_number": string, readonly "ticker": string }>, readonly "ownership_threshold"?: number, readonly "has_material_intermediary_ownership"?: boolean, readonly "estimated_annual_revenue_usd"?: "0_99999" | "100000_999999" | "1000000_9999999" | "10000000_49999999" | "50000000_249999999" | "250000000_plus", readonly "expected_monthly_payments_usd"?: number, readonly "expected_monthly_swift_transaction_volume"?: number, readonly "operates_in_prohibited_countries"?: boolean, readonly "account_purpose"?: "charitable_donations" | "ecommerce_retail_payments" | "investment_purposes" | "other" | "payments_to_friends_or_family_abroad" | "payroll" | "personal_or_living_expenses" | "protect_wealth" | "purchase_goods_and_services" | "receive_payments_for_goods_and_services" | "tax_optimization" | "third_party_money_transmission" | "treasury_management", readonly "account_purpose_other"?: string, readonly "high_risk_activities_explanation"?: string, readonly "high_risk_activities"?: ReadonlyArray<"adult_entertainment" | "gambling" | "hold_client_funds" | "investment_services" | "lending_banking" | "marijuana_or_related_services" | "money_services" | "nicotine_tobacco_or_related_services" | "operate_foreign_exchange_virtual_currencies_brokerage_otc" | "pharmaceuticals" | "precious_metals_precious_stones_jewelry" | "safe_deposit_box_rentals" | "third_party_payment_processing" | "weapons_firearms_and_explosives" | "none_of_the_above">, readonly "source_of_funds"?: "business_loans" | "grants" | "inter_company_funds" | "investment_proceeds" | "legal_settlement" | "owners_capital" | "pension_retirement" | "sale_of_assets" | "sales_of_goods_and_services" | "third_party_funds" | "treasury_reserves", readonly "source_of_funds_description"?: string, readonly "conducts_money_services"?: boolean, readonly "conducts_money_services_using_bridge"?: boolean, readonly "conducts_money_services_description"?: string, readonly "identifying_information"?: ReadonlyArray<{ readonly "type": "drivers_license" | "matriculate_id" | "military_id" | "national_id" | "passport" | "permanent_residency_id" | "state_or_provincial_id" | "visa" | "abn" | "acn" | "ahv" | "ak" | "aom" | "arbn" | "avs" | "bc" | "bce" | "bin" | "bir" | "bp" | "brn" | "bsn" | "bvn" | "cc" | "cdi" | "cedula_juridica" | "cf" | "cif" | "cin" | "cipc" | "cn" | "cnp" | "cnpj" | "cpf" | "cpr" | "crc" | "crib" | "crn" | "cro" | "cui" | "cuil" | "curp" | "cuit" | "cvr" | "edrpou" | "ein" | "embg" | "emirates_id" | "en" | "fin" | "fn" | "gstin" | "gui" | "hetu" | "hkid" | "hn" | "ic" | "ico" | "id" | "id_broj" | "idno" | "idnp" | "idnr" | "if" | "iin" | "ik" | "inn" | "ird" | "itin" | "itr" | "iva" | "jmbg" | "kbo" | "kvk" | "matricule" | "mf" | "mn" | "ms" | "mst" | "nic" | "nicn" | "nie" | "nif" | "nin" | "nino" | "nip" | "nipc" | "nipt" | "nit" | "npwp" | "nric" | "nrn" | "nrt" | "ntn" | "nuit" | "nzbn" | "oib" | "orgnr" | "other" | "pan" | "partita_iva" | "pesel" | "pib" | "pin" | "pk" | "ppsn" | "qid" | "rc" | "regon" | "rfc" | "ricn" | "rif" | "rn" | "rnc" | "rnokpp" | "rp" | "rrn" | "rtn" | "ruc" | "rut" | "si" | "sin" | "siren" | "siret" | "spi" | "ssm" | "ssn" | "steuer_id" | "strn" | "tckn" | "tfn" | "tin" | "tpin" | "trn" | "ucn" | "uen" | "uic" | "uid" | "usc" | "ust_idnr" | "utr" | "vat" | "vkn" | "voen" | "y_tunnus", readonly "issuing_country": string, readonly "number"?: string, readonly "description"?: string, readonly "expiration"?: string, readonly "image_front"?: string, readonly "image_back"?: string }>, readonly "documents"?: ReadonlyArray<{ readonly "purposes": ReadonlyArray<"aml_comfort_letter" | "business_formation" | "directors_registry" | "e_signature_certificate" | "evidence_of_good_standing" | "flow_of_funds" | "marketing_materials" | "ownership_chart" | "ownership_information" | "proof_of_account_purpose" | "proof_of_address" | "proof_of_entity_name_change" | "proof_of_nature_of_business" | "proof_of_signatory_authority" | "proof_of_source_of_funds" | "proof_of_source_of_wealth" | "proof_of_tax_identification" | "shareholder_register" | "other">, readonly "file": string, readonly "description"?: string }>, readonly "incorporation_date"?: string, readonly "verified_business_formation_at"?: string, readonly "verified_business_registry_at"?: string, readonly "verified_evidence_of_good_standing_at"?: string, readonly "verified_ownership_at"?: string, readonly "regulated_activity"?: { readonly "regulated_activities_description": string, readonly "primary_regulatory_authority_country": string, readonly "primary_regulatory_authority_name": string, readonly "license_number": string }, readonly "acting_as_intermediary"?: boolean, readonly "client_reference_id"?: string } & { readonly [x: string]: Schema.Json } +export const UpdateBusinessCustomerPayload = Schema.StructWithRest(Schema.Struct({ "type": Schema.optionalKey(Schema.Literal("business").annotate({ "description": "Type of the customer (individual vs. business)" })), "business_legal_name": Schema.optionalKey(Schema.String.annotate({ "description": "The official registered name of the business as documented with government authorities." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" }))), "transliterated_business_legal_name": Schema.optionalKey(Schema.String.annotate({ "description": "Required if `business_legal_name` includes any non Latin-1 characters. Acceptable characters - Latin-1 Unicode Character Range: À-ÖØ-ßà-öø-ÿ; Standard Unicode Character Range: -~" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" }))), "business_trade_name": Schema.optionalKey(Schema.String.annotate({ "description": "The trading name or DBA (Doing Business As) name under which the business operates publicly." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" }))), "transliterated_business_trade_name": Schema.optionalKey(Schema.String.annotate({ "description": "Required if `business_trade` includes any non Latin-1 characters. Acceptable characters - Latin-1 Unicode Character Range: À-ÖØ-ßà-öø-ÿ; Standard Unicode Character Range: -~" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" }))), "business_description": Schema.optionalKey(Schema.String.annotate({ "description": "A brief summary of the business" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" }))), "has_foreign_tax_registration": Schema.optionalKey(Schema.Boolean.annotate({ "description": "Whether the business is registered for tax in any jurisdiction **outside** its country of incorporation. When `true`, provide additional tax identifiers in `identifying_information` whose `issuing_country` reflects each foreign registration, per [EEA tax residency](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#tax-residency-status-foreign-tax-registry).\n" })), "email": Schema.optionalKey(Schema.String.annotate({ "description": "The business's primary email address" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" }))), "phone": Schema.optionalKey(Schema.String.annotate({ "description": "The business's primary phone number in format \"+12223334444\"" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" }))), "business_type": Schema.optionalKey(Schema.Literals(["cooperative", "corporation", "llc", "other", "partnership", "sole_prop", "trust"]).annotate({ "description": "How the business is legally registered" })), "primary_website": Schema.optionalKey(Schema.String.annotate({ "description": "The business's primary website/web presence. A document with purpose 'proof_of_nature_of_business' is required if this is not provided" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" }))), "other_websites": Schema.optionalKey(Schema.Array(Schema.String).annotate({ "description": "The business's other websites and social media handles" })), "registered_address": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "street_line_1": Schema.String.check(Schema.isMinLength(4).annotate({ "expected": "a value with a length of at least 4" })), "street_line_2": Schema.optionalKey(Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "city": Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "subdivision": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-2 subdivision code. Must be supplied for US addresses." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))), "postal_code": Schema.optionalKey(Schema.String.annotate({ "description": "Must be supplied for countries that use postal codes." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "country": Schema.String.annotate({ "description": "Three-letter alpha-3 country code as defined in the ISO 3166-1 spec." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "The official registered address of the business.", "writeOnly": true })), "transliterated_registered_address": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "street_line_1": Schema.String.check(Schema.isMinLength(4).annotate({ "expected": "a value with a length of at least 4" })), "street_line_2": Schema.optionalKey(Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "city": Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "subdivision": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-2 subdivision code. Must be supplied for US addresses." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))), "postal_code": Schema.optionalKey(Schema.String.annotate({ "description": "Must be supplied for countries that use postal codes." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "country": Schema.String.annotate({ "description": "Three-letter alpha-3 country code as defined in the ISO 3166-1 spec." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Required if any part of the `registered_address` includes any non Latin-1 characters. Acceptable characters - Latin-1 Unicode Character Range: À-ÖØ-ßà-öø-ÿ; Standard Unicode Character Range: -~", "writeOnly": true })), "physical_address": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "street_line_1": Schema.String.check(Schema.isMinLength(4).annotate({ "expected": "a value with a length of at least 4" })), "street_line_2": Schema.optionalKey(Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "city": Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "subdivision": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-2 subdivision code. Must be supplied for US addresses." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))), "postal_code": Schema.optionalKey(Schema.String.annotate({ "description": "Must be supplied for countries that use postal codes." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "country": Schema.String.annotate({ "description": "Three-letter alpha-3 country code as defined in the ISO 3166-1 spec." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "The physical address for the primary place of business. This must be a physical address and cannot be a PO Box.", "writeOnly": true })), "transliterated_physical_address": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "street_line_1": Schema.String.check(Schema.isMinLength(4).annotate({ "expected": "a value with a length of at least 4" })), "street_line_2": Schema.optionalKey(Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "city": Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "subdivision": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-2 subdivision code. Must be supplied for US addresses." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))), "postal_code": Schema.optionalKey(Schema.String.annotate({ "description": "Must be supplied for countries that use postal codes." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "country": Schema.String.annotate({ "description": "Three-letter alpha-3 country code as defined in the ISO 3166-1 spec." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Required if any part of the `physical_address` includes any non Latin-1 characters. Acceptable characters - Latin-1 Unicode Character Range: À-ÖØ-ßà-öø-ÿ; Standard Unicode Character Range: -~", "writeOnly": true })), "signed_agreement_id": Schema.optionalKey(Schema.String.annotate({ "description": "The ID of the signed agreement that the customer completed. You can get a signed agreement id for a _new_ customer by following [this guide](https://apidocs.bridge.xyz/docs/terms-of-service#tos-acceptance-for-a-new-customer).\n", "writeOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" }))), "is_dao": Schema.optionalKey(Schema.Boolean.annotate({ "description": "Whether the business is a DAO (Decentralized Autonomous Organization)" })), "compliance_screening_explanation": Schema.optionalKey(Schema.String.annotate({ "description": "Required if `conducts_money_services` is true. A detailed description of the business's compliance and anti-money laundering controls and practices." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" }))), "associated_persons": Schema.optionalKey(Schema.Array(Schema.StructWithRest(Schema.Struct({ "first_name": Schema.String.annotate({ "description": "The first name of the associated person" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" })), "middle_name": Schema.optionalKey(Schema.String.annotate({ "description": "The middle name of the associated person" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" }))), "last_name": Schema.String.annotate({ "description": "The last name of the associated person" }).check(Schema.isMinLength(2).annotate({ "expected": "a value with a length of at least 2" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" })), "transliterated_first_name": Schema.optionalKey(Schema.String.annotate({ "description": "Required when the `first_name` includes any non Latin-1 characters. Acceptable characters - Latin-1 Unicode Character Range: À-ÖØ-ßà-öø-ÿ; Standard Unicode Character Range: -~" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" }))), "transliterated_middle_name": Schema.optionalKey(Schema.String.annotate({ "description": "Required when the `middle_name` includes any non Latin-1 characters. Acceptable characters - Latin-1 Unicode Character Range: À-ÖØ-ßà-öø-ÿ; Standard Unicode Character Range: -~" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" }))), "transliterated_last_name": Schema.optionalKey(Schema.String.annotate({ "description": "Required when the `last_name` includes any non Latin-1 characters. Acceptable characters - Latin-1 Unicode Character Range: À-ÖØ-ßà-öø-ÿ; Standard Unicode Character Range: -~" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" }))), "email": Schema.String.annotate({ "description": "The persons primary email address" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" })), "phone": Schema.optionalKey(Schema.String.annotate({ "description": "The persons phone in format \"+12223334444\"" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" }))), "residential_address": Schema.StructWithRest(Schema.Struct({ "street_line_1": Schema.String.check(Schema.isMinLength(4).annotate({ "expected": "a value with a length of at least 4" })), "street_line_2": Schema.optionalKey(Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "city": Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "subdivision": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-2 subdivision code. Must be supplied for US addresses." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))), "postal_code": Schema.optionalKey(Schema.String.annotate({ "description": "Must be supplied for countries that use postal codes." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "country": Schema.String.annotate({ "description": "Three-letter alpha-3 country code as defined in the ISO 3166-1 spec." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "The residential address of the associated person. This must be a physical address and cannot be a PO Box.", "writeOnly": true }), "transliterated_residential_address": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "street_line_1": Schema.String.check(Schema.isMinLength(4).annotate({ "expected": "a value with a length of at least 4" })), "street_line_2": Schema.optionalKey(Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "city": Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "subdivision": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-2 subdivision code. Must be supplied for US addresses." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))), "postal_code": Schema.optionalKey(Schema.String.annotate({ "description": "Must be supplied for countries that use postal codes." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "country": Schema.String.annotate({ "description": "Three-letter alpha-3 country code as defined in the ISO 3166-1 spec." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Required when any part of the `residential_address` includes any non Latin-1 characters. Acceptable characters - Latin-1 Unicode Character Range: À-ÖØ-ßà-öø-ÿ; Standard Unicode Character Range: -~", "writeOnly": true })), "birth_date": Schema.String.annotate({ "description": "Date of birth in format yyyy-mm-dd. Must be at least 18 years old." }).check(Schema.isMinLength(10).annotate({ "expected": "a value with a length of at least 10" })).check(Schema.isMaxLength(10).annotate({ "expected": "a value with a length of at most 10" })), "nationality": Schema.optionalKey(Schema.String.annotate({ "description": "Legacy single nationality (ISO 3166-1 alpha-3). Prefer `nationalities` for all nationalities. See individual customer `nationality` / `nationalities` and [EEA nationalities](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#nationalities).\n", "writeOnly": true })), "nationalities": Schema.optionalKey(Schema.Array(Schema.String.check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))).annotate({ "description": "All nationalities for this associated person (ISO 3166-1 alpha-3). **EEA / BBSA in-scope businesses:** required on each UBO / associated person where policy applies.\n", "writeOnly": true })), "place_of_birth": Schema.optionalKey(Schema.Struct({ "country": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-1 alpha-3 country code for the place of birth." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))), "city": Schema.optionalKey(Schema.String.annotate({ "description": "City of birth (recommended for EEA)." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))) }).annotate({ "description": "Country (and optionally city) of birth. **EEA / BBSA in-scope customers:** supply when onboarding individuals or associated persons under the [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#country-of-birth-and-city-of-birth). This is a sparse address — no street address. At least `country` should be present when the object is sent; `city` is recommended and will be required by EU law in 2027.\n", "writeOnly": true })), "verified_database_at": Schema.optionalKey(Schema.String.annotate({ "description": "Write-only ISO 8601 timestamp. For **EEA in-scope** associated persons on **reliance**, second factor with `verified_govid_at` under `TWO_FORMS_OF_ID_RELIANCE`.\n", "writeOnly": true, "format": "date-time" })), "has_ownership": Schema.Boolean.annotate({ "description": "True if this person has at least 25% ownership of the business." }), "has_control": Schema.Boolean.annotate({ "description": "True if this is the control person of the company, having significant responsibility to control, manage or influence the activities of the business entity. At least one control person must be specified. " }), "is_signer": Schema.Boolean.annotate({ "description": "True if this person is able to authorize transactions on behalf of the business. At least one signer must be specified." }), "is_director": Schema.optionalKey(Schema.Boolean.annotate({ "description": "True if this person is an appointed director of the company. **EEA / BBSA in-scope businesses:** must be set for every associated person (complete director list). See [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#complete-director-list)." })), "title": Schema.optionalKey(Schema.String.annotate({ "description": "The title of this associated person at the company, e.g. CEO, CFO, etc. Required if has_control is true." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" }))), "ownership_percentage": Schema.optionalKey(Schema.Number.annotate({ "description": "Ultimate ownership percentage of the business. **EEA / BBSA in-scope businesses:** required when `has_ownership` is true for UBOs at or above the configured threshold (default 25%). See [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#ownership-percentage-per-ubo).\n", "writeOnly": true }).check(Schema.isInt().annotate({ "expected": "an integer" }))), "attested_ownership_structure_at": Schema.optionalKey(Schema.String.annotate({ "description": "The date or timestamp when this individual attested to the correctness of the ownership structure provided to Bridge. If provided by at least one control person, ownership documents for the business are not required.", "writeOnly": true })), "verified_account_authorization_at": Schema.optionalKey(Schema.String.annotate({ "description": "Write-only ISO 8601 timestamp. For **EEA in-scope** businesses on **reliance**, may satisfy signatory authority for signers who are not owner, director, or control person (`signature_authority_requirement(for_reliance: true)`); alternative is `documents` with purpose `proof_of_signatory_authority`. See [EEA updated requirements — LOA](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#letter-of-authority-loa).\n", "writeOnly": true, "format": "date-time" })), "relationship_established_at": Schema.optionalKey(Schema.String.annotate({ "description": "The date or timestamp when the associated person relationship was established in format yyyy-mm-dd." })), "verified_govid_at": Schema.optionalKey(Schema.String.annotate({ "description": "Write-only ISO 8601 timestamp. For **EEA in-scope** associated persons on **reliance**, use with `verified_selfie_at` or `verified_database_at` under `TWO_FORMS_OF_ID_RELIANCE`.\n", "writeOnly": true, "format": "date-time" })), "verified_selfie_at": Schema.optionalKey(Schema.String.annotate({ "description": "Write-only ISO 8601 timestamp. For **EEA in-scope** associated persons on **reliance**, pairs with `verified_govid_at` or `verified_database_at` under `TWO_FORMS_OF_ID_RELIANCE`.\n", "writeOnly": true, "format": "date-time" })), "identifying_information": Schema.Array(Schema.Struct({ "type": Schema.Literals(["drivers_license", "matriculate_id", "military_id", "national_id", "passport", "permanent_residency_id", "state_or_provincial_id", "visa", "abn", "acn", "ahv", "ak", "aom", "arbn", "avs", "bc", "bce", "bin", "bir", "bp", "brn", "bsn", "bvn", "cc", "cdi", "cedula_juridica", "cf", "cif", "cin", "cipc", "cn", "cnp", "cnpj", "cpf", "cpr", "crc", "crib", "crn", "cro", "cui", "cuil", "curp", "cuit", "cvr", "edrpou", "ein", "embg", "emirates_id", "en", "fin", "fn", "gstin", "gui", "hetu", "hkid", "hn", "ic", "ico", "id", "id_broj", "idno", "idnp", "idnr", "if", "iin", "ik", "inn", "ird", "itin", "itr", "iva", "jmbg", "kbo", "kvk", "matricule", "mf", "mn", "ms", "mst", "nic", "nicn", "nie", "nif", "nin", "nino", "nip", "nipc", "nipt", "nit", "npwp", "nric", "nrn", "nrt", "ntn", "nuit", "nzbn", "oib", "orgnr", "other", "pan", "partita_iva", "pesel", "pib", "pin", "pk", "ppsn", "qid", "rc", "regon", "rfc", "ricn", "rif", "rn", "rnc", "rnokpp", "rp", "rrn", "rtn", "ruc", "rut", "si", "sin", "siren", "siret", "spi", "ssm", "ssn", "steuer_id", "strn", "tckn", "tfn", "tin", "tpin", "trn", "ucn", "uen", "uic", "uid", "usc", "ust_idnr", "utr", "vat", "vkn", "voen", "y_tunnus"]).annotate({ "description": "Tax identification number type or government-issued ID document type (see enum). Country-specific tax and national ID lists: [Individuals](https://apidocs.bridge.xyz/docs/individual-tax-identification-numbers-by-country), [Businesses](https://apidocs.bridge.xyz/docs/business-tax-identification-numbers-by-country).\n\n**EEA / BBSA (policy in `eea_requirements.rb`):** In-scope individuals and UBOs need **both** a valid national-ID-type entry and a valid TIN per [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements). In-scope businesses need business registration **and** business tax ID types per country tables there. **TIN issuing country** must match residence (individuals) or incorporation (businesses). **Foreign tax** outside the incorporation country: set `has_foreign_tax_registration` on the business customer and add TIN objects per jurisdiction ([foreign tax / tax residency](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#tax-residency-status-foreign-tax-registry)).\n" }), "issuing_country": Schema.String.annotate({ "description": "The ISO 3166-1 (three-character) country code that issued the provided document." }), "number": Schema.optionalKey(Schema.String.annotate({ "description": "The unique identifier of the document. Required if this document is being used as a tax identification number (e.g., you are providing a passport or national_id with no other identification)." })), "description": Schema.optionalKey(Schema.String.annotate({ "description": "A description describing the provided document. This field is required when `other` is selected." })), "expiration": Schema.optionalKey(Schema.String.annotate({ "description": "The expiration date of the given document in yyyy-mm-dd format." })), "image_front": Schema.optionalKey(Schema.String.annotate({ "description": "This field is optionally accepted for tax_id types, but required for government_id types. Base64 encoded image* of the front side of the provided document, following the data-uri scheme i.e. data:image/[type];base64,[base_64_encoded_file_contents], with a minimum size of 200px x 200px \\n\\n*Maximum File Size: 15MB\\n\\n*Valid file types: .pdf, .jpeg, .jpg, .png, .heic, .tif\n\n_Note: When combined with an `image_back`, the combined size of both images must not exceed 24MB._\n" })), "image_back": Schema.optionalKey(Schema.String.annotate({ "description": "Base64 encoded image* of the back side of the provided document, following the data-uri scheme i.e. data:image/[type];base64,[base_64_encoded_file_contents], with a minimum size of 200px x 200px \\n\\n*Maximum File Size: 15MB\\n\\n*Valid file types: .pdf, .jpeg, .jpg, .png, .heic, .tif\n\n_Note: When combined with an `image_front`, the combined size of both images must not exceed 24MB._\n" })) })).annotate({ "title": "Identification Information", "writeOnly": true }), "documents": Schema.optionalKey(Schema.Array(Schema.Struct({ "purposes": Schema.Array(Schema.Literals(["proof_of_account_purpose", "proof_of_address", "proof_of_individual_name_change", "proof_of_relationship", "proof_of_source_of_funds", "proof_of_source_of_wealth", "proof_of_tax_identification", "other"])).annotate({ "description": "A list of purposes that the given document serves. Click \"ADD STRING\" to see common document purposes for individuals, or view the full list of possible values [here](https://apidocs.bridge.xyz/docs/supported-documents)." }), "file": Schema.String.annotate({ "description": "Base64 encoded image* of the provided document, following the data-uri scheme i.e. data:image/[type];base64,[base_64_encoded_file_contents], with a minimum size of 200px x 200px \n\n*Maximum File Size: 24MB\n\n*Valid file types: .pdf, .jpeg, .jpg, .png, .heic, .tif" }), "description": Schema.optionalKey(Schema.String.annotate({ "description": "A description describing the provided document. This field is required when `other` is provided as one of the purposes." })) })).annotate({ "title": "Documents", "description": "Please click \"ADD OBJECT\" for more information.", "writeOnly": true })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))])).annotate({ "description": "List of notable people associated with the business such as UBOs." })), "endorsements": Schema.optionalKey(Schema.Array(Schema.Literals(["base", "cards", "cop", "faster_payments", "pix", "pix_onramp", "pix_offramp", "sepa", "spei"]).annotate({ "description": "The type of endorsement. Note: `pix_onramp` (BRL deposits via PIX) and `pix_offramp` (BRL withdrawals via PIX) can be requested individually for granular access. Requesting `pix` grants both directional endorsements. `pix_onramp` is not supported for non-BR individuals; if requested (or requested via `pix`) it will remain in an `endorsement_not_available_in_customers_region` state and no action is required.\n" })).annotate({ "description": "List of endorsements to request for this customer. If omitted, we'll attempt to grant `base` and `sepa`.\n", "writeOnly": true })), "business_industry": Schema.optionalKey(Schema.Array(Schema.String).annotate({ "description": "The industry in which this business operates. Click [here](https://apidocs.bridge.xyz/page/business-industry-list-updated-2022-naics-codes) for the complete list of valid industries and codes." })), "publicly_traded_listings": Schema.optionalKey(Schema.Array(Schema.Struct({ "market_identifier_code": Schema.String.annotate({ "description": "The 4-digit Market Identifier Code (MIC) (ISO 10383) for the venue where the business is publicly listed and traded." }), "stock_number": Schema.String.annotate({ "description": "The 12-digit International Securities Identification Number (ISIN) of the company without dashes (-)." }), "ticker": Schema.String.annotate({ "description": "The ticker for the business's publicly traded listing." }) })).annotate({ "description": "A list of public exchanges that the company is traded on if applicable.", "writeOnly": true })), "ownership_threshold": Schema.optionalKey(Schema.Number.annotate({ "description": "The applicable beneficial ownership threshold for the submitted `associated_persons` information. Valid values are between 5 to 25. Default value is 25." }).check(Schema.isInt().annotate({ "expected": "an integer" }))), "has_material_intermediary_ownership": Schema.optionalKey(Schema.Boolean.annotate({ "description": "The business has at least one intermediate legal entity owner with 25% or more ownership" })), "estimated_annual_revenue_usd": Schema.optionalKey(Schema.Literals(["0_99999", "100000_999999", "1000000_9999999", "10000000_49999999", "50000000_249999999", "250000000_plus"]).annotate({ "description": "Estimated annual revenue in USD\n\n_Required for high risk customers. More information found [here](https://apidocs.bridge.xyz/docs/business-accounts)_\n" })), "expected_monthly_payments_usd": Schema.optionalKey(Schema.Number.annotate({ "description": "Expected monthly payments in USD\n\n_Required for high risk customers. More information found [here](https://apidocs.bridge.xyz/docs/business-accounts)_\n" }).check(Schema.isInt().annotate({ "expected": "an integer" }))), "expected_monthly_swift_transaction_volume": Schema.optionalKey(Schema.Number.annotate({ "description": "Expected monthly SWIFT transaction volume in USD.\n\n_Deprecated: no longer required for the SWIFT endorsement._\n" }).check(Schema.isInt().annotate({ "expected": "an integer" }))), "operates_in_prohibited_countries": Schema.optionalKey(Schema.Boolean.annotate({ "description": "Does the business operate in any prohibited countries?\n\n_Required for high risk customers. More information found [here](https://apidocs.bridge.xyz/docs/business-accounts)_\n" })), "account_purpose": Schema.optionalKey(Schema.Literals(["charitable_donations", "ecommerce_retail_payments", "investment_purposes", "other", "payments_to_friends_or_family_abroad", "payroll", "personal_or_living_expenses", "protect_wealth", "purchase_goods_and_services", "receive_payments_for_goods_and_services", "tax_optimization", "third_party_money_transmission", "treasury_management"]).annotate({ "description": "What is the primary purpose of the business account?" })), "account_purpose_other": Schema.optionalKey(Schema.String.annotate({ "description": "Required if the primary purpose is 'other'." })), "high_risk_activities_explanation": Schema.optionalKey(Schema.String.annotate({ "description": "An explanation of the high risk activities that the business performs. \n\n_Required if `high_risk_activities` contains entries other than `none_of_the_above`_\n" })), "high_risk_activities": Schema.optionalKey(Schema.Array(Schema.Literals(["adult_entertainment", "gambling", "hold_client_funds", "investment_services", "lending_banking", "marijuana_or_related_services", "money_services", "nicotine_tobacco_or_related_services", "operate_foreign_exchange_virtual_currencies_brokerage_otc", "pharmaceuticals", "precious_metals_precious_stones_jewelry", "safe_deposit_box_rentals", "third_party_payment_processing", "weapons_firearms_and_explosives", "none_of_the_above"])).annotate({ "description": "List of high-risk activities the business is involved in.\n\n_Required for high risk customers. More information found [here](https://apidocs.bridge.xyz/docs/business-accounts)_\n" })), "source_of_funds": Schema.optionalKey(Schema.Literals(["business_loans", "grants", "inter_company_funds", "investment_proceeds", "legal_settlement", "owners_capital", "pension_retirement", "sale_of_assets", "sales_of_goods_and_services", "third_party_funds", "treasury_reserves"]).annotate({ "description": "The source of funds for the business, e.g. profits, income, venture capital, etc." })), "source_of_funds_description": Schema.optionalKey(Schema.String.annotate({ "description": "Description of the source of funds for the business' account.\n\n_Required for high risk customers. More information found [here](https://apidocs.bridge.xyz/docs/business-accounts)_\n" })), "conducts_money_services": Schema.optionalKey(Schema.Boolean.annotate({ "description": "The business offers money services, investment products, and/or other financial services.\n\n_Required for high risk customers. More information found [here](https://apidocs.bridge.xyz/docs/business-accounts)_\n" })), "conducts_money_services_using_bridge": Schema.optionalKey(Schema.Boolean.annotate({ "description": "The business plans to conduct money services, investment products, and/or other financial services using its Bridge account. A document with purpose 'flow_of_funds' is required if this is true.\n\n_Required if `conducts_money_services` is true_\n" })), "conducts_money_services_description": Schema.optionalKey(Schema.String.annotate({ "description": "Description of the money services offered by the business.\n\n_Required if `conducts_money_services` is true_\n" })), "identifying_information": Schema.optionalKey(Schema.Array(Schema.Struct({ "type": Schema.Literals(["drivers_license", "matriculate_id", "military_id", "national_id", "passport", "permanent_residency_id", "state_or_provincial_id", "visa", "abn", "acn", "ahv", "ak", "aom", "arbn", "avs", "bc", "bce", "bin", "bir", "bp", "brn", "bsn", "bvn", "cc", "cdi", "cedula_juridica", "cf", "cif", "cin", "cipc", "cn", "cnp", "cnpj", "cpf", "cpr", "crc", "crib", "crn", "cro", "cui", "cuil", "curp", "cuit", "cvr", "edrpou", "ein", "embg", "emirates_id", "en", "fin", "fn", "gstin", "gui", "hetu", "hkid", "hn", "ic", "ico", "id", "id_broj", "idno", "idnp", "idnr", "if", "iin", "ik", "inn", "ird", "itin", "itr", "iva", "jmbg", "kbo", "kvk", "matricule", "mf", "mn", "ms", "mst", "nic", "nicn", "nie", "nif", "nin", "nino", "nip", "nipc", "nipt", "nit", "npwp", "nric", "nrn", "nrt", "ntn", "nuit", "nzbn", "oib", "orgnr", "other", "pan", "partita_iva", "pesel", "pib", "pin", "pk", "ppsn", "qid", "rc", "regon", "rfc", "ricn", "rif", "rn", "rnc", "rnokpp", "rp", "rrn", "rtn", "ruc", "rut", "si", "sin", "siren", "siret", "spi", "ssm", "ssn", "steuer_id", "strn", "tckn", "tfn", "tin", "tpin", "trn", "ucn", "uen", "uic", "uid", "usc", "ust_idnr", "utr", "vat", "vkn", "voen", "y_tunnus"]).annotate({ "description": "Tax identification number type or government-issued ID document type (see enum). Country-specific tax and national ID lists: [Individuals](https://apidocs.bridge.xyz/docs/individual-tax-identification-numbers-by-country), [Businesses](https://apidocs.bridge.xyz/docs/business-tax-identification-numbers-by-country).\n\n**EEA / BBSA (policy in `eea_requirements.rb`):** In-scope individuals and UBOs need **both** a valid national-ID-type entry and a valid TIN per [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements). In-scope businesses need business registration **and** business tax ID types per country tables there. **TIN issuing country** must match residence (individuals) or incorporation (businesses). **Foreign tax** outside the incorporation country: set `has_foreign_tax_registration` on the business customer and add TIN objects per jurisdiction ([foreign tax / tax residency](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#tax-residency-status-foreign-tax-registry)).\n" }), "issuing_country": Schema.String.annotate({ "description": "The ISO 3166-1 (three-character) country code that issued the provided document." }), "number": Schema.optionalKey(Schema.String.annotate({ "description": "The unique identifier of the document. Required if this document is being used as a tax identification number (e.g., you are providing a passport or national_id with no other identification)." })), "description": Schema.optionalKey(Schema.String.annotate({ "description": "A description describing the provided document. This field is required when `other` is selected." })), "expiration": Schema.optionalKey(Schema.String.annotate({ "description": "The expiration date of the given document in yyyy-mm-dd format." })), "image_front": Schema.optionalKey(Schema.String.annotate({ "description": "This field is optionally accepted for tax_id types, but required for government_id types. Base64 encoded image* of the front side of the provided document, following the data-uri scheme i.e. data:image/[type];base64,[base_64_encoded_file_contents], with a minimum size of 200px x 200px \\n\\n*Maximum File Size: 15MB\\n\\n*Valid file types: .pdf, .jpeg, .jpg, .png, .heic, .tif\n\n_Note: When combined with an `image_back`, the combined size of both images must not exceed 24MB._\n" })), "image_back": Schema.optionalKey(Schema.String.annotate({ "description": "Base64 encoded image* of the back side of the provided document, following the data-uri scheme i.e. data:image/[type];base64,[base_64_encoded_file_contents], with a minimum size of 200px x 200px \\n\\n*Maximum File Size: 15MB\\n\\n*Valid file types: .pdf, .jpeg, .jpg, .png, .heic, .tif\n\n_Note: When combined with an `image_front`, the combined size of both images must not exceed 24MB._\n" })) })).annotate({ "title": "Identification Information", "writeOnly": true })), "documents": Schema.optionalKey(Schema.Array(Schema.Struct({ "purposes": Schema.Array(Schema.Literals(["aml_comfort_letter", "business_formation", "directors_registry", "e_signature_certificate", "evidence_of_good_standing", "flow_of_funds", "marketing_materials", "ownership_chart", "ownership_information", "proof_of_account_purpose", "proof_of_address", "proof_of_entity_name_change", "proof_of_nature_of_business", "proof_of_signatory_authority", "proof_of_source_of_funds", "proof_of_source_of_wealth", "proof_of_tax_identification", "shareholder_register", "other"])).annotate({ "description": "**EEA / BBSA (business KYB):** purposes used in [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements) include `business_formation`, `evidence_of_good_standing`, `ownership_information`, and `proof_of_signatory_authority` (letter of authorization). See supported-documents for the full enum [here](https://apidocs.bridge.xyz/docs/supported-documents).\n\nFor **non-reliance** EEA in-scope businesses, `business_formation`, `evidence_of_good_standing`, and `ownership_information` are evaluated **independently** in CPU policy: each may be satisfied by an uploaded/Persona-backed document **or**, when Stripe business-registry verification passes with the required checks and provider metadata, by that verification alone for that document slot (see `BUSINESS_REGISTRY_CHECK` and `BUSINESS_OWNERSHIP` in `eea_requirements.rb`).\n" }), "file": Schema.String.annotate({ "description": "Base64 encoded image of the provided document, following the data-uri scheme i.e. data:image/[type];base64,[base_64_encoded_file_contents], with a minimum size of 200px x 200px \n\n*Maximum File Size: 24MB\n\n*Valid file types: .pdf, .jpeg, .jpg, .png, .heic, .tif" }), "description": Schema.optionalKey(Schema.String.annotate({ "description": "A description describing the provided document. This field is required when `other` is provided as one of the purposes." })) })).annotate({ "title": "Documents", "description": "Please click \"ADD OBJECT\" for more information.", "writeOnly": true })), "incorporation_date": Schema.optionalKey(Schema.String.annotate({ "description": "The date the business was incorporated, in ISO 8601 format (YYYY-MM-DD).", "format": "date" })), "verified_business_formation_at": Schema.optionalKey(Schema.String.annotate({ "description": "Write-only ISO 8601 timestamp. For **EEA in-scope** businesses on **reliance**, may satisfy `BUSINESS_REGISTRY_CHECK_RELIANCE` together with good-standing/registry evidence (or use document purpose `business_formation`). See [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#evidence-of-good-standing).\n", "writeOnly": true, "format": "date-time" })), "verified_business_registry_at": Schema.optionalKey(Schema.String.annotate({ "description": "Write-only ISO 8601 timestamp. For **EEA in-scope** businesses on **reliance**, registry-side evidence for `BUSINESS_REGISTRY_CHECK_RELIANCE`. Use `verified_evidence_of_good_standing_at` when the artifact maps to purpose `evidence_of_good_standing`.\n", "writeOnly": true, "format": "date-time" })), "verified_evidence_of_good_standing_at": Schema.optionalKey(Schema.String.annotate({ "description": "Write-only ISO 8601 timestamp. For **EEA in-scope** businesses on **reliance**, evidence-of-good-standing path (`evidence_of_good_standing`) under `BUSINESS_REGISTRY_CHECK_RELIANCE`.\n", "writeOnly": true, "format": "date-time" })), "verified_ownership_at": Schema.optionalKey(Schema.String.annotate({ "description": "Write-only ISO 8601 timestamp. For **EEA in-scope** businesses on **reliance**, may satisfy `BUSINESS_OWNERSHIP_RELIANCE` (ownership / cap-table documentation). See [EEA updated requirements — ownership document](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#ownership-document-always-required).\n", "writeOnly": true, "format": "date-time" })), "regulated_activity": Schema.optionalKey(Schema.Struct({ "regulated_activities_description": Schema.String.annotate({ "description": "A detailed description of the regulated activities the business is licensed to conduct." }), "primary_regulatory_authority_country": Schema.String.annotate({ "description": "The ISO 3166-1 (three-character) country code." }), "primary_regulatory_authority_name": Schema.String.annotate({ "description": "The name of the primary regulatory authority that oversees the business's regulated activities." }), "license_number": Schema.String.annotate({ "description": "The license number or registration number assigned by the business's primary regulator." }) })), "acting_as_intermediary": Schema.optionalKey(Schema.Boolean.annotate({ "description": "Is the customer acting as an intermediary for a third party?\n\n_Required for high risk customers. More information found [here](https://apidocs.bridge.xyz/docs/business-accounts)_\n" })), "client_reference_id": Schema.optionalKey(Schema.String.annotate({ "description": "Caller-provided identifier used to correlate this customer with your internal records. Returned in API and webhook responses." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" }))) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "title": "Business Customer", "identifier": "UpdateBusinessCustomerPayload" }) +export type ExternalAccountResponse = { readonly "id": string, readonly "customer_id": string, readonly "created_at": string, readonly "updated_at": string, readonly "account_owner_name": string, readonly "currency": "usd", readonly "account_type": "us", readonly "active": boolean, readonly "bank_name"?: string, readonly "account_owner_type"?: "individual" | "business", readonly "first_name"?: string, readonly "last_name"?: string, readonly "business_name"?: string, readonly "address"?: { readonly "street_line_1": string, readonly "street_line_2"?: string, readonly "city": string, readonly "state"?: string, readonly "postal_code"?: string, readonly "country": string } & { readonly [x: string]: Schema.Json }, readonly "account_owner_country"?: string, readonly "deactivation_reason"?: "plaid_item_error" | "deactivated_due_to_bounceback" | "deleted_by_developer" | "requested_by_developer" | "invalid_account_number" | "invalid_bank_validation" | "rejected_by_bank_provider", readonly "deactivation_details"?: string, readonly "account": { readonly "account_number"?: string, readonly "routing_number": string, readonly "last_4": string, readonly "checking_or_savings"?: "checking" | "savings" } & { readonly [x: string]: Schema.Json }, readonly "beneficiary_address_valid"?: boolean, readonly "last_4"?: string, readonly "account_number"?: string, readonly "routing_number"?: string } & { readonly [x: string]: Schema.Json } | { readonly "id": string, readonly "customer_id": string, readonly "created_at": string, readonly "updated_at": string, readonly "account_owner_name": string, readonly "currency": "eur", readonly "account_type": "iban", readonly "active": boolean, readonly "bank_name"?: string, readonly "account_owner_type"?: "individual" | "business", readonly "first_name"?: string, readonly "last_name"?: string, readonly "business_name"?: string, readonly "address"?: { readonly "street_line_1": string, readonly "street_line_2"?: string, readonly "city": string, readonly "state"?: string, readonly "postal_code"?: string, readonly "country": string } & { readonly [x: string]: Schema.Json }, readonly "account_owner_country"?: string, readonly "deactivation_reason"?: "plaid_item_error" | "deactivated_due_to_bounceback" | "deleted_by_developer" | "requested_by_developer" | "invalid_account_number" | "invalid_bank_validation" | "rejected_by_bank_provider", readonly "deactivation_details"?: string, readonly "iban": { readonly "account_number"?: string, readonly "bic"?: string, readonly "country": string, readonly "last_4": string } & { readonly [x: string]: Schema.Json }, readonly "account_verification"?: { readonly "iban"?: { readonly "match_level"?: "pending" | "match" | "close_match" | "no_match" | "error", readonly "reason_code"?: string | null, readonly "validated_account_owner_name"?: string | null }, readonly "requested_at"?: string, readonly "completed_at"?: string | null } } & { readonly [x: string]: Schema.Json } | { readonly "id": string, readonly "customer_id": string, readonly "created_at": string, readonly "updated_at": string, readonly "account_owner_name": string, readonly "currency": "mxn", readonly "account_type": "clabe", readonly "active": boolean, readonly "bank_name"?: string, readonly "account_owner_type"?: "individual" | "business", readonly "first_name"?: string, readonly "last_name"?: string, readonly "business_name"?: string, readonly "address"?: { readonly "street_line_1": string, readonly "street_line_2"?: string, readonly "city": string, readonly "state"?: string, readonly "postal_code"?: string, readonly "country": string } & { readonly [x: string]: Schema.Json }, readonly "account_owner_country"?: string, readonly "deactivation_reason"?: "plaid_item_error" | "deactivated_due_to_bounceback" | "deleted_by_developer" | "requested_by_developer" | "invalid_account_number" | "invalid_bank_validation" | "rejected_by_bank_provider", readonly "deactivation_details"?: string, readonly "clabe": { readonly "account_number"?: string, readonly "last_4": string } & { readonly [x: string]: Schema.Json }, readonly "account_validation"?: { readonly "validated_account_owner_name"?: string | null, readonly "validated_bank_name"?: string | null, readonly "validated_document_number_last4"?: string | null }, readonly "account_verification"?: { readonly "clabe"?: { readonly "matched"?: boolean | null, readonly "reason_code"?: string | null, readonly "validated_account_owner_name"?: string | null, readonly "validated_bank_name"?: string | null }, readonly "requested_at"?: string, readonly "completed_at"?: string | null } } & { readonly [x: string]: Schema.Json } | { readonly "id": string, readonly "customer_id": string, readonly "created_at": string, readonly "updated_at": string, readonly "account_owner_name": string, readonly "currency": "brl", readonly "account_type": "pix", readonly "active": boolean, readonly "bank_name"?: string, readonly "account_owner_type"?: "individual" | "business", readonly "first_name"?: string, readonly "last_name"?: string, readonly "business_name"?: string, readonly "address"?: { readonly "street_line_1": string, readonly "street_line_2"?: string, readonly "city": string, readonly "state"?: string, readonly "postal_code"?: string, readonly "country": string } & { readonly [x: string]: Schema.Json }, readonly "account_owner_country"?: string, readonly "deactivation_reason"?: "plaid_item_error" | "deactivated_due_to_bounceback" | "deleted_by_developer" | "requested_by_developer" | "invalid_account_number" | "invalid_bank_validation" | "rejected_by_bank_provider", readonly "deactivation_details"?: string, readonly "pix_key"?: { readonly "pix_key"?: string, readonly "document_number"?: string, readonly "account_preview": string, readonly "document_number_last4"?: string } & { readonly [x: string]: Schema.Json }, readonly "br_code"?: { readonly "br_code"?: string, readonly "document_number"?: string, readonly "account_preview": string, readonly "document_number_last4"?: string } & { readonly [x: string]: Schema.Json }, readonly "account_validation"?: { readonly "validated_account_owner_name"?: string | null, readonly "validated_bank_name"?: string | null, readonly "validated_document_number_last4"?: string | null }, readonly "account_verification"?: { readonly "pix"?: { readonly "matched"?: boolean | null, readonly "reason_code"?: string | null, readonly "validated_account_owner_name"?: string | null, readonly "validated_bank_name"?: string | null }, readonly "requested_at"?: string, readonly "completed_at"?: string | null } } & { readonly [x: string]: Schema.Json } | { readonly "id": string, readonly "customer_id": string, readonly "created_at": string, readonly "updated_at": string, readonly "account_owner_name": string, readonly "currency": "gbp", readonly "account_type": "gb", readonly "active": boolean, readonly "bank_name"?: string, readonly "account_owner_type"?: "individual" | "business", readonly "first_name"?: string, readonly "last_name"?: string, readonly "business_name"?: string, readonly "address"?: { readonly "street_line_1": string, readonly "street_line_2"?: string, readonly "city": string, readonly "state"?: string, readonly "postal_code"?: string, readonly "country": string } & { readonly [x: string]: Schema.Json }, readonly "account_owner_country"?: string, readonly "deactivation_reason"?: "plaid_item_error" | "deactivated_due_to_bounceback" | "deleted_by_developer" | "requested_by_developer" | "invalid_account_number" | "invalid_bank_validation" | "rejected_by_bank_provider", readonly "deactivation_details"?: string, readonly "account": { readonly "account_number"?: string, readonly "last_4": string, readonly "sort_code": string }, readonly "account_verification"?: { readonly "gb"?: { readonly "match_level"?: "pending" | "match" | "close_match" | "no_match" | "error", readonly "reason_code"?: string | null, readonly "validated_account_owner_name"?: string | null }, readonly "requested_at"?: string, readonly "completed_at"?: string | null } } & { readonly [x: string]: Schema.Json } | { readonly "id": string, readonly "customer_id": string, readonly "created_at": string, readonly "updated_at": string, readonly "account_owner_name": string, readonly "currency": "cop", readonly "account_type": "bre_b", readonly "active": boolean, readonly "bank_name"?: string, readonly "account_owner_type"?: "individual" | "business", readonly "first_name"?: string, readonly "last_name"?: string, readonly "business_name"?: string, readonly "address"?: { readonly "street_line_1": string, readonly "street_line_2"?: string, readonly "city": string, readonly "state"?: string, readonly "postal_code"?: string, readonly "country": string } & { readonly [x: string]: Schema.Json }, readonly "account_owner_country"?: string, readonly "deactivation_reason"?: "plaid_item_error" | "deactivated_due_to_bounceback" | "deleted_by_developer" | "requested_by_developer" | "invalid_account_number" | "invalid_bank_validation" | "rejected_by_bank_provider", readonly "deactivation_details"?: string, readonly "account": { readonly "bre_b_key"?: string, readonly "last_4": string } & { readonly [x: string]: Schema.Json }, readonly "account_validation"?: { readonly "validated_account_owner_name"?: string | null, readonly "validated_bank_name"?: string | null, readonly "validated_document_number_last4"?: string | null }, readonly "account_verification"?: { readonly "bre_b"?: { readonly "matched"?: boolean | null, readonly "reason_code"?: string | null, readonly "validated_account_owner_name"?: string | null, readonly "validated_bank_name"?: string | null, readonly "validated_document_number_last4"?: string | null }, readonly "requested_at"?: string, readonly "completed_at"?: string | null } } & { readonly [x: string]: Schema.Json } | { readonly "id": string, readonly "customer_id": string, readonly "created_at": string, readonly "updated_at": string, readonly "account_owner_name": string, readonly "currency": "cop", readonly "account_type": "co_bank_transfer", readonly "active": boolean, readonly "bank_name"?: string, readonly "account_owner_type"?: "individual" | "business", readonly "first_name"?: string, readonly "last_name"?: string, readonly "business_name"?: string, readonly "address"?: { readonly "street_line_1": string, readonly "street_line_2"?: string, readonly "city": string, readonly "state"?: string, readonly "postal_code"?: string, readonly "country": string } & { readonly [x: string]: Schema.Json }, readonly "account_owner_country"?: string, readonly "deactivation_reason"?: "plaid_item_error" | "deactivated_due_to_bounceback" | "deleted_by_developer" | "requested_by_developer" | "invalid_account_number" | "invalid_bank_validation" | "rejected_by_bank_provider", readonly "deactivation_details"?: string, readonly "account": { readonly "last_4"?: string, readonly "routing_number"?: string }, readonly "account_verification"?: { readonly "co_bank_transfer"?: { readonly "matched"?: boolean | null, readonly "reason_code"?: string | null, readonly "validated_account_owner_name"?: string | null, readonly "validated_bank_name"?: string | null, readonly "validated_document_number_last4"?: string | null }, readonly "requested_at"?: string, readonly "completed_at"?: string | null } } & { readonly [x: string]: Schema.Json } +export const ExternalAccountResponse = Schema.Union([Schema.StructWithRest(Schema.Struct({ "id": Schema.String.annotate({ "description": "A UUID that uniquely identifies a resource", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" })), "customer_id": Schema.String.annotate({ "description": "The id of the Bridge customer that this External Account belongs to", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "created_at": Schema.String.annotate({ "description": "Time of creation of the External Account", "readOnly": true, "format": "date-time" }), "updated_at": Schema.String.annotate({ "description": "Time of last update of the External Account", "readOnly": true, "format": "date-time" }), "account_owner_name": Schema.String.annotate({ "description": "Owner of the account Bank Account (e.g. \"John Doe\"). For ach, wire, and iban accounts, this field must be at least 3 characters, at most 35 characters, and follow the regex pattern for the given account type:\n- ach: `^(?!\\s*$)[\\x20-\\x7E]*$`\n- wire: ```^[ \\w!\"#$%&'()+,\\-./:;<=>?@\\\\_`~]*$```\n- iban: `^(?![:\\- ]*$)[a-zA-Z0-9\\/\\-?:().,'+ _]+$`\n" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" })), "currency": Schema.Literal("usd").annotate({ "description": "Currency associated with the bank account. Must be `usd` for US accounts." }), "account_type": Schema.Literal("us").annotate({ "description": "Type of the bank account." }), "active": Schema.Boolean.annotate({ "description": "Whether or not this External Account is active", "readOnly": true }), "bank_name": Schema.optionalKey(Schema.String.annotate({ "description": "Bank name of the account (e.g. \"Chase\")" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" }))), "account_owner_type": Schema.optionalKey(Schema.Literals(["individual", "business"]).annotate({ "description": "The type of the account ownership. Required when the `account_type` is `iban`. For `individual` ownership, `first_name` and `last_name` are required. For `business` ownership, `business_name` is required." })), "first_name": Schema.optionalKey(Schema.String.annotate({ "description": "First name of the individual account holder. Required when the `account_owner_type` is `individual`" })), "last_name": Schema.optionalKey(Schema.String.annotate({ "description": "Last name of the individual account holder. Required when the `account_owner_type` is `individual`" })), "business_name": Schema.optionalKey(Schema.String.annotate({ "description": "Business name of the business account holder. Required when the `account_owner_type` is `business`" })), "address": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "street_line_1": Schema.String.check(Schema.isMinLength(4).annotate({ "expected": "a value with a length of at least 4" })).check(Schema.isMaxLength(35).annotate({ "expected": "a value with a length of at most 35" })), "street_line_2": Schema.optionalKey(Schema.String.check(Schema.isMaxLength(35).annotate({ "expected": "a value with a length of at most 35" }))), "city": Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "state": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-2 subdivision code. Must be supplied for US addresses." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "postal_code": Schema.optionalKey(Schema.String.annotate({ "description": "Must be supplied for countries that use postal codes." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "country": Schema.String.annotate({ "description": "Three-letter alpha-3 country code as defined in the ISO 3166-1 spec." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Address of the beneficiary of this account. Please ensure the address is valid (Google Maps is good for this). US addresses used to receive wires must include a street number." })), "account_owner_country": Schema.optionalKey(Schema.String.annotate({ "description": "Three-letter alpha-3 country of residence of the account owner (ISO 3166-1).", "readOnly": true }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))), "deactivation_reason": Schema.optionalKey(Schema.Literals(["plaid_item_error", "deactivated_due_to_bounceback", "deleted_by_developer", "requested_by_developer", "invalid_account_number", "invalid_bank_validation", "rejected_by_bank_provider"]).annotate({ "description": "Reason for deactivation when this External Account is inactive", "readOnly": true })), "deactivation_details": Schema.optionalKey(Schema.String.annotate({ "description": "Additional details about the deactivation when this External Account is inactive", "readOnly": true })), "account": Schema.StructWithRest(Schema.Struct({ "account_number": Schema.optionalKey(Schema.String.annotate({ "description": "The bank account number", "writeOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "routing_number": Schema.String.annotate({ "description": "The bank routing number" }).check(Schema.isMinLength(9).annotate({ "expected": "a value with a length of at least 9" })).check(Schema.isMaxLength(9).annotate({ "expected": "a value with a length of at most 9" })), "last_4": Schema.String.annotate({ "description": "Last 4 digits of the bank account number", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "checking_or_savings": Schema.optionalKey(Schema.Literals(["checking", "savings"]).annotate({ "description": "Determines whether the US account is treated as checking or savings. All US accounts will be treated as checking by default." })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "title": "us" }), "beneficiary_address_valid": Schema.optionalKey(Schema.Boolean.annotate({ "description": "Whether the beneficiary address is valid. A valid beneficiary address is required for all US External Accounts", "readOnly": true })), "last_4": Schema.optionalKey(Schema.String.annotate({ "description": "Last 4 digits of the bank account number. This field is getting deprecated in favor of the `account.last_4` field", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "account_number": Schema.optionalKey(Schema.String.annotate({ "description": "Account number of your bank account. This field is getting deprecated in favor of the `account.account_number` field for US accounts.", "writeOnly": true }).check(Schema.isMinLength(12).annotate({ "expected": "a value with a length of at least 12" }))), "routing_number": Schema.optionalKey(Schema.String.annotate({ "description": "Routing number of your bank account. This field is getting deprecated in favor of the `account.routing_number` field for US accounts.", "writeOnly": true }).check(Schema.isMinLength(9).annotate({ "expected": "a value with a length of at least 9" }))) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "title": "ACH/Wire", "description": "Properties shared by all external account types" }), Schema.StructWithRest(Schema.Struct({ "id": Schema.String.annotate({ "description": "A UUID that uniquely identifies a resource", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" })), "customer_id": Schema.String.annotate({ "description": "The id of the Bridge customer that this External Account belongs to", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "created_at": Schema.String.annotate({ "description": "Time of creation of the External Account", "readOnly": true, "format": "date-time" }), "updated_at": Schema.String.annotate({ "description": "Time of last update of the External Account", "readOnly": true, "format": "date-time" }), "account_owner_name": Schema.String.annotate({ "description": "Owner of the account Bank Account (e.g. \"John Doe\"). For ach, wire, and iban accounts, this field must be at least 3 characters, at most 35 characters, and follow the regex pattern for the given account type:\n- ach: `^(?!\\s*$)[\\x20-\\x7E]*$`\n- wire: ```^[ \\w!\"#$%&'()+,\\-./:;<=>?@\\\\_`~]*$```\n- iban: `^(?![:\\- ]*$)[a-zA-Z0-9\\/\\-?:().,'+ _]+$`\n" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" })), "currency": Schema.Literal("eur").annotate({ "description": "Currency associated with the bank account. Must be `eur` for IBAN accounts." }), "account_type": Schema.Literal("iban").annotate({ "description": "Type of the bank account." }), "active": Schema.Boolean.annotate({ "description": "Whether or not this External Account is active", "readOnly": true }), "bank_name": Schema.optionalKey(Schema.String.annotate({ "description": "Bank name of the account (e.g. \"Chase\")" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" }))), "account_owner_type": Schema.optionalKey(Schema.Literals(["individual", "business"]).annotate({ "description": "The type of the account ownership. Required when the `account_type` is `iban`. For `individual` ownership, `first_name` and `last_name` are required. For `business` ownership, `business_name` is required." })), "first_name": Schema.optionalKey(Schema.String.annotate({ "description": "First name of the individual account holder. Required when the `account_owner_type` is `individual`" })), "last_name": Schema.optionalKey(Schema.String.annotate({ "description": "Last name of the individual account holder. Required when the `account_owner_type` is `individual`" })), "business_name": Schema.optionalKey(Schema.String.annotate({ "description": "Business name of the business account holder. Required when the `account_owner_type` is `business`" })), "address": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "street_line_1": Schema.String.check(Schema.isMinLength(4).annotate({ "expected": "a value with a length of at least 4" })).check(Schema.isMaxLength(35).annotate({ "expected": "a value with a length of at most 35" })), "street_line_2": Schema.optionalKey(Schema.String.check(Schema.isMaxLength(35).annotate({ "expected": "a value with a length of at most 35" }))), "city": Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "state": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-2 subdivision code. Must be supplied for US addresses." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "postal_code": Schema.optionalKey(Schema.String.annotate({ "description": "Must be supplied for countries that use postal codes." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "country": Schema.String.annotate({ "description": "Three-letter alpha-3 country code as defined in the ISO 3166-1 spec." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Address of the beneficiary of this account. Please ensure the address is valid (Google Maps is good for this). US addresses used to receive wires must include a street number." })), "account_owner_country": Schema.optionalKey(Schema.String.annotate({ "description": "Three-letter alpha-3 country of residence of the account owner (ISO 3166-1).", "readOnly": true }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))), "deactivation_reason": Schema.optionalKey(Schema.Literals(["plaid_item_error", "deactivated_due_to_bounceback", "deleted_by_developer", "requested_by_developer", "invalid_account_number", "invalid_bank_validation", "rejected_by_bank_provider"]).annotate({ "description": "Reason for deactivation when this External Account is inactive", "readOnly": true })), "deactivation_details": Schema.optionalKey(Schema.String.annotate({ "description": "Additional details about the deactivation when this External Account is inactive", "readOnly": true })), "iban": Schema.StructWithRest(Schema.Struct({ "account_number": Schema.optionalKey(Schema.String.annotate({ "description": "The International Bank Account Number (IBAN) that will be used to send the funds", "writeOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "bic": Schema.optionalKey(Schema.String.annotate({ "description": "The Bank Identifier Code (BIC/SWIFT code) associated with the beneficiary bank.\nWhile not strictly required for IBAN-based payments, providing the BIC may improve\npayment success rates.\n" }).check(Schema.isMinLength(8).annotate({ "expected": "a value with a length of at least 8" })).check(Schema.isMaxLength(11).annotate({ "expected": "a value with a length of at most 11" })).check(Schema.isPattern(new RegExp("^[A-Za-z]{4}[A-Za-z]{2}[A-Za-z0-9]{2}([A-Za-z0-9]{3})?$")).annotate({ "expected": "a string matching the RegExp ^[A-Za-z]{4}[A-Za-z]{2}[A-Za-z0-9]{2}([A-Za-z0-9]{3})?$" }))), "country": Schema.String.annotate({ "description": "Country in which the bank account is located. It's a three-letter alpha-3 country code as defined in the ISO 3166-1 spec." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" })), "last_4": Schema.String.annotate({ "description": "Last 4 digits of the bank account number", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]), "account_verification": Schema.optionalKey(Schema.Struct({ "iban": Schema.optionalKey(Schema.Struct({ "match_level": Schema.optionalKey(Schema.Literals(["pending", "match", "close_match", "no_match", "error"]).annotate({ "description": "The result of the name match check." })), "reason_code": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Additional context from the receiving bank when the result is not a full match." })), "validated_account_owner_name": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Account owner name as returned by the validation provider." })) })), "requested_at": Schema.optionalKey(Schema.String.annotate({ "description": "When the verification was requested.", "format": "date-time" })), "completed_at": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "When the verification completed. Null while pending.", "format": "date-time" })) }).annotate({ "title": "IBAN", "description": "Present for accounts with a holder verification check; contains the verification result.", "readOnly": true })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "title": "IBAN", "description": "Properties shared by all external account types" }), Schema.StructWithRest(Schema.Struct({ "id": Schema.String.annotate({ "description": "A UUID that uniquely identifies a resource", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" })), "customer_id": Schema.String.annotate({ "description": "The id of the Bridge customer that this External Account belongs to", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "created_at": Schema.String.annotate({ "description": "Time of creation of the External Account", "readOnly": true, "format": "date-time" }), "updated_at": Schema.String.annotate({ "description": "Time of last update of the External Account", "readOnly": true, "format": "date-time" }), "account_owner_name": Schema.String.annotate({ "description": "Owner of the account Bank Account (e.g. \"John Doe\"). For ach, wire, and iban accounts, this field must be at least 3 characters, at most 35 characters, and follow the regex pattern for the given account type:\n- ach: `^(?!\\s*$)[\\x20-\\x7E]*$`\n- wire: ```^[ \\w!\"#$%&'()+,\\-./:;<=>?@\\\\_`~]*$```\n- iban: `^(?![:\\- ]*$)[a-zA-Z0-9\\/\\-?:().,'+ _]+$`\n" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" })), "currency": Schema.Literal("mxn").annotate({ "description": "Currency associated with the bank account. Must be `mxn` for CLABE (SPEI) accounts." }), "account_type": Schema.Literal("clabe").annotate({ "description": "Type of the bank account." }), "active": Schema.Boolean.annotate({ "description": "Whether or not this External Account is active", "readOnly": true }), "bank_name": Schema.optionalKey(Schema.String.annotate({ "description": "Bank name of the account (e.g. \"Chase\")" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" }))), "account_owner_type": Schema.optionalKey(Schema.Literals(["individual", "business"]).annotate({ "description": "The type of the account ownership. Required when the `account_type` is `iban`. For `individual` ownership, `first_name` and `last_name` are required. For `business` ownership, `business_name` is required." })), "first_name": Schema.optionalKey(Schema.String.annotate({ "description": "First name of the individual account holder. Required when the `account_owner_type` is `individual`" })), "last_name": Schema.optionalKey(Schema.String.annotate({ "description": "Last name of the individual account holder. Required when the `account_owner_type` is `individual`" })), "business_name": Schema.optionalKey(Schema.String.annotate({ "description": "Business name of the business account holder. Required when the `account_owner_type` is `business`" })), "address": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "street_line_1": Schema.String.check(Schema.isMinLength(4).annotate({ "expected": "a value with a length of at least 4" })).check(Schema.isMaxLength(35).annotate({ "expected": "a value with a length of at most 35" })), "street_line_2": Schema.optionalKey(Schema.String.check(Schema.isMaxLength(35).annotate({ "expected": "a value with a length of at most 35" }))), "city": Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "state": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-2 subdivision code. Must be supplied for US addresses." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "postal_code": Schema.optionalKey(Schema.String.annotate({ "description": "Must be supplied for countries that use postal codes." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "country": Schema.String.annotate({ "description": "Three-letter alpha-3 country code as defined in the ISO 3166-1 spec." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Address of the beneficiary of this account. Please ensure the address is valid (Google Maps is good for this). US addresses used to receive wires must include a street number." })), "account_owner_country": Schema.optionalKey(Schema.String.annotate({ "description": "Three-letter alpha-3 country of residence of the account owner (ISO 3166-1).", "readOnly": true }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))), "deactivation_reason": Schema.optionalKey(Schema.Literals(["plaid_item_error", "deactivated_due_to_bounceback", "deleted_by_developer", "requested_by_developer", "invalid_account_number", "invalid_bank_validation", "rejected_by_bank_provider"]).annotate({ "description": "Reason for deactivation when this External Account is inactive", "readOnly": true })), "deactivation_details": Schema.optionalKey(Schema.String.annotate({ "description": "Additional details about the deactivation when this External Account is inactive", "readOnly": true })), "clabe": Schema.StructWithRest(Schema.Struct({ "account_number": Schema.optionalKey(Schema.String.annotate({ "description": "The CLABE account number of the bank account", "writeOnly": true }).check(Schema.isMinLength(18).annotate({ "expected": "a value with a length of at least 18" })).check(Schema.isMaxLength(18).annotate({ "expected": "a value with a length of at most 18" }))), "last_4": Schema.String.annotate({ "description": "Last 4 digits of the CLABE", "readOnly": true }).check(Schema.isMinLength(4).annotate({ "expected": "a value with a length of at least 4" })).check(Schema.isMaxLength(4).annotate({ "expected": "a value with a length of at most 4" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]), "account_validation": Schema.optionalKey(Schema.Struct({ "validated_account_owner_name": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Account owner name as returned by the validation provider." })), "validated_bank_name": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Bank name as returned by the validation provider." })), "validated_document_number_last4": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Last 4 characters of the account owner's document number, as returned by the validation provider. Present only for Bre-B (Colombian) accounts.", "readOnly": true })) }).annotate({ "description": "Present for CLABE accounts with a successful validation; contains validated owner and bank name.", "readOnly": true })), "account_verification": Schema.optionalKey(Schema.Struct({ "clabe": Schema.optionalKey(Schema.Struct({ "matched": Schema.optionalKey(Schema.Union([Schema.Boolean, Schema.Null]).annotate({ "description": "Match result as returned by the validation provider." })), "reason_code": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Additional context from the validation provider." })), "validated_account_owner_name": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Account owner name as returned by the validation provider." })), "validated_bank_name": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Bank name as returned by the validation provider." })) })), "requested_at": Schema.optionalKey(Schema.String.annotate({ "description": "When the verification was requested.", "format": "date-time" })), "completed_at": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "When the verification completed. Null while pending.", "format": "date-time" })) }).annotate({ "title": "CLABE", "description": "Present for accounts with a holder verification check; contains the verification result.", "readOnly": true })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "title": "CLABE", "description": "Properties shared by all external account types" }), Schema.StructWithRest(Schema.Struct({ "id": Schema.String.annotate({ "description": "A UUID that uniquely identifies a resource", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" })), "customer_id": Schema.String.annotate({ "description": "The id of the Bridge customer that this External Account belongs to", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "created_at": Schema.String.annotate({ "description": "Time of creation of the External Account", "readOnly": true, "format": "date-time" }), "updated_at": Schema.String.annotate({ "description": "Time of last update of the External Account", "readOnly": true, "format": "date-time" }), "account_owner_name": Schema.String.annotate({ "description": "Owner of the account Bank Account (e.g. \"John Doe\"). For ach, wire, and iban accounts, this field must be at least 3 characters, at most 35 characters, and follow the regex pattern for the given account type:\n- ach: `^(?!\\s*$)[\\x20-\\x7E]*$`\n- wire: ```^[ \\w!\"#$%&'()+,\\-./:;<=>?@\\\\_`~]*$```\n- iban: `^(?![:\\- ]*$)[a-zA-Z0-9\\/\\-?:().,'+ _]+$`\n" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" })), "currency": Schema.Literal("brl").annotate({ "description": "Currency associated with the bank account. Must be `brl` for Pix accounts." }), "account_type": Schema.Literal("pix").annotate({ "description": "Type of the bank account." }), "active": Schema.Boolean.annotate({ "description": "Whether or not this External Account is active", "readOnly": true }), "bank_name": Schema.optionalKey(Schema.String.annotate({ "description": "Bank name of the account (e.g. \"Chase\")" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" }))), "account_owner_type": Schema.optionalKey(Schema.Literals(["individual", "business"]).annotate({ "description": "The type of the account ownership. Required when the `account_type` is `iban`. For `individual` ownership, `first_name` and `last_name` are required. For `business` ownership, `business_name` is required." })), "first_name": Schema.optionalKey(Schema.String.annotate({ "description": "First name of the individual account holder. Required when the `account_owner_type` is `individual`" })), "last_name": Schema.optionalKey(Schema.String.annotate({ "description": "Last name of the individual account holder. Required when the `account_owner_type` is `individual`" })), "business_name": Schema.optionalKey(Schema.String.annotate({ "description": "Business name of the business account holder. Required when the `account_owner_type` is `business`" })), "address": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "street_line_1": Schema.String.check(Schema.isMinLength(4).annotate({ "expected": "a value with a length of at least 4" })).check(Schema.isMaxLength(35).annotate({ "expected": "a value with a length of at most 35" })), "street_line_2": Schema.optionalKey(Schema.String.check(Schema.isMaxLength(35).annotate({ "expected": "a value with a length of at most 35" }))), "city": Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "state": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-2 subdivision code. Must be supplied for US addresses." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "postal_code": Schema.optionalKey(Schema.String.annotate({ "description": "Must be supplied for countries that use postal codes." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "country": Schema.String.annotate({ "description": "Three-letter alpha-3 country code as defined in the ISO 3166-1 spec." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Address of the beneficiary of this account. Please ensure the address is valid (Google Maps is good for this). US addresses used to receive wires must include a street number." })), "account_owner_country": Schema.optionalKey(Schema.String.annotate({ "description": "Three-letter alpha-3 country of residence of the account owner (ISO 3166-1).", "readOnly": true }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))), "deactivation_reason": Schema.optionalKey(Schema.Literals(["plaid_item_error", "deactivated_due_to_bounceback", "deleted_by_developer", "requested_by_developer", "invalid_account_number", "invalid_bank_validation", "rejected_by_bank_provider"]).annotate({ "description": "Reason for deactivation when this External Account is inactive", "readOnly": true })), "deactivation_details": Schema.optionalKey(Schema.String.annotate({ "description": "Additional details about the deactivation when this External Account is inactive", "readOnly": true })), "pix_key": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "pix_key": Schema.optionalKey(Schema.String.annotate({ "description": "The Pix key for the Brazilian bank account. Must be one of the following formats:\n- **EVP (Virtual Payment Address)**: Random UUID generated by Banco Central do Brasil (e.g., `550e8400-e29b-41d4-a716-446655440000`)\n- **CPF (Tax ID)**: 11-digit individual tax number (e.g., `12345678901`)\n- **CNPJ (Business Tax ID)**: 14-digit business tax number (e.g., `12345678000195`)\n- **Phone**: Brazilian mobile phone in format +55 followed by 11 digits (e.g., `+5511987654321`)\n- **Email**: Valid email address (e.g., `joao.silva@email.com`)\n", "writeOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "document_number": Schema.optionalKey(Schema.String.annotate({ "description": "Optional document number (CPF/CNPJ) associated with the Pix key. Must be all numerals (no punctuation) if provided.", "writeOnly": true })), "account_preview": Schema.String.annotate({ "description": "Masked preview of the Pix key", "readOnly": true }), "document_number_last4": Schema.optionalKey(Schema.String.annotate({ "description": "Last 4 digits of the document number (CPF/CNPJ) when available", "readOnly": true })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "title": "pix_key", "description": "Pix key display info. Returned in GET responses when the account uses a Pix key.", "readOnly": true })), "br_code": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "br_code": Schema.optionalKey(Schema.String.annotate({ "description": "The Copie e cola code for Pix transactions", "writeOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "document_number": Schema.optionalKey(Schema.String.annotate({ "description": "Optional document number (CPF/CNPJ) associated with the Pix key. Must be all numerals (no punctuation) if provided.", "writeOnly": true })), "account_preview": Schema.String.annotate({ "description": "Masked preview of the BR Code", "readOnly": true }), "document_number_last4": Schema.optionalKey(Schema.String.annotate({ "description": "Last 4 digits of the document number (CPF/CNPJ) when available", "readOnly": true })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "title": "br_code", "description": "BR Code display info. Returned in GET responses when the account uses a BR Code.", "readOnly": true })), "account_validation": Schema.optionalKey(Schema.Struct({ "validated_account_owner_name": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Account owner name as returned by the validation provider." })), "validated_bank_name": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Bank name as returned by the validation provider." })), "validated_document_number_last4": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Last 4 characters of the account owner's document number, as returned by the validation provider. Present only for Bre-B (Colombian) accounts.", "readOnly": true })) }).annotate({ "description": "Present for Pix accounts with a successful validation; contains validated owner and bank name.", "readOnly": true })), "account_verification": Schema.optionalKey(Schema.Struct({ "pix": Schema.optionalKey(Schema.Struct({ "matched": Schema.optionalKey(Schema.Union([Schema.Boolean, Schema.Null]).annotate({ "description": "Match result as returned by the validation provider." })), "reason_code": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Additional context from the validation provider." })), "validated_account_owner_name": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Account owner name as returned by the validation provider." })), "validated_bank_name": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Bank name as returned by the validation provider." })) })), "requested_at": Schema.optionalKey(Schema.String.annotate({ "description": "When the verification was requested.", "format": "date-time" })), "completed_at": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "When the verification completed. Null while pending.", "format": "date-time" })) }).annotate({ "title": "Pix", "description": "Present for accounts with a holder verification check; contains the verification result.", "readOnly": true })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "title": "Pix", "description": "Properties shared by all external account types" }), Schema.StructWithRest(Schema.Struct({ "id": Schema.String.annotate({ "description": "A UUID that uniquely identifies a resource", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" })), "customer_id": Schema.String.annotate({ "description": "The id of the Bridge customer that this External Account belongs to", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "created_at": Schema.String.annotate({ "description": "Time of creation of the External Account", "readOnly": true, "format": "date-time" }), "updated_at": Schema.String.annotate({ "description": "Time of last update of the External Account", "readOnly": true, "format": "date-time" }), "account_owner_name": Schema.String.annotate({ "description": "Owner of the account Bank Account (e.g. \"John Doe\"). For ach, wire, and iban accounts, this field must be at least 3 characters, at most 35 characters, and follow the regex pattern for the given account type:\n- ach: `^(?!\\s*$)[\\x20-\\x7E]*$`\n- wire: ```^[ \\w!\"#$%&'()+,\\-./:;<=>?@\\\\_`~]*$```\n- iban: `^(?![:\\- ]*$)[a-zA-Z0-9\\/\\-?:().,'+ _]+$`\n" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" })), "currency": Schema.Literal("gbp").annotate({ "description": "Currency associated with the bank account. Must be `gbp` for GB accounts." }), "account_type": Schema.Literal("gb").annotate({ "description": "Type of the bank account." }), "active": Schema.Boolean.annotate({ "description": "Whether or not this External Account is active", "readOnly": true }), "bank_name": Schema.optionalKey(Schema.String.annotate({ "description": "Bank name of the account (e.g. \"Chase\")" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" }))), "account_owner_type": Schema.optionalKey(Schema.Literals(["individual", "business"]).annotate({ "description": "The type of the account ownership. Required when the `account_type` is `iban`. For `individual` ownership, `first_name` and `last_name` are required. For `business` ownership, `business_name` is required." })), "first_name": Schema.optionalKey(Schema.String.annotate({ "description": "First name of the individual account holder. Required when the `account_owner_type` is `individual`" })), "last_name": Schema.optionalKey(Schema.String.annotate({ "description": "Last name of the individual account holder. Required when the `account_owner_type` is `individual`" })), "business_name": Schema.optionalKey(Schema.String.annotate({ "description": "Business name of the business account holder. Required when the `account_owner_type` is `business`" })), "address": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "street_line_1": Schema.String.check(Schema.isMinLength(4).annotate({ "expected": "a value with a length of at least 4" })).check(Schema.isMaxLength(35).annotate({ "expected": "a value with a length of at most 35" })), "street_line_2": Schema.optionalKey(Schema.String.check(Schema.isMaxLength(35).annotate({ "expected": "a value with a length of at most 35" }))), "city": Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "state": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-2 subdivision code. Must be supplied for US addresses." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "postal_code": Schema.optionalKey(Schema.String.annotate({ "description": "Must be supplied for countries that use postal codes." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "country": Schema.String.annotate({ "description": "Three-letter alpha-3 country code as defined in the ISO 3166-1 spec." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Address of the beneficiary of this account. Please ensure the address is valid (Google Maps is good for this). US addresses used to receive wires must include a street number." })), "account_owner_country": Schema.optionalKey(Schema.String.annotate({ "description": "Three-letter alpha-3 country of residence of the account owner (ISO 3166-1).", "readOnly": true }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))), "deactivation_reason": Schema.optionalKey(Schema.Literals(["plaid_item_error", "deactivated_due_to_bounceback", "deleted_by_developer", "requested_by_developer", "invalid_account_number", "invalid_bank_validation", "rejected_by_bank_provider"]).annotate({ "description": "Reason for deactivation when this External Account is inactive", "readOnly": true })), "deactivation_details": Schema.optionalKey(Schema.String.annotate({ "description": "Additional details about the deactivation when this External Account is inactive", "readOnly": true })), "account": Schema.Struct({ "account_number": Schema.optionalKey(Schema.String.annotate({ "description": "The bank account number", "writeOnly": true }).check(Schema.isMinLength(8).annotate({ "expected": "a value with a length of at least 8" })).check(Schema.isMaxLength(8).annotate({ "expected": "a value with a length of at most 8" }))), "last_4": Schema.String.annotate({ "description": "Last 4 digits of the bank account number", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "sort_code": Schema.String.annotate({ "description": "The sort code, without hyphens" }).check(Schema.isMinLength(6).annotate({ "expected": "a value with a length of at least 6" })).check(Schema.isMaxLength(6).annotate({ "expected": "a value with a length of at most 6" })) }).annotate({ "title": "gb" }), "account_verification": Schema.optionalKey(Schema.Struct({ "gb": Schema.optionalKey(Schema.Struct({ "match_level": Schema.optionalKey(Schema.Literals(["pending", "match", "close_match", "no_match", "error"]).annotate({ "description": "The result of the name match check." })), "reason_code": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Additional context from the receiving bank when the result is not a full match." })), "validated_account_owner_name": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Account owner name as returned by the validation provider." })) })), "requested_at": Schema.optionalKey(Schema.String.annotate({ "description": "When the verification was requested.", "format": "date-time" })), "completed_at": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "When the verification completed. Null while pending.", "format": "date-time" })) }).annotate({ "title": "GB", "description": "Present for accounts with a holder verification check; contains the verification result.", "readOnly": true })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "title": "GB", "description": "Properties shared by all external account types" }), Schema.StructWithRest(Schema.Struct({ "id": Schema.String.annotate({ "description": "A UUID that uniquely identifies a resource", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" })), "customer_id": Schema.String.annotate({ "description": "The id of the Bridge customer that this External Account belongs to", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "created_at": Schema.String.annotate({ "description": "Time of creation of the External Account", "readOnly": true, "format": "date-time" }), "updated_at": Schema.String.annotate({ "description": "Time of last update of the External Account", "readOnly": true, "format": "date-time" }), "account_owner_name": Schema.String.annotate({ "description": "Owner of the account Bank Account (e.g. \"John Doe\"). For ach, wire, and iban accounts, this field must be at least 3 characters, at most 35 characters, and follow the regex pattern for the given account type:\n- ach: `^(?!\\s*$)[\\x20-\\x7E]*$`\n- wire: ```^[ \\w!\"#$%&'()+,\\-./:;<=>?@\\\\_`~]*$```\n- iban: `^(?![:\\- ]*$)[a-zA-Z0-9\\/\\-?:().,'+ _]+$`\n" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" })), "currency": Schema.Literal("cop").annotate({ "description": "Currency associated with the bank account. Must be `cop` for Bre-B accounts." }), "account_type": Schema.Literal("bre_b").annotate({ "description": "Type of the bank account." }), "active": Schema.Boolean.annotate({ "description": "Whether or not this External Account is active", "readOnly": true }), "bank_name": Schema.optionalKey(Schema.String.annotate({ "description": "Bank name of the account (e.g. \"Chase\")" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" }))), "account_owner_type": Schema.optionalKey(Schema.Literals(["individual", "business"]).annotate({ "description": "The type of the account ownership. Required when the `account_type` is `iban`. For `individual` ownership, `first_name` and `last_name` are required. For `business` ownership, `business_name` is required." })), "first_name": Schema.optionalKey(Schema.String.annotate({ "description": "First name of the individual account holder. Required when the `account_owner_type` is `individual`" })), "last_name": Schema.optionalKey(Schema.String.annotate({ "description": "Last name of the individual account holder. Required when the `account_owner_type` is `individual`" })), "business_name": Schema.optionalKey(Schema.String.annotate({ "description": "Business name of the business account holder. Required when the `account_owner_type` is `business`" })), "address": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "street_line_1": Schema.String.check(Schema.isMinLength(4).annotate({ "expected": "a value with a length of at least 4" })).check(Schema.isMaxLength(35).annotate({ "expected": "a value with a length of at most 35" })), "street_line_2": Schema.optionalKey(Schema.String.check(Schema.isMaxLength(35).annotate({ "expected": "a value with a length of at most 35" }))), "city": Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "state": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-2 subdivision code. Must be supplied for US addresses." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "postal_code": Schema.optionalKey(Schema.String.annotate({ "description": "Must be supplied for countries that use postal codes." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "country": Schema.String.annotate({ "description": "Three-letter alpha-3 country code as defined in the ISO 3166-1 spec." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Address of the beneficiary of this account. Please ensure the address is valid (Google Maps is good for this). US addresses used to receive wires must include a street number." })), "account_owner_country": Schema.optionalKey(Schema.String.annotate({ "description": "Three-letter alpha-3 country of residence of the account owner (ISO 3166-1).", "readOnly": true }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))), "deactivation_reason": Schema.optionalKey(Schema.Literals(["plaid_item_error", "deactivated_due_to_bounceback", "deleted_by_developer", "requested_by_developer", "invalid_account_number", "invalid_bank_validation", "rejected_by_bank_provider"]).annotate({ "description": "Reason for deactivation when this External Account is inactive", "readOnly": true })), "deactivation_details": Schema.optionalKey(Schema.String.annotate({ "description": "Additional details about the deactivation when this External Account is inactive", "readOnly": true })), "account": Schema.StructWithRest(Schema.Struct({ "bre_b_key": Schema.optionalKey(Schema.String.annotate({ "description": "The Bre-B key of the Colombian bank account", "writeOnly": true })), "last_4": Schema.String.annotate({ "description": "Last 4 digits of the Bre-B key", "readOnly": true }).check(Schema.isMinLength(4).annotate({ "expected": "a value with a length of at least 4" })).check(Schema.isMaxLength(4).annotate({ "expected": "a value with a length of at most 4" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "title": "bre_b" }), "account_validation": Schema.optionalKey(Schema.Struct({ "validated_account_owner_name": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Account owner name as returned by the validation provider." })), "validated_bank_name": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Bank name as returned by the validation provider." })), "validated_document_number_last4": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Last 4 characters of the account owner's document number, as returned by the validation provider. Present only for Bre-B (Colombian) accounts.", "readOnly": true })) }).annotate({ "description": "Present for Bre-B accounts with a successful validation; contains validated owner and bank name.", "readOnly": true })), "account_verification": Schema.optionalKey(Schema.Struct({ "bre_b": Schema.optionalKey(Schema.Struct({ "matched": Schema.optionalKey(Schema.Union([Schema.Boolean, Schema.Null]).annotate({ "description": "Match result as returned by the validation provider." })), "reason_code": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Additional context from the validation provider." })), "validated_account_owner_name": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Account owner name as returned by the validation provider." })), "validated_bank_name": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Bank name as returned by the validation provider." })), "validated_document_number_last4": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Last 4 characters of the account owner's document number, as returned by the validation provider. Present only for Bre-B (Colombian) accounts.", "readOnly": true })) })), "requested_at": Schema.optionalKey(Schema.String.annotate({ "description": "When the verification was requested.", "format": "date-time" })), "completed_at": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "When the verification completed. Null while pending.", "format": "date-time" })) }).annotate({ "title": "Bre-B", "description": "Present for accounts with a holder verification check; contains the verification result.", "readOnly": true })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "title": "Bre-B", "description": "Properties shared by all external account types" }), Schema.StructWithRest(Schema.Struct({ "id": Schema.String.annotate({ "description": "A UUID that uniquely identifies a resource", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" })), "customer_id": Schema.String.annotate({ "description": "The id of the Bridge customer that this External Account belongs to", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "created_at": Schema.String.annotate({ "description": "Time of creation of the External Account", "readOnly": true, "format": "date-time" }), "updated_at": Schema.String.annotate({ "description": "Time of last update of the External Account", "readOnly": true, "format": "date-time" }), "account_owner_name": Schema.String.annotate({ "description": "Owner of the account Bank Account (e.g. \"John Doe\"). For ach, wire, and iban accounts, this field must be at least 3 characters, at most 35 characters, and follow the regex pattern for the given account type:\n- ach: `^(?!\\s*$)[\\x20-\\x7E]*$`\n- wire: ```^[ \\w!\"#$%&'()+,\\-./:;<=>?@\\\\_`~]*$```\n- iban: `^(?![:\\- ]*$)[a-zA-Z0-9\\/\\-?:().,'+ _]+$`\n" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" })), "currency": Schema.Literal("cop").annotate({ "description": "Currency associated with the bank account. Must be `cop` for CO bank transfer accounts." }), "account_type": Schema.Literal("co_bank_transfer").annotate({ "description": "Type of the bank account." }), "active": Schema.Boolean.annotate({ "description": "Whether or not this External Account is active", "readOnly": true }), "bank_name": Schema.optionalKey(Schema.String.annotate({ "description": "Bank name of the account (e.g. \"Chase\")" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" }))), "account_owner_type": Schema.optionalKey(Schema.Literals(["individual", "business"]).annotate({ "description": "The type of the account ownership. Required when the `account_type` is `iban`. For `individual` ownership, `first_name` and `last_name` are required. For `business` ownership, `business_name` is required." })), "first_name": Schema.optionalKey(Schema.String.annotate({ "description": "First name of the individual account holder. Required when the `account_owner_type` is `individual`" })), "last_name": Schema.optionalKey(Schema.String.annotate({ "description": "Last name of the individual account holder. Required when the `account_owner_type` is `individual`" })), "business_name": Schema.optionalKey(Schema.String.annotate({ "description": "Business name of the business account holder. Required when the `account_owner_type` is `business`" })), "address": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "street_line_1": Schema.String.check(Schema.isMinLength(4).annotate({ "expected": "a value with a length of at least 4" })).check(Schema.isMaxLength(35).annotate({ "expected": "a value with a length of at most 35" })), "street_line_2": Schema.optionalKey(Schema.String.check(Schema.isMaxLength(35).annotate({ "expected": "a value with a length of at most 35" }))), "city": Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "state": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-2 subdivision code. Must be supplied for US addresses." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "postal_code": Schema.optionalKey(Schema.String.annotate({ "description": "Must be supplied for countries that use postal codes." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "country": Schema.String.annotate({ "description": "Three-letter alpha-3 country code as defined in the ISO 3166-1 spec." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Address of the beneficiary of this account. Please ensure the address is valid (Google Maps is good for this). US addresses used to receive wires must include a street number." })), "account_owner_country": Schema.optionalKey(Schema.String.annotate({ "description": "Three-letter alpha-3 country of residence of the account owner (ISO 3166-1).", "readOnly": true }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))), "deactivation_reason": Schema.optionalKey(Schema.Literals(["plaid_item_error", "deactivated_due_to_bounceback", "deleted_by_developer", "requested_by_developer", "invalid_account_number", "invalid_bank_validation", "rejected_by_bank_provider"]).annotate({ "description": "Reason for deactivation when this External Account is inactive", "readOnly": true })), "deactivation_details": Schema.optionalKey(Schema.String.annotate({ "description": "Additional details about the deactivation when this External Account is inactive", "readOnly": true })), "account": Schema.Struct({ "last_4": Schema.optionalKey(Schema.String.annotate({ "description": "Last 4 digits of the account number", "readOnly": true })), "routing_number": Schema.optionalKey(Schema.String.annotate({ "description": "The bank code of the account", "readOnly": true })) }).annotate({ "description": "CO bank transfer account display information. Returned in GET responses." }), "account_verification": Schema.optionalKey(Schema.Struct({ "co_bank_transfer": Schema.optionalKey(Schema.Struct({ "matched": Schema.optionalKey(Schema.Union([Schema.Boolean, Schema.Null]).annotate({ "description": "Match result as returned by the validation provider." })), "reason_code": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Additional context from the validation provider." })), "validated_account_owner_name": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Account owner name as returned by the validation provider." })), "validated_bank_name": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Bank name as returned by the validation provider." })), "validated_document_number_last4": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Last 4 characters of the account owner's document number, as returned by the validation provider. Present only for Bre-B (Colombian) accounts.", "readOnly": true })) })), "requested_at": Schema.optionalKey(Schema.String.annotate({ "description": "When the verification was requested.", "format": "date-time" })), "completed_at": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "When the verification completed. Null while pending.", "format": "date-time" })) }).annotate({ "title": "CO Bank Transfer", "description": "Present for accounts with a holder verification check; contains the verification result.", "readOnly": true })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "title": "CO Bank Transfer", "description": "Properties shared by all external account types" })], { mode: "oneOf" }).annotate({ "identifier": "ExternalAccountResponse" }) +export type CreateExternalAccountInput = { readonly "id"?: string, readonly "customer_id"?: string, readonly "bank_name"?: string, readonly "account_owner_name": string, readonly "created_at"?: string, readonly "updated_at"?: string, readonly "active"?: boolean, readonly "address": { readonly "street_line_1": string, readonly "street_line_2"?: string, readonly "city": string, readonly "state"?: string, readonly "postal_code"?: string, readonly "country": string } & { readonly [x: string]: Schema.Json }, readonly "deactivation_reason"?: "plaid_item_error" | "deactivated_due_to_bounceback" | "deleted_by_developer" | "requested_by_developer" | "invalid_account_number" | "invalid_bank_validation" | "rejected_by_bank_provider", readonly "deactivation_details"?: string, readonly "account_type": "us", readonly "currency": "usd", readonly "account": { readonly "account_number": string, readonly "routing_number": string, readonly "last_4"?: string, readonly "checking_or_savings"?: "checking" | "savings" } & { readonly [x: string]: Schema.Json }, readonly "account_number"?: string, readonly "routing_number"?: string } & { readonly [x: string]: Schema.Json } | { readonly "id"?: string, readonly "customer_id"?: string, readonly "bank_name"?: string, readonly "account_owner_name": string, readonly "created_at"?: string, readonly "updated_at"?: string, readonly "active"?: boolean, readonly "account_owner_type"?: "individual" | "business", readonly "first_name"?: string, readonly "last_name"?: string, readonly "business_name"?: string, readonly "address"?: { readonly "street_line_1": string, readonly "street_line_2"?: string, readonly "city": string, readonly "state"?: string, readonly "postal_code"?: string, readonly "country": string } & { readonly [x: string]: Schema.Json }, readonly "account_owner_country"?: string, readonly "deactivation_reason"?: "plaid_item_error" | "deactivated_due_to_bounceback" | "deleted_by_developer" | "requested_by_developer" | "invalid_account_number" | "invalid_bank_validation" | "rejected_by_bank_provider", readonly "deactivation_details"?: string, readonly "account_type": "iban", readonly "currency": "eur", readonly "iban": { readonly "account_number": string, readonly "bic"?: string, readonly "country": string, readonly "last_4"?: string } & { readonly [x: string]: Schema.Json } } & { readonly [x: string]: Schema.Json } | { readonly "id"?: string, readonly "customer_id"?: string, readonly "bank_name"?: string, readonly "account_owner_name": string, readonly "created_at"?: string, readonly "updated_at"?: string, readonly "active"?: boolean, readonly "address"?: { readonly "street_line_1": string, readonly "street_line_2"?: string, readonly "city": string, readonly "state"?: string, readonly "postal_code"?: string, readonly "country": string } & { readonly [x: string]: Schema.Json }, readonly "deactivation_reason"?: "plaid_item_error" | "deactivated_due_to_bounceback" | "deleted_by_developer" | "requested_by_developer" | "invalid_account_number" | "invalid_bank_validation" | "rejected_by_bank_provider", readonly "deactivation_details"?: string, readonly "account_type": "clabe", readonly "currency": "mxn", readonly "clabe": { readonly "account_number": string, readonly "last_4"?: string } & { readonly [x: string]: Schema.Json } } & { readonly [x: string]: Schema.Json } | { readonly "id"?: string, readonly "customer_id"?: string, readonly "bank_name"?: string, readonly "account_owner_name": string, readonly "created_at"?: string, readonly "updated_at"?: string, readonly "active"?: boolean, readonly "address"?: { readonly "street_line_1": string, readonly "street_line_2"?: string, readonly "city": string, readonly "state"?: string, readonly "postal_code"?: string, readonly "country": string } & { readonly [x: string]: Schema.Json }, readonly "deactivation_reason"?: "plaid_item_error" | "deactivated_due_to_bounceback" | "deleted_by_developer" | "requested_by_developer" | "invalid_account_number" | "invalid_bank_validation" | "rejected_by_bank_provider", readonly "deactivation_details"?: string, readonly "currency": "brl", readonly "account_type": "pix", readonly "pix_key": { readonly "pix_key": string, readonly "document_number"?: string, readonly "account_preview"?: string, readonly "document_number_last4"?: string } & { readonly [x: string]: Schema.Json } } & { readonly [x: string]: Schema.Json } | { readonly "id"?: string, readonly "customer_id"?: string, readonly "bank_name"?: string, readonly "account_owner_name": string, readonly "created_at"?: string, readonly "updated_at"?: string, readonly "active"?: boolean, readonly "address"?: { readonly "street_line_1": string, readonly "street_line_2"?: string, readonly "city": string, readonly "state"?: string, readonly "postal_code"?: string, readonly "country": string } & { readonly [x: string]: Schema.Json }, readonly "deactivation_reason"?: "plaid_item_error" | "deactivated_due_to_bounceback" | "deleted_by_developer" | "requested_by_developer" | "invalid_account_number" | "invalid_bank_validation" | "rejected_by_bank_provider", readonly "deactivation_details"?: string, readonly "currency": "brl", readonly "account_type": "pix", readonly "br_code": { readonly "br_code": string, readonly "document_number"?: string, readonly "account_preview"?: string, readonly "document_number_last4"?: string } & { readonly [x: string]: Schema.Json } } & { readonly [x: string]: Schema.Json } | { readonly "id"?: string, readonly "customer_id"?: string, readonly "bank_name"?: string, readonly "account_owner_name": string, readonly "created_at"?: string, readonly "updated_at"?: string, readonly "active"?: boolean, readonly "account_owner_type"?: "individual" | "business", readonly "first_name"?: string, readonly "last_name"?: string, readonly "business_name"?: string, readonly "address"?: { readonly "street_line_1": string, readonly "street_line_2"?: string, readonly "city": string, readonly "state"?: string, readonly "postal_code"?: string, readonly "country": string } & { readonly [x: string]: Schema.Json }, readonly "account_owner_country"?: string, readonly "deactivation_reason"?: "plaid_item_error" | "deactivated_due_to_bounceback" | "deleted_by_developer" | "requested_by_developer" | "invalid_account_number" | "invalid_bank_validation" | "rejected_by_bank_provider", readonly "deactivation_details"?: string, readonly "account_type": "gb", readonly "currency": "gbp", readonly "account": { readonly "account_number": string, readonly "last_4"?: string, readonly "sort_code": string } } & { readonly [x: string]: Schema.Json } | { readonly "id"?: string, readonly "customer_id"?: string, readonly "bank_name"?: string, readonly "account_owner_name": string, readonly "created_at"?: string, readonly "updated_at"?: string, readonly "active"?: boolean, readonly "address"?: { readonly "street_line_1": string, readonly "street_line_2"?: string, readonly "city": string, readonly "state"?: string, readonly "postal_code"?: string, readonly "country": string } & { readonly [x: string]: Schema.Json }, readonly "deactivation_reason"?: "plaid_item_error" | "deactivated_due_to_bounceback" | "deleted_by_developer" | "requested_by_developer" | "invalid_account_number" | "invalid_bank_validation" | "rejected_by_bank_provider", readonly "deactivation_details"?: string, readonly "currency": "cop", readonly "account_type": "bre_b", readonly "account": { readonly "bre_b_key": string, readonly "last_4"?: string } & { readonly [x: string]: Schema.Json } } & { readonly [x: string]: Schema.Json } | { readonly "id"?: string, readonly "customer_id"?: string, readonly "bank_name"?: string, readonly "account_owner_name": string, readonly "created_at"?: string, readonly "updated_at"?: string, readonly "active"?: boolean, readonly "account_owner_type"?: "individual" | "business", readonly "first_name"?: string, readonly "last_name"?: string, readonly "business_name"?: string, readonly "address"?: { readonly "street_line_1": string, readonly "street_line_2"?: string, readonly "city": string, readonly "state"?: string, readonly "postal_code"?: string, readonly "country": string } & { readonly [x: string]: Schema.Json }, readonly "account_owner_country"?: string, readonly "deactivation_reason"?: "plaid_item_error" | "deactivated_due_to_bounceback" | "deleted_by_developer" | "requested_by_developer" | "invalid_account_number" | "invalid_bank_validation" | "rejected_by_bank_provider", readonly "deactivation_details"?: string, readonly "currency": "cop", readonly "account_type": "co_bank_transfer", readonly "account": { readonly "account_number": string, readonly "bank_code": "1001" | "1002" | "1006" | "1007" | "1009" | "1012" | "1013" | "1019" | "1023" | "1032" | "1040" | "1047" | "1051" | "1052" | "1053" | "1059" | "1060" | "1061" | "1062" | "1063" | "1065" | "1066" | "1067" | "1069" | "1070" | "1071" | "1097" | "1121" | "1283" | "1286" | "1289" | "1292" | "1303" | "1370" | "1507" | "1551" | "1558" | "1637" | "1801" | "1802" | "1803" | "1804" | "1805" | "1808" | "1809" | "1811" | "1812" | "1814" | "1815" | "1816", readonly "account_type": "checking" | "savings" | "electronic_deposit", readonly "document_type": "cc" | "ce" | "nit" | "rut" | "pa" | "ppt" | "ti" | "rc" | "te" | "die" | "nd", readonly "document_number": string, readonly "phone_number": string, readonly "last_4"?: string, readonly "routing_number"?: string } & { readonly [x: string]: Schema.Json } } & { readonly [x: string]: Schema.Json } +export const CreateExternalAccountInput = Schema.Union([Schema.StructWithRest(Schema.Struct({ "id": Schema.optionalKey(Schema.String.annotate({ "description": "A UUID that uniquely identifies a resource", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "customer_id": Schema.optionalKey(Schema.String.annotate({ "description": "The id of the Bridge customer that this External Account belongs to", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "bank_name": Schema.optionalKey(Schema.String.annotate({ "description": "Bank name of the account" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" }))), "account_owner_name": Schema.String.annotate({ "description": "Owner of the bank account" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" })), "created_at": Schema.optionalKey(Schema.String.annotate({ "description": "Time of creation of the External Account", "readOnly": true, "format": "date-time" })), "updated_at": Schema.optionalKey(Schema.String.annotate({ "description": "Time of last update of the External Account", "readOnly": true, "format": "date-time" })), "active": Schema.optionalKey(Schema.Boolean.annotate({ "description": "Whether or not this External Account is active", "readOnly": true })), "address": Schema.StructWithRest(Schema.Struct({ "street_line_1": Schema.String.check(Schema.isMinLength(4).annotate({ "expected": "a value with a length of at least 4" })).check(Schema.isMaxLength(35).annotate({ "expected": "a value with a length of at most 35" })), "street_line_2": Schema.optionalKey(Schema.String.check(Schema.isMaxLength(35).annotate({ "expected": "a value with a length of at most 35" }))), "city": Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "state": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-2 subdivision code. Must be supplied for US addresses." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "postal_code": Schema.optionalKey(Schema.String.annotate({ "description": "Must be supplied for countries that use postal codes." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "country": Schema.String.annotate({ "description": "Three-letter alpha-3 country code as defined in the ISO 3166-1 spec." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Address of the beneficiary of this account.", "writeOnly": true }), "deactivation_reason": Schema.optionalKey(Schema.Literals(["plaid_item_error", "deactivated_due_to_bounceback", "deleted_by_developer", "requested_by_developer", "invalid_account_number", "invalid_bank_validation", "rejected_by_bank_provider"]).annotate({ "description": "Reason for deactivation when this External Account is inactive", "readOnly": true })), "deactivation_details": Schema.optionalKey(Schema.String.annotate({ "description": "Additional details about the deactivation when this External Account is inactive", "readOnly": true })), "account_type": Schema.Literal("us").annotate({ "description": "Type of the bank account." }), "currency": Schema.Literal("usd").annotate({ "description": "Currency associated with the bank account. Must be `usd` for US accounts." }), "account": Schema.StructWithRest(Schema.Struct({ "account_number": Schema.String.annotate({ "description": "The bank account number", "writeOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "routing_number": Schema.String.annotate({ "description": "The bank routing number" }).check(Schema.isMinLength(9).annotate({ "expected": "a value with a length of at least 9" })).check(Schema.isMaxLength(9).annotate({ "expected": "a value with a length of at most 9" })), "last_4": Schema.optionalKey(Schema.String.annotate({ "description": "Last 4 digits of the bank account number", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "checking_or_savings": Schema.optionalKey(Schema.Literals(["checking", "savings"]).annotate({ "description": "Determines whether the US account is treated as checking or savings. All US accounts will be treated as checking by default." })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "title": "us" }), "account_number": Schema.optionalKey(Schema.String.annotate({ "description": "Account number of your bank account. This field is getting deprecated in favor of the `account.account_number` field for US accounts.", "writeOnly": true }).check(Schema.isMinLength(12).annotate({ "expected": "a value with a length of at least 12" }))), "routing_number": Schema.optionalKey(Schema.String.annotate({ "description": "Routing number of your bank account. This field is getting deprecated in favor of the `account.routing_number` field for US accounts.", "writeOnly": true }).check(Schema.isMinLength(9).annotate({ "expected": "a value with a length of at least 9" }))) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "title": "ACH/Wire", "description": "Request body for creating an external account." }), Schema.StructWithRest(Schema.Struct({ "id": Schema.optionalKey(Schema.String.annotate({ "description": "A UUID that uniquely identifies a resource", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "customer_id": Schema.optionalKey(Schema.String.annotate({ "description": "The id of the Bridge customer that this External Account belongs to", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "bank_name": Schema.optionalKey(Schema.String.annotate({ "description": "Bank name of the account (e.g. \"Chase\")" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" }))), "account_owner_name": Schema.String.annotate({ "description": "Owner of the account Bank Account (e.g. \"John Doe\"). For ach, wire, and iban accounts, this field must be at least 3 characters, at most 35 characters, and follow the regex pattern for the given account type:\n- ach: `^(?!\\s*$)[\\x20-\\x7E]*$`\n- wire: ```^[ \\w!\"#$%&'()+,\\-./:;<=>?@\\\\_`~]*$```\n- iban: `^(?![:\\- ]*$)[a-zA-Z0-9\\/\\-?:().,'+ _]+$`\n" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" })), "created_at": Schema.optionalKey(Schema.String.annotate({ "description": "Time of creation of the External Account", "readOnly": true, "format": "date-time" })), "updated_at": Schema.optionalKey(Schema.String.annotate({ "description": "Time of last update of the External Account", "readOnly": true, "format": "date-time" })), "active": Schema.optionalKey(Schema.Boolean.annotate({ "description": "Whether or not this External Account is active", "readOnly": true })), "account_owner_type": Schema.optionalKey(Schema.Literals(["individual", "business"]).annotate({ "description": "The type of the account ownership. Required when the `account_type` is `iban`. For `individual` ownership, `first_name` and `last_name` are required. For `business` ownership, `business_name` is required." })), "first_name": Schema.optionalKey(Schema.String.annotate({ "description": "First name of the individual account holder. Required when the `account_owner_type` is `individual`" })), "last_name": Schema.optionalKey(Schema.String.annotate({ "description": "Last name of the individual account holder. Required when the `account_owner_type` is `individual`" })), "business_name": Schema.optionalKey(Schema.String.annotate({ "description": "Business name of the business account holder. Required when the `account_owner_type` is `business`" })), "address": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "street_line_1": Schema.String.check(Schema.isMinLength(4).annotate({ "expected": "a value with a length of at least 4" })).check(Schema.isMaxLength(35).annotate({ "expected": "a value with a length of at most 35" })), "street_line_2": Schema.optionalKey(Schema.String.check(Schema.isMaxLength(35).annotate({ "expected": "a value with a length of at most 35" }))), "city": Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "state": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-2 subdivision code. Must be supplied for US addresses." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "postal_code": Schema.optionalKey(Schema.String.annotate({ "description": "Must be supplied for countries that use postal codes." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "country": Schema.String.annotate({ "description": "Three-letter alpha-3 country code as defined in the ISO 3166-1 spec." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Address of the beneficiary of this account. Please ensure the address is valid (Google Maps is good for this). US addresses used to receive wires must include a street number." })), "account_owner_country": Schema.optionalKey(Schema.String.annotate({ "description": "Three-letter alpha-3 country of residence of the account owner (ISO 3166-1).", "readOnly": true }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))), "deactivation_reason": Schema.optionalKey(Schema.Literals(["plaid_item_error", "deactivated_due_to_bounceback", "deleted_by_developer", "requested_by_developer", "invalid_account_number", "invalid_bank_validation", "rejected_by_bank_provider"]).annotate({ "description": "Reason for deactivation when this External Account is inactive", "readOnly": true })), "deactivation_details": Schema.optionalKey(Schema.String.annotate({ "description": "Additional details about the deactivation when this External Account is inactive", "readOnly": true })), "account_type": Schema.Literal("iban").annotate({ "description": "Type of the bank account." }), "currency": Schema.Literal("eur").annotate({ "description": "Currency associated with the bank account. Must be `eur` for IBAN accounts." }), "iban": Schema.StructWithRest(Schema.Struct({ "account_number": Schema.String.annotate({ "description": "The International Bank Account Number (IBAN) that will be used to send the funds", "writeOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "bic": Schema.optionalKey(Schema.String.annotate({ "description": "The Bank Identifier Code (BIC/SWIFT code) associated with the beneficiary bank.\nWhile not strictly required for IBAN-based payments, providing the BIC may improve\npayment success rates.\n" }).check(Schema.isMinLength(8).annotate({ "expected": "a value with a length of at least 8" })).check(Schema.isMaxLength(11).annotate({ "expected": "a value with a length of at most 11" })).check(Schema.isPattern(new RegExp("^[A-Za-z]{4}[A-Za-z]{2}[A-Za-z0-9]{2}([A-Za-z0-9]{3})?$")).annotate({ "expected": "a string matching the RegExp ^[A-Za-z]{4}[A-Za-z]{2}[A-Za-z0-9]{2}([A-Za-z0-9]{3})?$" }))), "country": Schema.String.annotate({ "description": "Country in which the bank account is located. It's a three-letter alpha-3 country code as defined in the ISO 3166-1 spec." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" })), "last_4": Schema.optionalKey(Schema.String.annotate({ "description": "Last 4 digits of the bank account number", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "title": "IBAN", "description": "Request body for creating an external account." }), Schema.StructWithRest(Schema.Struct({ "id": Schema.optionalKey(Schema.String.annotate({ "description": "A UUID that uniquely identifies a resource", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "customer_id": Schema.optionalKey(Schema.String.annotate({ "description": "The id of the Bridge customer that this External Account belongs to", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "bank_name": Schema.optionalKey(Schema.String.annotate({ "description": "Bank name of the account" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" }))), "account_owner_name": Schema.String.annotate({ "description": "Owner of the bank account" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" })), "created_at": Schema.optionalKey(Schema.String.annotate({ "description": "Time of creation of the External Account", "readOnly": true, "format": "date-time" })), "updated_at": Schema.optionalKey(Schema.String.annotate({ "description": "Time of last update of the External Account", "readOnly": true, "format": "date-time" })), "active": Schema.optionalKey(Schema.Boolean.annotate({ "description": "Whether or not this External Account is active", "readOnly": true })), "address": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "street_line_1": Schema.String.check(Schema.isMinLength(4).annotate({ "expected": "a value with a length of at least 4" })).check(Schema.isMaxLength(35).annotate({ "expected": "a value with a length of at most 35" })), "street_line_2": Schema.optionalKey(Schema.String.check(Schema.isMaxLength(35).annotate({ "expected": "a value with a length of at most 35" }))), "city": Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "state": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-2 subdivision code. Must be supplied for US addresses." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "postal_code": Schema.optionalKey(Schema.String.annotate({ "description": "Must be supplied for countries that use postal codes." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "country": Schema.String.annotate({ "description": "Three-letter alpha-3 country code as defined in the ISO 3166-1 spec." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Address of the beneficiary of this account.", "writeOnly": true })), "deactivation_reason": Schema.optionalKey(Schema.Literals(["plaid_item_error", "deactivated_due_to_bounceback", "deleted_by_developer", "requested_by_developer", "invalid_account_number", "invalid_bank_validation", "rejected_by_bank_provider"]).annotate({ "description": "Reason for deactivation when this External Account is inactive", "readOnly": true })), "deactivation_details": Schema.optionalKey(Schema.String.annotate({ "description": "Additional details about the deactivation when this External Account is inactive", "readOnly": true })), "account_type": Schema.Literal("clabe").annotate({ "description": "Type of the bank account." }), "currency": Schema.Literal("mxn").annotate({ "description": "Currency associated with the bank account. Must be `mxn` for CLABE (SPEI) accounts." }), "clabe": Schema.StructWithRest(Schema.Struct({ "account_number": Schema.String.annotate({ "description": "The CLABE account number of the bank account", "writeOnly": true }).check(Schema.isMinLength(18).annotate({ "expected": "a value with a length of at least 18" })).check(Schema.isMaxLength(18).annotate({ "expected": "a value with a length of at most 18" })), "last_4": Schema.optionalKey(Schema.String.annotate({ "description": "Last 4 digits of the CLABE", "readOnly": true }).check(Schema.isMinLength(4).annotate({ "expected": "a value with a length of at least 4" })).check(Schema.isMaxLength(4).annotate({ "expected": "a value with a length of at most 4" }))) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "title": "CLABE", "description": "Request body for creating an external account." }), Schema.StructWithRest(Schema.Struct({ "id": Schema.optionalKey(Schema.String.annotate({ "description": "A UUID that uniquely identifies a resource", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "customer_id": Schema.optionalKey(Schema.String.annotate({ "description": "The id of the Bridge customer that this External Account belongs to", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "bank_name": Schema.optionalKey(Schema.String.annotate({ "description": "Bank name of the account" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" }))), "account_owner_name": Schema.String.annotate({ "description": "Owner of the bank account" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" })), "created_at": Schema.optionalKey(Schema.String.annotate({ "description": "Time of creation of the External Account", "readOnly": true, "format": "date-time" })), "updated_at": Schema.optionalKey(Schema.String.annotate({ "description": "Time of last update of the External Account", "readOnly": true, "format": "date-time" })), "active": Schema.optionalKey(Schema.Boolean.annotate({ "description": "Whether or not this External Account is active", "readOnly": true })), "address": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "street_line_1": Schema.String.check(Schema.isMinLength(4).annotate({ "expected": "a value with a length of at least 4" })).check(Schema.isMaxLength(35).annotate({ "expected": "a value with a length of at most 35" })), "street_line_2": Schema.optionalKey(Schema.String.check(Schema.isMaxLength(35).annotate({ "expected": "a value with a length of at most 35" }))), "city": Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "state": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-2 subdivision code. Must be supplied for US addresses." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "postal_code": Schema.optionalKey(Schema.String.annotate({ "description": "Must be supplied for countries that use postal codes." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "country": Schema.String.annotate({ "description": "Three-letter alpha-3 country code as defined in the ISO 3166-1 spec." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Address of the beneficiary of this account.", "writeOnly": true })), "deactivation_reason": Schema.optionalKey(Schema.Literals(["plaid_item_error", "deactivated_due_to_bounceback", "deleted_by_developer", "requested_by_developer", "invalid_account_number", "invalid_bank_validation", "rejected_by_bank_provider"]).annotate({ "description": "Reason for deactivation when this External Account is inactive", "readOnly": true })), "deactivation_details": Schema.optionalKey(Schema.String.annotate({ "description": "Additional details about the deactivation when this External Account is inactive", "readOnly": true })), "currency": Schema.Literal("brl").annotate({ "description": "Currency associated with the bank account. Must be `brl` for Pix accounts." }), "account_type": Schema.Literal("pix").annotate({ "description": "Type of the bank account." }), "pix_key": Schema.StructWithRest(Schema.Struct({ "pix_key": Schema.String.annotate({ "description": "The Pix key for the Brazilian bank account. Must be one of the following formats:\n- **EVP (Virtual Payment Address)**: Random UUID generated by Banco Central do Brasil (e.g., `550e8400-e29b-41d4-a716-446655440000`)\n- **CPF (Tax ID)**: 11-digit individual tax number (e.g., `12345678901`)\n- **CNPJ (Business Tax ID)**: 14-digit business tax number (e.g., `12345678000195`)\n- **Phone**: Brazilian mobile phone in format +55 followed by 11 digits (e.g., `+5511987654321`)\n- **Email**: Valid email address (e.g., `joao.silva@email.com`)\n", "writeOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "document_number": Schema.optionalKey(Schema.String.annotate({ "description": "Optional document number (CPF/CNPJ) associated with the Pix key. Must be all numerals (no punctuation) if provided.", "writeOnly": true })), "account_preview": Schema.optionalKey(Schema.String.annotate({ "description": "Masked preview of the Pix key", "readOnly": true })), "document_number_last4": Schema.optionalKey(Schema.String.annotate({ "description": "Last 4 digits of the document number (CPF/CNPJ) when available", "readOnly": true })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "title": "pix_key", "description": "Brazilian Pix key bank account information. Required when account type is `pix` and using a Pix key.", "writeOnly": true }) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "title": "Pix (Pix Key)", "description": "Request body for creating an external account." }), Schema.StructWithRest(Schema.Struct({ "id": Schema.optionalKey(Schema.String.annotate({ "description": "A UUID that uniquely identifies a resource", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "customer_id": Schema.optionalKey(Schema.String.annotate({ "description": "The id of the Bridge customer that this External Account belongs to", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "bank_name": Schema.optionalKey(Schema.String.annotate({ "description": "Bank name of the account" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" }))), "account_owner_name": Schema.String.annotate({ "description": "Owner of the bank account" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" })), "created_at": Schema.optionalKey(Schema.String.annotate({ "description": "Time of creation of the External Account", "readOnly": true, "format": "date-time" })), "updated_at": Schema.optionalKey(Schema.String.annotate({ "description": "Time of last update of the External Account", "readOnly": true, "format": "date-time" })), "active": Schema.optionalKey(Schema.Boolean.annotate({ "description": "Whether or not this External Account is active", "readOnly": true })), "address": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "street_line_1": Schema.String.check(Schema.isMinLength(4).annotate({ "expected": "a value with a length of at least 4" })).check(Schema.isMaxLength(35).annotate({ "expected": "a value with a length of at most 35" })), "street_line_2": Schema.optionalKey(Schema.String.check(Schema.isMaxLength(35).annotate({ "expected": "a value with a length of at most 35" }))), "city": Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "state": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-2 subdivision code. Must be supplied for US addresses." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "postal_code": Schema.optionalKey(Schema.String.annotate({ "description": "Must be supplied for countries that use postal codes." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "country": Schema.String.annotate({ "description": "Three-letter alpha-3 country code as defined in the ISO 3166-1 spec." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Address of the beneficiary of this account.", "writeOnly": true })), "deactivation_reason": Schema.optionalKey(Schema.Literals(["plaid_item_error", "deactivated_due_to_bounceback", "deleted_by_developer", "requested_by_developer", "invalid_account_number", "invalid_bank_validation", "rejected_by_bank_provider"]).annotate({ "description": "Reason for deactivation when this External Account is inactive", "readOnly": true })), "deactivation_details": Schema.optionalKey(Schema.String.annotate({ "description": "Additional details about the deactivation when this External Account is inactive", "readOnly": true })), "currency": Schema.Literal("brl").annotate({ "description": "Currency associated with the bank account. Must be `brl` for Pix accounts." }), "account_type": Schema.Literal("pix").annotate({ "description": "Type of the bank account." }), "br_code": Schema.StructWithRest(Schema.Struct({ "br_code": Schema.String.annotate({ "description": "The Copie e cola code for Pix transactions", "writeOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "document_number": Schema.optionalKey(Schema.String.annotate({ "description": "Optional document number (CPF/CNPJ) associated with the Pix key. Must be all numerals (no punctuation) if provided.", "writeOnly": true })), "account_preview": Schema.optionalKey(Schema.String.annotate({ "description": "Masked preview of the BR Code", "readOnly": true })), "document_number_last4": Schema.optionalKey(Schema.String.annotate({ "description": "Last 4 digits of the document number (CPF/CNPJ) when available", "readOnly": true })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "title": "br_code", "description": "Brazilian BR Code (Copie e cola) bank account information. Required when account type is `pix` and using a BR Code.", "writeOnly": true }) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "title": "Pix (BR Code)", "description": "Request body for creating an external account." }), Schema.StructWithRest(Schema.Struct({ "id": Schema.optionalKey(Schema.String.annotate({ "description": "A UUID that uniquely identifies a resource", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "customer_id": Schema.optionalKey(Schema.String.annotate({ "description": "The id of the Bridge customer that this External Account belongs to", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "bank_name": Schema.optionalKey(Schema.String.annotate({ "description": "Bank name of the account (e.g. \"Chase\")" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" }))), "account_owner_name": Schema.String.annotate({ "description": "Owner of the account Bank Account (e.g. \"John Doe\"). For ach, wire, and iban accounts, this field must be at least 3 characters, at most 35 characters, and follow the regex pattern for the given account type:\n- ach: `^(?!\\s*$)[\\x20-\\x7E]*$`\n- wire: ```^[ \\w!\"#$%&'()+,\\-./:;<=>?@\\\\_`~]*$```\n- iban: `^(?![:\\- ]*$)[a-zA-Z0-9\\/\\-?:().,'+ _]+$`\n" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" })), "created_at": Schema.optionalKey(Schema.String.annotate({ "description": "Time of creation of the External Account", "readOnly": true, "format": "date-time" })), "updated_at": Schema.optionalKey(Schema.String.annotate({ "description": "Time of last update of the External Account", "readOnly": true, "format": "date-time" })), "active": Schema.optionalKey(Schema.Boolean.annotate({ "description": "Whether or not this External Account is active", "readOnly": true })), "account_owner_type": Schema.optionalKey(Schema.Literals(["individual", "business"]).annotate({ "description": "The type of the account ownership. Required when the `account_type` is `iban`. For `individual` ownership, `first_name` and `last_name` are required. For `business` ownership, `business_name` is required." })), "first_name": Schema.optionalKey(Schema.String.annotate({ "description": "First name of the individual account holder. Required when the `account_owner_type` is `individual`" })), "last_name": Schema.optionalKey(Schema.String.annotate({ "description": "Last name of the individual account holder. Required when the `account_owner_type` is `individual`" })), "business_name": Schema.optionalKey(Schema.String.annotate({ "description": "Business name of the business account holder. Required when the `account_owner_type` is `business`" })), "address": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "street_line_1": Schema.String.check(Schema.isMinLength(4).annotate({ "expected": "a value with a length of at least 4" })).check(Schema.isMaxLength(35).annotate({ "expected": "a value with a length of at most 35" })), "street_line_2": Schema.optionalKey(Schema.String.check(Schema.isMaxLength(35).annotate({ "expected": "a value with a length of at most 35" }))), "city": Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "state": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-2 subdivision code. Must be supplied for US addresses." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "postal_code": Schema.optionalKey(Schema.String.annotate({ "description": "Must be supplied for countries that use postal codes." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "country": Schema.String.annotate({ "description": "Three-letter alpha-3 country code as defined in the ISO 3166-1 spec." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Address of the beneficiary of this account. Please ensure the address is valid (Google Maps is good for this). US addresses used to receive wires must include a street number." })), "account_owner_country": Schema.optionalKey(Schema.String.annotate({ "description": "Three-letter alpha-3 country of residence of the account owner (ISO 3166-1).", "readOnly": true }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))), "deactivation_reason": Schema.optionalKey(Schema.Literals(["plaid_item_error", "deactivated_due_to_bounceback", "deleted_by_developer", "requested_by_developer", "invalid_account_number", "invalid_bank_validation", "rejected_by_bank_provider"]).annotate({ "description": "Reason for deactivation when this External Account is inactive", "readOnly": true })), "deactivation_details": Schema.optionalKey(Schema.String.annotate({ "description": "Additional details about the deactivation when this External Account is inactive", "readOnly": true })), "account_type": Schema.Literal("gb").annotate({ "description": "Type of the bank account." }), "currency": Schema.Literal("gbp").annotate({ "description": "Currency associated with the bank account. Must be `gbp` for GB accounts." }), "account": Schema.Struct({ "account_number": Schema.String.annotate({ "description": "The bank account number", "writeOnly": true }).check(Schema.isMinLength(8).annotate({ "expected": "a value with a length of at least 8" })).check(Schema.isMaxLength(8).annotate({ "expected": "a value with a length of at most 8" })), "last_4": Schema.optionalKey(Schema.String.annotate({ "description": "Last 4 digits of the bank account number", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "sort_code": Schema.String.annotate({ "description": "The sort code, without hyphens" }).check(Schema.isMinLength(6).annotate({ "expected": "a value with a length of at least 6" })).check(Schema.isMaxLength(6).annotate({ "expected": "a value with a length of at most 6" })) }).annotate({ "title": "gb" }) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "title": "FPS", "description": "Request body for creating an external account." }), Schema.StructWithRest(Schema.Struct({ "id": Schema.optionalKey(Schema.String.annotate({ "description": "A UUID that uniquely identifies a resource", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "customer_id": Schema.optionalKey(Schema.String.annotate({ "description": "The id of the Bridge customer that this External Account belongs to", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "bank_name": Schema.optionalKey(Schema.String.annotate({ "description": "Bank name of the account" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" }))), "account_owner_name": Schema.String.annotate({ "description": "Owner of the bank account" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" })), "created_at": Schema.optionalKey(Schema.String.annotate({ "description": "Time of creation of the External Account", "readOnly": true, "format": "date-time" })), "updated_at": Schema.optionalKey(Schema.String.annotate({ "description": "Time of last update of the External Account", "readOnly": true, "format": "date-time" })), "active": Schema.optionalKey(Schema.Boolean.annotate({ "description": "Whether or not this External Account is active", "readOnly": true })), "address": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "street_line_1": Schema.String.check(Schema.isMinLength(4).annotate({ "expected": "a value with a length of at least 4" })).check(Schema.isMaxLength(35).annotate({ "expected": "a value with a length of at most 35" })), "street_line_2": Schema.optionalKey(Schema.String.check(Schema.isMaxLength(35).annotate({ "expected": "a value with a length of at most 35" }))), "city": Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "state": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-2 subdivision code. Must be supplied for US addresses." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "postal_code": Schema.optionalKey(Schema.String.annotate({ "description": "Must be supplied for countries that use postal codes." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "country": Schema.String.annotate({ "description": "Three-letter alpha-3 country code as defined in the ISO 3166-1 spec." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Address of the beneficiary of this account.", "writeOnly": true })), "deactivation_reason": Schema.optionalKey(Schema.Literals(["plaid_item_error", "deactivated_due_to_bounceback", "deleted_by_developer", "requested_by_developer", "invalid_account_number", "invalid_bank_validation", "rejected_by_bank_provider"]).annotate({ "description": "Reason for deactivation when this External Account is inactive", "readOnly": true })), "deactivation_details": Schema.optionalKey(Schema.String.annotate({ "description": "Additional details about the deactivation when this External Account is inactive", "readOnly": true })), "currency": Schema.Literal("cop").annotate({ "description": "Currency associated with the bank account. Must be `cop` for Bre-B accounts." }), "account_type": Schema.Literal("bre_b").annotate({ "description": "Type of the bank account." }), "account": Schema.StructWithRest(Schema.Struct({ "bre_b_key": Schema.String.annotate({ "description": "The Bre-B key of the Colombian bank account", "writeOnly": true }), "last_4": Schema.optionalKey(Schema.String.annotate({ "description": "Last 4 digits of the Bre-B key", "readOnly": true }).check(Schema.isMinLength(4).annotate({ "expected": "a value with a length of at least 4" })).check(Schema.isMaxLength(4).annotate({ "expected": "a value with a length of at most 4" }))) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "title": "bre_b", "description": "Colombian Bre-B bank account information. Required when account type is `bre_b`.", "writeOnly": true }) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "title": "Bre-B", "description": "Request body for creating an external account." }), Schema.StructWithRest(Schema.Struct({ "id": Schema.optionalKey(Schema.String.annotate({ "description": "A UUID that uniquely identifies a resource", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "customer_id": Schema.optionalKey(Schema.String.annotate({ "description": "The id of the Bridge customer that this External Account belongs to", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "bank_name": Schema.optionalKey(Schema.String.annotate({ "description": "Bank name of the account (e.g. \"Chase\")" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" }))), "account_owner_name": Schema.String.annotate({ "description": "Owner of the account Bank Account (e.g. \"John Doe\"). For ach, wire, and iban accounts, this field must be at least 3 characters, at most 35 characters, and follow the regex pattern for the given account type:\n- ach: `^(?!\\s*$)[\\x20-\\x7E]*$`\n- wire: ```^[ \\w!\"#$%&'()+,\\-./:;<=>?@\\\\_`~]*$```\n- iban: `^(?![:\\- ]*$)[a-zA-Z0-9\\/\\-?:().,'+ _]+$`\n" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" })), "created_at": Schema.optionalKey(Schema.String.annotate({ "description": "Time of creation of the External Account", "readOnly": true, "format": "date-time" })), "updated_at": Schema.optionalKey(Schema.String.annotate({ "description": "Time of last update of the External Account", "readOnly": true, "format": "date-time" })), "active": Schema.optionalKey(Schema.Boolean.annotate({ "description": "Whether or not this External Account is active", "readOnly": true })), "account_owner_type": Schema.optionalKey(Schema.Literals(["individual", "business"]).annotate({ "description": "The type of the account ownership. Required when the `account_type` is `iban`. For `individual` ownership, `first_name` and `last_name` are required. For `business` ownership, `business_name` is required." })), "first_name": Schema.optionalKey(Schema.String.annotate({ "description": "First name of the individual account holder. Required when the `account_owner_type` is `individual`" })), "last_name": Schema.optionalKey(Schema.String.annotate({ "description": "Last name of the individual account holder. Required when the `account_owner_type` is `individual`" })), "business_name": Schema.optionalKey(Schema.String.annotate({ "description": "Business name of the business account holder. Required when the `account_owner_type` is `business`" })), "address": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "street_line_1": Schema.String.check(Schema.isMinLength(4).annotate({ "expected": "a value with a length of at least 4" })).check(Schema.isMaxLength(35).annotate({ "expected": "a value with a length of at most 35" })), "street_line_2": Schema.optionalKey(Schema.String.check(Schema.isMaxLength(35).annotate({ "expected": "a value with a length of at most 35" }))), "city": Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "state": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-2 subdivision code. Must be supplied for US addresses." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "postal_code": Schema.optionalKey(Schema.String.annotate({ "description": "Must be supplied for countries that use postal codes." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "country": Schema.String.annotate({ "description": "Three-letter alpha-3 country code as defined in the ISO 3166-1 spec." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Address of the beneficiary of this account. Please ensure the address is valid (Google Maps is good for this). US addresses used to receive wires must include a street number." })), "account_owner_country": Schema.optionalKey(Schema.String.annotate({ "description": "Three-letter alpha-3 country of residence of the account owner (ISO 3166-1).", "readOnly": true }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))), "deactivation_reason": Schema.optionalKey(Schema.Literals(["plaid_item_error", "deactivated_due_to_bounceback", "deleted_by_developer", "requested_by_developer", "invalid_account_number", "invalid_bank_validation", "rejected_by_bank_provider"]).annotate({ "description": "Reason for deactivation when this External Account is inactive", "readOnly": true })), "deactivation_details": Schema.optionalKey(Schema.String.annotate({ "description": "Additional details about the deactivation when this External Account is inactive", "readOnly": true })), "currency": Schema.Literal("cop").annotate({ "description": "Currency associated with the bank account. Must be `cop` for CO bank transfer accounts." }), "account_type": Schema.Literal("co_bank_transfer").annotate({ "description": "Type of the bank account." }), "account": Schema.StructWithRest(Schema.Struct({ "account_number": Schema.String.annotate({ "description": "The CO bank account number", "writeOnly": true }), "bank_code": Schema.Literals(["1001", "1002", "1006", "1007", "1009", "1012", "1013", "1019", "1023", "1032", "1040", "1047", "1051", "1052", "1053", "1059", "1060", "1061", "1062", "1063", "1065", "1066", "1067", "1069", "1070", "1071", "1097", "1121", "1283", "1286", "1289", "1292", "1303", "1370", "1507", "1551", "1558", "1637", "1801", "1802", "1803", "1804", "1805", "1808", "1809", "1811", "1812", "1814", "1815", "1816"]).annotate({ "description": "The Colombian bank code identifying the customer's bank.\n\n| Code | Bank |\n|------|------|\n| `1001` | Banco de Bogotá |\n| `1002` | Banco Popular |\n| `1006` | Itaú |\n| `1007` | Bancolombia |\n| `1009` | Citibank |\n| `1012` | Banco GNB Sudameris |\n| `1013` | BBVA Colombia |\n| `1019` | Scotiabank Colpatria |\n| `1023` | Banco de Occidente |\n| `1032` | Banco Caja Social |\n| `1040` | Banco Agrario |\n| `1047` | Banco Mundo Mujer |\n| `1051` | Banco Davivienda |\n| `1052` | Banco AV Villas |\n| `1053` | Banco W |\n| `1059` | Bancamía |\n| `1060` | Banco Pichincha |\n| `1061` | Bancoomeva |\n| `1062` | Banco Falabella |\n| `1063` | Banco Finandina |\n| `1065` | Banco Santander |\n| `1066` | Banco Cooperativo Coopcentral |\n| `1067` | MiBanco |\n| `1069` | Banco Serfinanza |\n| `1070` | Lulo Bank |\n| `1071` | Banco J.P. Morgan Colombia |\n| `1097` | Dale |\n| `1121` | Financiera Juriscoop |\n| `1283` | Cooperativa Financiera de Antioquia |\n| `1286` | JFK Cooperativa Financiera |\n| `1289` | Cootrafa Cooperativa Financiera |\n| `1292` | Confiar Cooperativa Financiera |\n| `1303` | Banco Unión |\n| `1370` | Coltefinanciera |\n| `1507` | Nequi |\n| `1551` | Daviplata |\n| `1558` | Ban100 |\n| `1637` | Iris |\n| `1801` | Movii |\n| `1802` | Ding Tecnipagos |\n| `1803` | Powwi |\n| `1804` | Ualá |\n| `1805` | Banco BTG Pactual |\n| `1808` | Bold CF |\n| `1809` | Nu Colombia |\n| `1811` | Rappipay |\n| `1812` | Coink |\n| `1814` | Global66 |\n| `1815` | Alianza Fiduciaria |\n| `1816` | Crezcamos |\n" }), "account_type": Schema.Literals(["checking", "savings", "electronic_deposit"]).annotate({ "description": "The type of bank account" }), "document_type": Schema.Literals(["cc", "ce", "nit", "rut", "pa", "ppt", "ti", "rc", "te", "die", "nd"]).annotate({ "description": "Colombian document type identifier. `cc` = Cédula de Ciudadanía, `ce` = Cédula de Extranjería, `nit` = NIT (tax ID), `rut` = RUT (worker registration), `pa` = Passport, `ppt` = Permiso de Protección Temporal.\n" }), "document_number": Schema.String.annotate({ "description": "The document number of the account holder" }), "phone_number": Schema.String.annotate({ "description": "Phone number of the account holder in E.164 format (e.g. +573001234567)" }), "last_4": Schema.optionalKey(Schema.String.annotate({ "description": "Last 4 digits of the account number", "readOnly": true }).check(Schema.isMinLength(4).annotate({ "expected": "a value with a length of at least 4" })).check(Schema.isMaxLength(4).annotate({ "expected": "a value with a length of at most 4" }))), "routing_number": Schema.optionalKey(Schema.String.annotate({ "description": "The bank code of the account", "readOnly": true })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "title": "co_bank_transfer", "description": "Colombian CO bank account information. Required when account type is co_bank_transfer.", "writeOnly": true }) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "title": "CO Bank Transfer", "description": "Request body for creating an external account." })], { mode: "oneOf" }).annotate({ "identifier": "CreateExternalAccountInput" }) +export type UpdateExternalAccountInput = { readonly "address"?: { readonly "street_line_1": string, readonly "street_line_2"?: string, readonly "city": string, readonly "state"?: string, readonly "postal_code"?: string, readonly "country": string } & { readonly [x: string]: Schema.Json }, readonly "account"?: { readonly "checking_or_savings"?: "checking" | "savings", readonly "routing_number"?: string } & { readonly [x: string]: Schema.Json } } & { readonly [x: string]: Schema.Json } +export const UpdateExternalAccountInput = Schema.StructWithRest(Schema.Struct({ "address": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "street_line_1": Schema.String.check(Schema.isMinLength(4).annotate({ "expected": "a value with a length of at least 4" })), "street_line_2": Schema.optionalKey(Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "city": Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "state": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-2 subdivision code. Must be supplied for US addresses." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))), "postal_code": Schema.optionalKey(Schema.String.annotate({ "description": "Must be supplied for countries that use postal codes." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "country": Schema.String.annotate({ "description": "Three-letter alpha-3 country code as defined in the ISO 3166-1 spec." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Address of the beneficiary of this account.", "writeOnly": true })), "account": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "checking_or_savings": Schema.optionalKey(Schema.Literals(["checking", "savings"]).annotate({ "description": "Determines whether the US account is treated as checking or savings. All US accounts will be treated as checking by default." })), "routing_number": Schema.optionalKey(Schema.String.annotate({ "description": "The bank routing number" }).check(Schema.isMinLength(9).annotate({ "expected": "a value with a length of at least 9" })).check(Schema.isMaxLength(9).annotate({ "expected": "a value with a length of at most 9" }))) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "US bank account information. Required when the `account_type` is `us`." })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "identifier": "UpdateExternalAccountInput" }) +export type AssociatedPersonResponse = { readonly "id": string, readonly "email"?: string, readonly "first_name"?: string, readonly "last_name"?: string, readonly "has_ownership"?: boolean, readonly "has_control"?: boolean, readonly "is_signer"?: boolean, readonly "title"?: string, readonly "attested_ownership_structure_at"?: string, readonly "relationship_established_at"?: string, readonly "created_at": number, readonly "updated_at": number } +export const AssociatedPersonResponse = Schema.Struct({ "id": Schema.String.annotate({ "description": "Unique identifier for the associated person" }), "email": Schema.optionalKey(Schema.String.annotate({ "description": "The email address of the associated person" })), "first_name": Schema.optionalKey(Schema.String.annotate({ "description": "The first name of the associated person" }).check(Schema.isMinLength(2).annotate({ "expected": "a value with a length of at least 2" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" }))), "last_name": Schema.optionalKey(Schema.String.annotate({ "description": "The last name of the associated person" }).check(Schema.isMinLength(2).annotate({ "expected": "a value with a length of at least 2" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" }))), "has_ownership": Schema.optionalKey(Schema.Boolean.annotate({ "description": "True if this person has at least 25% ownership of the business." })), "has_control": Schema.optionalKey(Schema.Boolean.annotate({ "description": "True if this is the control person of the company, having significant responsibility to control, manage or influence the activities of the business entity." })), "is_signer": Schema.optionalKey(Schema.Boolean.annotate({ "description": "True if this person is able to authorize transactions on behalf of the business." })), "title": Schema.optionalKey(Schema.String.annotate({ "description": "The title of this associated person at the company, e.g. CEO, CFO, etc." })), "attested_ownership_structure_at": Schema.optionalKey(Schema.String.annotate({ "description": "When this individual attested to the correctness of the ownership structure provided to Bridge. If provided by at least one control person, ownership documents for the business are not required." })), "relationship_established_at": Schema.optionalKey(Schema.String.annotate({ "description": "When the associated person relationship was established in format yyyy-mm-dd." })), "created_at": Schema.Number.annotate({ "description": "Created timestamp in milliseconds since Unix epoch" }).check(Schema.isInt().annotate({ "expected": "an integer" })), "updated_at": Schema.Number.annotate({ "description": "Last updated timestamp in milliseconds since Unix epoch" }).check(Schema.isInt().annotate({ "expected": "an integer" })) }).annotate({ "identifier": "AssociatedPersonResponse" }) +export type AssociatedPerson = { readonly "first_name": string, readonly "middle_name"?: string, readonly "last_name": string, readonly "transliterated_first_name"?: string, readonly "transliterated_middle_name"?: string, readonly "transliterated_last_name"?: string, readonly "email": string, readonly "phone"?: string, readonly "residential_address": { readonly "street_line_1": string, readonly "street_line_2"?: string, readonly "city": string, readonly "subdivision"?: string, readonly "postal_code"?: string, readonly "country": string } & { readonly [x: string]: Schema.Json }, readonly "transliterated_residential_address"?: { readonly "street_line_1": string, readonly "street_line_2"?: string, readonly "city": string, readonly "subdivision"?: string, readonly "postal_code"?: string, readonly "country": string } & { readonly [x: string]: Schema.Json }, readonly "birth_date": string, readonly "nationality"?: string, readonly "nationalities"?: ReadonlyArray, readonly "place_of_birth"?: { readonly "country"?: string, readonly "city"?: string }, readonly "verified_database_at"?: string, readonly "has_ownership": boolean, readonly "has_control": boolean, readonly "is_signer": boolean, readonly "is_director"?: boolean, readonly "title"?: string, readonly "ownership_percentage"?: number, readonly "attested_ownership_structure_at"?: string, readonly "verified_account_authorization_at"?: string, readonly "relationship_established_at"?: string, readonly "verified_govid_at"?: string, readonly "verified_selfie_at"?: string, readonly "identifying_information": ReadonlyArray<{ readonly "type": "drivers_license" | "matriculate_id" | "military_id" | "national_id" | "passport" | "permanent_residency_id" | "state_or_provincial_id" | "visa" | "abn" | "acn" | "ahv" | "ak" | "aom" | "arbn" | "avs" | "bc" | "bce" | "bin" | "bir" | "bp" | "brn" | "bsn" | "bvn" | "cc" | "cdi" | "cedula_juridica" | "cf" | "cif" | "cin" | "cipc" | "cn" | "cnp" | "cnpj" | "cpf" | "cpr" | "crc" | "crib" | "crn" | "cro" | "cui" | "cuil" | "curp" | "cuit" | "cvr" | "edrpou" | "ein" | "embg" | "emirates_id" | "en" | "fin" | "fn" | "gstin" | "gui" | "hetu" | "hkid" | "hn" | "ic" | "ico" | "id" | "id_broj" | "idno" | "idnp" | "idnr" | "if" | "iin" | "ik" | "inn" | "ird" | "itin" | "itr" | "iva" | "jmbg" | "kbo" | "kvk" | "matricule" | "mf" | "mn" | "ms" | "mst" | "nic" | "nicn" | "nie" | "nif" | "nin" | "nino" | "nip" | "nipc" | "nipt" | "nit" | "npwp" | "nric" | "nrn" | "nrt" | "ntn" | "nuit" | "nzbn" | "oib" | "orgnr" | "other" | "pan" | "partita_iva" | "pesel" | "pib" | "pin" | "pk" | "ppsn" | "qid" | "rc" | "regon" | "rfc" | "ricn" | "rif" | "rn" | "rnc" | "rnokpp" | "rp" | "rrn" | "rtn" | "ruc" | "rut" | "si" | "sin" | "siren" | "siret" | "spi" | "ssm" | "ssn" | "steuer_id" | "strn" | "tckn" | "tfn" | "tin" | "tpin" | "trn" | "ucn" | "uen" | "uic" | "uid" | "usc" | "ust_idnr" | "utr" | "vat" | "vkn" | "voen" | "y_tunnus", readonly "issuing_country": string, readonly "number"?: string, readonly "description"?: string, readonly "expiration"?: string, readonly "image_front"?: string, readonly "image_back"?: string }>, readonly "documents"?: ReadonlyArray<{ readonly "purposes": ReadonlyArray<"proof_of_account_purpose" | "proof_of_address" | "proof_of_individual_name_change" | "proof_of_relationship" | "proof_of_source_of_funds" | "proof_of_source_of_wealth" | "proof_of_tax_identification" | "other">, readonly "file": string, readonly "description"?: string }> } & { readonly [x: string]: Schema.Json } +export const AssociatedPerson = Schema.StructWithRest(Schema.Struct({ "first_name": Schema.String.annotate({ "description": "The first name of the associated person" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" })), "middle_name": Schema.optionalKey(Schema.String.annotate({ "description": "The middle name of the associated person" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" }))), "last_name": Schema.String.annotate({ "description": "The last name of the associated person" }).check(Schema.isMinLength(2).annotate({ "expected": "a value with a length of at least 2" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" })), "transliterated_first_name": Schema.optionalKey(Schema.String.annotate({ "description": "Required when the `first_name` includes any non Latin-1 characters. Acceptable characters - Latin-1 Unicode Character Range: À-ÖØ-ßà-öø-ÿ; Standard Unicode Character Range: -~" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" }))), "transliterated_middle_name": Schema.optionalKey(Schema.String.annotate({ "description": "Required when the `middle_name` includes any non Latin-1 characters. Acceptable characters - Latin-1 Unicode Character Range: À-ÖØ-ßà-öø-ÿ; Standard Unicode Character Range: -~" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" }))), "transliterated_last_name": Schema.optionalKey(Schema.String.annotate({ "description": "Required when the `last_name` includes any non Latin-1 characters. Acceptable characters - Latin-1 Unicode Character Range: À-ÖØ-ßà-öø-ÿ; Standard Unicode Character Range: -~" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" }))), "email": Schema.String.annotate({ "description": "The persons primary email address" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" })), "phone": Schema.optionalKey(Schema.String.annotate({ "description": "The persons phone in format \"+12223334444\"" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" }))), "residential_address": Schema.StructWithRest(Schema.Struct({ "street_line_1": Schema.String.check(Schema.isMinLength(4).annotate({ "expected": "a value with a length of at least 4" })), "street_line_2": Schema.optionalKey(Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "city": Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "subdivision": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-2 subdivision code. Must be supplied for US addresses." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))), "postal_code": Schema.optionalKey(Schema.String.annotate({ "description": "Must be supplied for countries that use postal codes." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "country": Schema.String.annotate({ "description": "Three-letter alpha-3 country code as defined in the ISO 3166-1 spec." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "The residential address of the associated person. This must be a physical address and cannot be a PO Box.", "writeOnly": true }), "transliterated_residential_address": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "street_line_1": Schema.String.check(Schema.isMinLength(4).annotate({ "expected": "a value with a length of at least 4" })), "street_line_2": Schema.optionalKey(Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "city": Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "subdivision": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-2 subdivision code. Must be supplied for US addresses." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))), "postal_code": Schema.optionalKey(Schema.String.annotate({ "description": "Must be supplied for countries that use postal codes." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "country": Schema.String.annotate({ "description": "Three-letter alpha-3 country code as defined in the ISO 3166-1 spec." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Required when any part of the `residential_address` includes any non Latin-1 characters. Acceptable characters - Latin-1 Unicode Character Range: À-ÖØ-ßà-öø-ÿ; Standard Unicode Character Range: -~", "writeOnly": true })), "birth_date": Schema.String.annotate({ "description": "Date of birth in format yyyy-mm-dd. Must be at least 18 years old." }).check(Schema.isMinLength(10).annotate({ "expected": "a value with a length of at least 10" })).check(Schema.isMaxLength(10).annotate({ "expected": "a value with a length of at most 10" })), "nationality": Schema.optionalKey(Schema.String.annotate({ "description": "Legacy single nationality (ISO 3166-1 alpha-3). Prefer `nationalities` for all nationalities. See individual customer `nationality` / `nationalities` and [EEA nationalities](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#nationalities).\n", "writeOnly": true })), "nationalities": Schema.optionalKey(Schema.Array(Schema.String.check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))).annotate({ "description": "All nationalities for this associated person (ISO 3166-1 alpha-3). **EEA / BBSA in-scope businesses:** required on each UBO / associated person where policy applies.\n", "writeOnly": true })), "place_of_birth": Schema.optionalKey(Schema.Struct({ "country": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-1 alpha-3 country code for the place of birth." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))), "city": Schema.optionalKey(Schema.String.annotate({ "description": "City of birth (recommended for EEA)." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))) }).annotate({ "description": "Country (and optionally city) of birth. **EEA / BBSA in-scope customers:** supply when onboarding individuals or associated persons under the [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#country-of-birth-and-city-of-birth). This is a sparse address — no street address. At least `country` should be present when the object is sent; `city` is recommended and will be required by EU law in 2027.\n", "writeOnly": true })), "verified_database_at": Schema.optionalKey(Schema.String.annotate({ "description": "Write-only ISO 8601 timestamp. For **EEA in-scope** associated persons on **reliance**, second factor with `verified_govid_at` under `TWO_FORMS_OF_ID_RELIANCE`.\n", "writeOnly": true, "format": "date-time" })), "has_ownership": Schema.Boolean.annotate({ "description": "True if this person has at least 25% ownership of the business." }), "has_control": Schema.Boolean.annotate({ "description": "True if this is the control person of the company, having significant responsibility to control, manage or influence the activities of the business entity. At least one control person must be specified. " }), "is_signer": Schema.Boolean.annotate({ "description": "True if this person is able to authorize transactions on behalf of the business. At least one signer must be specified." }), "is_director": Schema.optionalKey(Schema.Boolean.annotate({ "description": "True if this person is an appointed director of the company. **EEA / BBSA in-scope businesses:** must be set for every associated person (complete director list). See [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#complete-director-list)." })), "title": Schema.optionalKey(Schema.String.annotate({ "description": "The title of this associated person at the company, e.g. CEO, CFO, etc. Required if has_control is true." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" }))), "ownership_percentage": Schema.optionalKey(Schema.Number.annotate({ "description": "Ultimate ownership percentage of the business. **EEA / BBSA in-scope businesses:** required when `has_ownership` is true for UBOs at or above the configured threshold (default 25%). See [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#ownership-percentage-per-ubo).\n", "writeOnly": true }).check(Schema.isInt().annotate({ "expected": "an integer" }))), "attested_ownership_structure_at": Schema.optionalKey(Schema.String.annotate({ "description": "The date or timestamp when this individual attested to the correctness of the ownership structure provided to Bridge. If provided by at least one control person, ownership documents for the business are not required.", "writeOnly": true })), "verified_account_authorization_at": Schema.optionalKey(Schema.String.annotate({ "description": "Write-only ISO 8601 timestamp. For **EEA in-scope** businesses on **reliance**, may satisfy signatory authority for signers who are not owner, director, or control person (`signature_authority_requirement(for_reliance: true)`); alternative is `documents` with purpose `proof_of_signatory_authority`. See [EEA updated requirements — LOA](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#letter-of-authority-loa).\n", "writeOnly": true, "format": "date-time" })), "relationship_established_at": Schema.optionalKey(Schema.String.annotate({ "description": "The date or timestamp when the associated person relationship was established in format yyyy-mm-dd." })), "verified_govid_at": Schema.optionalKey(Schema.String.annotate({ "description": "Write-only ISO 8601 timestamp. For **EEA in-scope** associated persons on **reliance**, use with `verified_selfie_at` or `verified_database_at` under `TWO_FORMS_OF_ID_RELIANCE`.\n", "writeOnly": true, "format": "date-time" })), "verified_selfie_at": Schema.optionalKey(Schema.String.annotate({ "description": "Write-only ISO 8601 timestamp. For **EEA in-scope** associated persons on **reliance**, pairs with `verified_govid_at` or `verified_database_at` under `TWO_FORMS_OF_ID_RELIANCE`.\n", "writeOnly": true, "format": "date-time" })), "identifying_information": Schema.Array(Schema.Struct({ "type": Schema.Literals(["drivers_license", "matriculate_id", "military_id", "national_id", "passport", "permanent_residency_id", "state_or_provincial_id", "visa", "abn", "acn", "ahv", "ak", "aom", "arbn", "avs", "bc", "bce", "bin", "bir", "bp", "brn", "bsn", "bvn", "cc", "cdi", "cedula_juridica", "cf", "cif", "cin", "cipc", "cn", "cnp", "cnpj", "cpf", "cpr", "crc", "crib", "crn", "cro", "cui", "cuil", "curp", "cuit", "cvr", "edrpou", "ein", "embg", "emirates_id", "en", "fin", "fn", "gstin", "gui", "hetu", "hkid", "hn", "ic", "ico", "id", "id_broj", "idno", "idnp", "idnr", "if", "iin", "ik", "inn", "ird", "itin", "itr", "iva", "jmbg", "kbo", "kvk", "matricule", "mf", "mn", "ms", "mst", "nic", "nicn", "nie", "nif", "nin", "nino", "nip", "nipc", "nipt", "nit", "npwp", "nric", "nrn", "nrt", "ntn", "nuit", "nzbn", "oib", "orgnr", "other", "pan", "partita_iva", "pesel", "pib", "pin", "pk", "ppsn", "qid", "rc", "regon", "rfc", "ricn", "rif", "rn", "rnc", "rnokpp", "rp", "rrn", "rtn", "ruc", "rut", "si", "sin", "siren", "siret", "spi", "ssm", "ssn", "steuer_id", "strn", "tckn", "tfn", "tin", "tpin", "trn", "ucn", "uen", "uic", "uid", "usc", "ust_idnr", "utr", "vat", "vkn", "voen", "y_tunnus"]).annotate({ "description": "Tax identification number type or government-issued ID document type (see enum). Country-specific tax and national ID lists: [Individuals](https://apidocs.bridge.xyz/docs/individual-tax-identification-numbers-by-country), [Businesses](https://apidocs.bridge.xyz/docs/business-tax-identification-numbers-by-country).\n\n**EEA / BBSA (policy in `eea_requirements.rb`):** In-scope individuals and UBOs need **both** a valid national-ID-type entry and a valid TIN per [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements). In-scope businesses need business registration **and** business tax ID types per country tables there. **TIN issuing country** must match residence (individuals) or incorporation (businesses). **Foreign tax** outside the incorporation country: set `has_foreign_tax_registration` on the business customer and add TIN objects per jurisdiction ([foreign tax / tax residency](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#tax-residency-status-foreign-tax-registry)).\n" }), "issuing_country": Schema.String.annotate({ "description": "The ISO 3166-1 (three-character) country code that issued the provided document." }), "number": Schema.optionalKey(Schema.String.annotate({ "description": "The unique identifier of the document. Required if this document is being used as a tax identification number (e.g., you are providing a passport or national_id with no other identification)." })), "description": Schema.optionalKey(Schema.String.annotate({ "description": "A description describing the provided document. This field is required when `other` is selected." })), "expiration": Schema.optionalKey(Schema.String.annotate({ "description": "The expiration date of the given document in yyyy-mm-dd format." })), "image_front": Schema.optionalKey(Schema.String.annotate({ "description": "This field is optionally accepted for tax_id types, but required for government_id types. Base64 encoded image* of the front side of the provided document, following the data-uri scheme i.e. data:image/[type];base64,[base_64_encoded_file_contents], with a minimum size of 200px x 200px \\n\\n*Maximum File Size: 15MB\\n\\n*Valid file types: .pdf, .jpeg, .jpg, .png, .heic, .tif\n\n_Note: When combined with an `image_back`, the combined size of both images must not exceed 24MB._\n" })), "image_back": Schema.optionalKey(Schema.String.annotate({ "description": "Base64 encoded image* of the back side of the provided document, following the data-uri scheme i.e. data:image/[type];base64,[base_64_encoded_file_contents], with a minimum size of 200px x 200px \\n\\n*Maximum File Size: 15MB\\n\\n*Valid file types: .pdf, .jpeg, .jpg, .png, .heic, .tif\n\n_Note: When combined with an `image_front`, the combined size of both images must not exceed 24MB._\n" })) })).annotate({ "title": "Identification Information", "writeOnly": true }), "documents": Schema.optionalKey(Schema.Array(Schema.Struct({ "purposes": Schema.Array(Schema.Literals(["proof_of_account_purpose", "proof_of_address", "proof_of_individual_name_change", "proof_of_relationship", "proof_of_source_of_funds", "proof_of_source_of_wealth", "proof_of_tax_identification", "other"])).annotate({ "description": "A list of purposes that the given document serves. Click \"ADD STRING\" to see common document purposes for individuals, or view the full list of possible values [here](https://apidocs.bridge.xyz/docs/supported-documents)." }), "file": Schema.String.annotate({ "description": "Base64 encoded image* of the provided document, following the data-uri scheme i.e. data:image/[type];base64,[base_64_encoded_file_contents], with a minimum size of 200px x 200px \n\n*Maximum File Size: 24MB\n\n*Valid file types: .pdf, .jpeg, .jpg, .png, .heic, .tif" }), "description": Schema.optionalKey(Schema.String.annotate({ "description": "A description describing the provided document. This field is required when `other` is provided as one of the purposes." })) })).annotate({ "title": "Documents", "description": "Please click \"ADD OBJECT\" for more information.", "writeOnly": true })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "identifier": "AssociatedPerson" }) +export type FiatPayoutConfigurationResponse = { readonly "fiat_payout_configuration": { readonly "usd"?: { readonly "wire"?: "developer" | "customer", readonly "ach"?: "bridge" }, readonly "eur"?: { readonly "sepa"?: "bridge" }, readonly "brl"?: { readonly "pix"?: "payment_provider" }, readonly "mxn"?: { readonly "spei"?: "payment_provider" } } } +export const FiatPayoutConfigurationResponse = Schema.Struct({ "fiat_payout_configuration": Schema.Struct({ "usd": Schema.optionalKey(Schema.Struct({ "wire": Schema.optionalKey(Schema.Literals(["developer", "customer"]).annotate({ "description": "The payout method to use for USD wire transfers" })), "ach": Schema.optionalKey(Schema.Literal("bridge").annotate({ "description": "The payout method to use for USD ACH transfers" })) }).annotate({ "description": "Payment rail configuration for USD" })), "eur": Schema.optionalKey(Schema.Struct({ "sepa": Schema.optionalKey(Schema.Literal("bridge").annotate({ "description": "The payout method to use for EUR SEPA transfers" })) }).annotate({ "description": "Payment rail configuration for EUR" })), "brl": Schema.optionalKey(Schema.Struct({ "pix": Schema.optionalKey(Schema.Literal("payment_provider").annotate({ "description": "The payout method to use for BRL PIX transfers" })) }).annotate({ "description": "Payment rail configuration for BRL" })), "mxn": Schema.optionalKey(Schema.Struct({ "spei": Schema.optionalKey(Schema.Literal("payment_provider").annotate({ "description": "The payout method to use for MXN SPEI transfers" })) }).annotate({ "description": "Payment rail configuration for MXN" })) }).annotate({ "description": "A nested hash structure representing the fiat payout configuration. The top-level keys are currency codes. \nEach currency maps to a hash where keys are payment rail codes and values are payout names.\n", "examples": [{ "usd": { "wire": "developer", "ach": "bridge" }, "eur": { "sepa": "bridge" }, "brl": { "pix": "payment_provider" }, "mxn": { "spei": "payment_provider" } }] }) }).annotate({ "identifier": "FiatPayoutConfigurationResponse" }) +export type PatchFiatPayoutConfigurationInput = { readonly "fiat_payout_configuration": { readonly "usd"?: { readonly "wire"?: "developer" | "customer", readonly "ach"?: "bridge" }, readonly "eur"?: { readonly "sepa"?: "bridge" }, readonly "brl"?: { readonly "pix"?: "payment_provider" }, readonly "mxn"?: { readonly "spei"?: "payment_provider" } } } +export const PatchFiatPayoutConfigurationInput = Schema.Struct({ "fiat_payout_configuration": Schema.Struct({ "usd": Schema.optionalKey(Schema.Struct({ "wire": Schema.optionalKey(Schema.Literals(["developer", "customer"]).annotate({ "description": "The payout method to use for USD wire transfers" })), "ach": Schema.optionalKey(Schema.Literal("bridge").annotate({ "description": "The payout method to use for USD ACH transfers" })) }).annotate({ "description": "Payment rail configuration for USD" })), "eur": Schema.optionalKey(Schema.Struct({ "sepa": Schema.optionalKey(Schema.Literal("bridge").annotate({ "description": "The payout method to use for EUR SEPA transfers" })) }).annotate({ "description": "Payment rail configuration for EUR" })), "brl": Schema.optionalKey(Schema.Struct({ "pix": Schema.optionalKey(Schema.Literal("payment_provider").annotate({ "description": "The payout method to use for BRL PIX transfers" })) }).annotate({ "description": "Payment rail configuration for BRL" })), "mxn": Schema.optionalKey(Schema.Struct({ "spei": Schema.optionalKey(Schema.Literal("payment_provider").annotate({ "description": "The payout method to use for MXN SPEI transfers" })) }).annotate({ "description": "Payment rail configuration for MXN" })) }).annotate({ "description": "A nested hash structure representing the fiat payout configuration. The top-level keys are currency codes. \nEach currency maps to a hash where keys are payment rail codes and values are payout names.\n", "examples": [{ "usd": { "wire": "developer", "ach": "bridge" }, "eur": { "sepa": "bridge" }, "brl": { "pix": "payment_provider" }, "mxn": { "spei": "payment_provider" } }] }) }).annotate({ "description": "Input payload for updating a customer's fiat payout configuration", "examples": [{ "fiat_payout_configuration": { "usd": { "wire": "customer" } } }], "identifier": "PatchFiatPayoutConfigurationInput" }) +export type AccountVerification = { readonly "iban"?: { readonly "match_level"?: "pending" | "match" | "close_match" | "no_match" | "error", readonly "reason_code"?: string | null, readonly "validated_account_owner_name"?: string | null }, readonly "requested_at"?: string, readonly "completed_at"?: string | null } | { readonly "gb"?: { readonly "match_level"?: "pending" | "match" | "close_match" | "no_match" | "error", readonly "reason_code"?: string | null, readonly "validated_account_owner_name"?: string | null }, readonly "requested_at"?: string, readonly "completed_at"?: string | null } | { readonly "pix"?: { readonly "matched"?: boolean | null, readonly "reason_code"?: string | null, readonly "validated_account_owner_name"?: string | null, readonly "validated_bank_name"?: string | null }, readonly "requested_at"?: string, readonly "completed_at"?: string | null } | { readonly "clabe"?: { readonly "matched"?: boolean | null, readonly "reason_code"?: string | null, readonly "validated_account_owner_name"?: string | null, readonly "validated_bank_name"?: string | null }, readonly "requested_at"?: string, readonly "completed_at"?: string | null } | { readonly "bre_b"?: { readonly "matched"?: boolean | null, readonly "reason_code"?: string | null, readonly "validated_account_owner_name"?: string | null, readonly "validated_bank_name"?: string | null, readonly "validated_document_number_last4"?: string | null }, readonly "requested_at"?: string, readonly "completed_at"?: string | null } | { readonly "co_bank_transfer"?: { readonly "matched"?: boolean | null, readonly "reason_code"?: string | null, readonly "validated_account_owner_name"?: string | null, readonly "validated_bank_name"?: string | null, readonly "validated_document_number_last4"?: string | null }, readonly "requested_at"?: string, readonly "completed_at"?: string | null } +export const AccountVerification = Schema.Union([Schema.Struct({ "iban": Schema.optionalKey(Schema.Struct({ "match_level": Schema.optionalKey(Schema.Literals(["pending", "match", "close_match", "no_match", "error"]).annotate({ "description": "The result of the name match check." })), "reason_code": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Additional context from the receiving bank when the result is not a full match." })), "validated_account_owner_name": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Account owner name as returned by the validation provider." })) })), "requested_at": Schema.optionalKey(Schema.String.annotate({ "description": "When the verification was requested.", "format": "date-time" })), "completed_at": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "When the verification completed. Null while pending.", "format": "date-time" })) }).annotate({ "title": "IBAN", "description": "Present when verifying an IBAN account." }), Schema.Struct({ "gb": Schema.optionalKey(Schema.Struct({ "match_level": Schema.optionalKey(Schema.Literals(["pending", "match", "close_match", "no_match", "error"]).annotate({ "description": "The result of the name match check." })), "reason_code": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Additional context from the receiving bank when the result is not a full match." })), "validated_account_owner_name": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Account owner name as returned by the validation provider." })) })), "requested_at": Schema.optionalKey(Schema.String.annotate({ "description": "When the verification was requested.", "format": "date-time" })), "completed_at": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "When the verification completed. Null while pending.", "format": "date-time" })) }).annotate({ "title": "GB", "description": "Present when verifying a GB account." }), Schema.Struct({ "pix": Schema.optionalKey(Schema.Struct({ "matched": Schema.optionalKey(Schema.Union([Schema.Boolean, Schema.Null]).annotate({ "description": "Match result as returned by the validation provider." })), "reason_code": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Additional context from the validation provider." })), "validated_account_owner_name": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Account owner name as returned by the validation provider." })), "validated_bank_name": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Bank name as returned by the validation provider." })) })), "requested_at": Schema.optionalKey(Schema.String.annotate({ "description": "When the verification was requested.", "format": "date-time" })), "completed_at": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "When the verification completed. Null while pending.", "format": "date-time" })) }).annotate({ "title": "Pix", "description": "Present when verifying a Pix account." }), Schema.Struct({ "clabe": Schema.optionalKey(Schema.Struct({ "matched": Schema.optionalKey(Schema.Union([Schema.Boolean, Schema.Null]).annotate({ "description": "Match result as returned by the validation provider." })), "reason_code": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Additional context from the validation provider." })), "validated_account_owner_name": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Account owner name as returned by the validation provider." })), "validated_bank_name": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Bank name as returned by the validation provider." })) })), "requested_at": Schema.optionalKey(Schema.String.annotate({ "description": "When the verification was requested.", "format": "date-time" })), "completed_at": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "When the verification completed. Null while pending.", "format": "date-time" })) }).annotate({ "title": "CLABE", "description": "Present when verifying a CLABE account." }), Schema.Struct({ "bre_b": Schema.optionalKey(Schema.Struct({ "matched": Schema.optionalKey(Schema.Union([Schema.Boolean, Schema.Null]).annotate({ "description": "Match result as returned by the validation provider." })), "reason_code": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Additional context from the validation provider." })), "validated_account_owner_name": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Account owner name as returned by the validation provider." })), "validated_bank_name": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Bank name as returned by the validation provider." })), "validated_document_number_last4": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Last 4 characters of the account owner's document number, as returned by the validation provider. Present only for Bre-B (Colombian) accounts.", "readOnly": true })) })), "requested_at": Schema.optionalKey(Schema.String.annotate({ "description": "When the verification was requested.", "format": "date-time" })), "completed_at": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "When the verification completed. Null while pending.", "format": "date-time" })) }).annotate({ "title": "Bre-B", "description": "Present when verifying a Bre-B account." }), Schema.Struct({ "co_bank_transfer": Schema.optionalKey(Schema.Struct({ "matched": Schema.optionalKey(Schema.Union([Schema.Boolean, Schema.Null]).annotate({ "description": "Match result as returned by the validation provider." })), "reason_code": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Additional context from the validation provider." })), "validated_account_owner_name": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Account owner name as returned by the validation provider." })), "validated_bank_name": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Bank name as returned by the validation provider." })), "validated_document_number_last4": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Last 4 characters of the account owner's document number, as returned by the validation provider. Present only for Bre-B (Colombian) accounts.", "readOnly": true })) })), "requested_at": Schema.optionalKey(Schema.String.annotate({ "description": "When the verification was requested.", "format": "date-time" })), "completed_at": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "When the verification completed. Null while pending.", "format": "date-time" })) }).annotate({ "title": "CO Bank Transfer", "description": "Present when verifying a PSE account." })], { mode: "oneOf" }).annotate({ "description": "The current state of a holder verification check, keyed by account type.", "identifier": "AccountVerification" }) +export type TransferResponse = { readonly "id": string, readonly "client_reference_id"?: string, readonly "amount": string, readonly "currency": "usd" | "eur" | "mxn" | "brl" | "cop" | "gbp", readonly "on_behalf_of": string, readonly "developer_fee": string, readonly "developer_fee_percent"?: string, readonly "source": { readonly "currency": "brl" | "cop" | "eur" | "eurc" | "gbp" | "mxn" | "pyusd" | "usd" | "usdb" | "usdc" | "usdt" | "usdl_linea", readonly "payment_rail": "ach" | "wire" | "ach_push" | "ach_same_day" | "fednow" | "arbitrum" | "avalanche_c_chain" | "base" | "bre_b" | "co_bank_transfer" | "bridge_wallet" | "celo" | "ethereum" | "faster_payments" | "linea" | "optimism" | "pix" | "polygon" | "sepa" | "solana" | "spei" | "stellar" | "swift" | "tempo" | "tron" | "xdc", readonly "payment_scheme"?: "sepa_credit" | "sepa_instant", readonly "omad"?: string, readonly "imad"?: string, readonly "trace_number"?: string, readonly "bank_beneficiary_name"?: string, readonly "bank_beneficiary_address"?: string, readonly "bank_routing_number"?: string, readonly "bank_name"?: string, readonly "originator_name"?: string, readonly "originator_address"?: string, readonly "wire_message"?: string, readonly "bridge_wallet_id"?: string, readonly "sender_name"?: string, readonly "sender_bank_routing_number"?: string, readonly "end_to_end_id"?: string, readonly "description"?: string, readonly "tracking_number"?: string, readonly "clabe"?: string, readonly "bank_code"?: string, readonly "transaction_id"?: string, readonly "co_bank_transfer"?: { readonly "redirect_url": string, readonly "expiry_date"?: string, readonly "sender_data"?: { readonly "full_name": string, readonly "document_type": "cc" | "ce" | "nit" | "rut" | "pa" | "ppt" | "ti" | "rc" | "te" | "die" | "nd", readonly "document_number": string, readonly "email": string, readonly "phone_number": string } }, readonly "payment_received_rail"?: "ach" | "wire" | "ach_push" | "ach_same_day" | "fednow" | "arbitrum" | "avalanche_c_chain" | "base" | "bre_b" | "co_bank_transfer" | "bridge_wallet" | "celo" | "ethereum" | "faster_payments" | "linea" | "optimism" | "pix" | "polygon" | "sepa" | "solana" | "spei" | "stellar" | "swift" | "tempo" | "tron" | "xdc", readonly "from_address"?: string } & { readonly [x: string]: Schema.Json }, readonly "destination": { readonly "currency": "brl" | "cop" | "eur" | "eurc" | "gbp" | "mxn" | "pyusd" | "usd" | "usdb" | "usdc" | "usdt" | "usdl_linea", readonly "payment_rail": "ach" | "wire" | "ach_push" | "ach_same_day" | "arbitrum" | "avalanche_c_chain" | "base" | "bre_b" | "co_bank_transfer" | "celo" | "ethereum" | "fiat_deposit_return" | "linea" | "optimism" | "polygon" | "sepa" | "solana" | "spei" | "stellar" | "swift" | "tempo" | "tron" | "xdc", readonly "external_account_id"?: string, readonly "bridge_wallet_id"?: string, readonly "omad"?: string, readonly "imad"?: string, readonly "trace_number"?: string, readonly "end_to_end_id"?: string, readonly "wire_message"?: string, readonly "sepa_reference"?: string, readonly "swift_reference"?: string, readonly "spei_reference"?: string, readonly "reference"?: string | string, readonly "charge_bearer"?: "our" | "sha" | "ben", readonly "ach_reference"?: string, readonly "uetr"?: string, readonly "blockchain_memo"?: string, readonly "deposit_id"?: string, readonly "tracking_number"?: string, readonly "transaction_id"?: string, readonly "sending_institution_name"?: string, readonly "amount"?: string, readonly "to_address"?: string } & { readonly [x: string]: Schema.Json }, readonly "state": "awaiting_funds" | "in_review" | "funds_received" | "payment_submitted" | "payment_processed" | "canceled" | "undeliverable" | "returned" | "refund_in_flight" | "refund_failed" | "refunded", readonly "source_deposit_instructions"?: { readonly "payment_rail": "ach" | "wire" | "ach_push" | "ach_same_day" | "arbitrum" | "avalanche_c_chain" | "base" | "bre_b" | "co_bank_transfer" | "celo" | "ethereum" | "optimism" | "pix" | "polygon" | "solana" | "spei" | "stellar" | "tempo", readonly "amount": string, readonly "currency": "usdb" | "usdc" | "usdt" | "usdl_linea" | "usd" | "pyusd", readonly "from_address"?: string, readonly "to_address"?: string | null, readonly "memoless_to_address"?: string, readonly "deposit_message"?: string, readonly "bank_name"?: string, readonly "bank_address"?: string, readonly "bank_routing_number"?: string, readonly "bank_account_number"?: string, readonly "bank_beneficiary_name"?: string, readonly "bank_beneficiary_address"?: string, readonly "intermediary_bank_name"?: string, readonly "intermediary_bank_bic"?: string, readonly "intermediary_bank_routing_number"?: string, readonly "iban"?: string, readonly "bic"?: string, readonly "clabe"?: string, readonly "account_holder_name"?: string, readonly "bre_b_key"?: string, readonly "start_url"?: string, readonly "redirect_url"?: string, readonly "expires_at"?: string, readonly "blockchain_memo"?: string } & { readonly [x: string]: Schema.Json }, readonly "receipt": { readonly "initial_amount": string, readonly "developer_fee": string, readonly "exchange_fee": string, readonly "developer_exchange_fee"?: { readonly "amount"?: string, readonly "currency"?: string }, readonly "pre_conversion_subtotal_amount"?: string, readonly "mid_market_rate"?: string, readonly "converted_amount"?: string, readonly "subtotal_amount": string, readonly "remaining_prefunded_balance"?: string, readonly "gas_fee"?: string, readonly "final_amount"?: string, readonly "source_tx_hash"?: Schema.Json, readonly "destination_tx_hash"?: Schema.Json, readonly "exchange_rate"?: Schema.Json, readonly "url"?: string, readonly "bank_details"?: { readonly "sending_routing_number"?: string, readonly "ach_description"?: string, readonly "ach_trace_id"?: string, readonly "wire_message"?: string, readonly "imad"?: string, readonly "recipient_name"?: string, readonly "sending_bic"?: string, readonly "sepa_reference"?: string, readonly "uetr"?: string, readonly "receiving_account_last_four"?: string, readonly "receiving_bic"?: string } } & { readonly [x: string]: Schema.Json }, readonly "return_details"?: { readonly "reason"?: string, readonly "refund_reference_id"?: string, readonly "risk_rejection_reason"?: string } & { readonly [x: string]: Schema.Json }, readonly "return_instructions"?: { readonly "address": string, readonly "memo"?: string }, readonly "exchange_details"?: { readonly "fixed_rate"?: string, readonly "estimated_market_rate"?: string, readonly "traded_market_rate"?: string, readonly "trade_at_market"?: boolean, readonly "updated_at"?: string } & { readonly [x: string]: Schema.Json }, readonly "created_at": string, readonly "updated_at": string, readonly "template_id"?: string, readonly "first_confirmed_at"?: string } & { readonly [x: string]: Schema.Json } +export const TransferResponse = Schema.StructWithRest(Schema.Struct({ "id": Schema.String.annotate({ "description": "A UUID that uniquely identifies a resource", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" })), "client_reference_id": Schema.optionalKey(Schema.String.annotate({ "description": "A client-provided reference ID that uniquely identifies a resource in the client's system" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" }))), "amount": Schema.String.annotate({ "description": "Amount of the transfer, expressed as a decimal string. Examples include \"100.25\", \"0.1\", \"1.234567\", \"1.01\" etc.\n\nIt is denominated in the source currency if that is a fiat currency, or in the fiat currency to which the source currency is pegged." }), "currency": Schema.Literals(["usd", "eur", "mxn", "brl", "cop", "gbp"]).annotate({ "description": "Fiat currency for the transfer amount and developer fee. It's the source currency if that is a fiat currency or the fiat currency to which the source currency is pegged." }), "on_behalf_of": Schema.String.annotate({ "description": "The id of the Bridge customer that you are moving funds on behalf of." }), "developer_fee": Schema.String.annotate({ "description": "The fee, expressed as a decimal string, represents the amount you wish to reserve for your own account. This fee is the final amount deducted from what your customer ultimately receives, rather than a percentage.\n\nIt is denominated in the source currency if that is a fiat currency, or in the fiat currency to which the source currency is pegged." }), "developer_fee_percent": Schema.optionalKey(Schema.String.annotate({ "description": "The fee percent, expressed as a decimal string from `0.0` to `100.0`, represents the percentage of the transfer you wish to reserve for your own account.\n\nThis field must be set instead of `developer_fee` when using [Flexible Amounts](https://apidocs.bridge.xyz/platform/orchestration/fees-and-mins/devfees#transfers-with-fixed-amounts)." })), "source": Schema.StructWithRest(Schema.Struct({ "currency": Schema.Union([Schema.Literal("brl").annotate({ "description": "The source currency" }), Schema.Literal("cop").annotate({ "description": "The source currency" }), Schema.Literal("eur").annotate({ "description": "The source currency" }), Schema.Literal("eurc").annotate({ "description": "The source currency" }), Schema.Literal("gbp").annotate({ "description": "The source currency" }), Schema.Literal("mxn").annotate({ "description": "The source currency" }), Schema.Literal("pyusd").annotate({ "description": "The source currency" }), Schema.Literal("usd").annotate({ "description": "The source currency" }), Schema.Literal("usdb").annotate({ "description": "The source currency" }), Schema.Literal("usdc").annotate({ "description": "The source currency" }), Schema.Literal("usdt").annotate({ "description": "The source currency" }), Schema.Literal("usdl_linea").annotate({ "description": "The source currency" })]).annotate({ "description": "When `eur` is specified as the source currency:\n 1. the source rail must be `sepa`;\n 2. only `usdc` or `eurc` are supported as the destination currency" }), "payment_rail": Schema.Union([Schema.Literal("ach").annotate({ "description": "The intended source payment rail" }), Schema.Literal("wire").annotate({ "description": "The intended source payment rail" }), Schema.Literal("ach_push").annotate({ "description": "The intended source payment rail" }), Schema.Literal("ach_same_day").annotate({ "description": "The intended source payment rail" }), Schema.Literal("fednow").annotate({ "description": "The intended source payment rail" }), Schema.Literal("arbitrum").annotate({ "description": "The intended source payment rail" }), Schema.Literal("avalanche_c_chain").annotate({ "description": "The intended source payment rail" }), Schema.Literal("base").annotate({ "description": "The intended source payment rail" }), Schema.Literal("bre_b").annotate({ "description": "The intended source payment rail" }), Schema.Literal("co_bank_transfer").annotate({ "description": "The intended source payment rail" }), Schema.Literal("bridge_wallet").annotate({ "description": "The intended source payment rail" }), Schema.Literal("celo").annotate({ "description": "The intended source payment rail" }), Schema.Literal("ethereum").annotate({ "description": "The intended source payment rail" }), Schema.Literal("faster_payments").annotate({ "description": "The intended source payment rail" }), Schema.Literal("linea").annotate({ "description": "The intended source payment rail" }), Schema.Literal("optimism").annotate({ "description": "The intended source payment rail" }), Schema.Literal("pix").annotate({ "description": "The intended source payment rail" }), Schema.Literal("polygon").annotate({ "description": "The intended source payment rail" }), Schema.Literal("sepa").annotate({ "description": "The intended source payment rail" }), Schema.Literal("solana").annotate({ "description": "The intended source payment rail" }), Schema.Literal("spei").annotate({ "description": "The intended source payment rail" }), Schema.Literal("stellar").annotate({ "description": "The intended source payment rail" }), Schema.Literal("swift").annotate({ "description": "The intended source payment rail" }), Schema.Literal("tempo").annotate({ "description": "The intended source payment rail" }), Schema.Literal("tron").annotate({ "description": "The intended source payment rail" }), Schema.Literal("xdc").annotate({ "description": "The intended source payment rail" })]).annotate({ "description": "When `sepa` is specified as the source rail:\n 1. the source currency must be `eur`;\n 2. only `usdc` or `eurc` are supported as the destination currency \n\n **Note: This is the intended payment rail, and may differ from the actual payment rail used to onramp the funds.**" }), "payment_scheme": Schema.optionalKey(Schema.Literals(["sepa_credit", "sepa_instant"]).annotate({ "description": "(SEPA only) The payment scheme used for this transaction, such as SEPA Credit Transfer or SEPA Instant", "readOnly": true })), "omad": Schema.optionalKey(Schema.String.annotate({ "description": "(Wire only) The OMAD of a wire transfer, if available", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(40).annotate({ "expected": "a value with a length of at most 40" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "imad": Schema.optionalKey(Schema.String.annotate({ "description": "(Wire only) The IMAD of a wire transfer, if available", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(40).annotate({ "expected": "a value with a length of at most 40" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "trace_number": Schema.optionalKey(Schema.String.annotate({ "description": "The trace number of an ACH transfer", "readOnly": true }).check(Schema.isMinLength(15).annotate({ "expected": "a value with a length of at least 15" })).check(Schema.isMaxLength(15).annotate({ "expected": "a value with a length of at most 15" })).check(Schema.isPattern(new RegExp("[0-9]")).annotate({ "expected": "a string matching the RegExp [0-9]" }))), "bank_beneficiary_name": Schema.optionalKey(Schema.String.annotate({ "description": "(Wire only) The name of the beneficiary of the bank account that the customer sent the deposit to", "readOnly": true })), "bank_beneficiary_address": Schema.optionalKey(Schema.String.annotate({ "description": "(Wire only) The address of the beneficiary of the bank account that the customer sent the deposit to", "readOnly": true })), "bank_routing_number": Schema.optionalKey(Schema.String.annotate({ "description": "(Wire only) The routing number of the bank that the customer sent the deposit to", "readOnly": true })), "bank_name": Schema.optionalKey(Schema.String.annotate({ "description": "(Wire and SPEI only) The name of the bank that the customer sent the deposit from.", "readOnly": true })), "originator_name": Schema.optionalKey(Schema.String.annotate({ "description": "(Wire only) The originator name of this wire", "readOnly": true })), "originator_address": Schema.optionalKey(Schema.String.annotate({ "description": "(Wire only) The originator address of this wire", "readOnly": true })), "wire_message": Schema.optionalKey(Schema.String.annotate({ "description": "(Wire only) The memo for this wire", "readOnly": true })), "bridge_wallet_id": Schema.optionalKey(Schema.String.annotate({ "description": "(Bridge Wallet only) The ID of the Bridge Wallet to draw funds from" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "sender_name": Schema.optionalKey(Schema.String.annotate({ "description": "(ACH and FedNow only) The name of the business or individual who initiated the transaction", "readOnly": true })), "sender_bank_routing_number": Schema.optionalKey(Schema.String.annotate({ "description": "(ACH and FedNow only) The routing number of the entity that initiated this transaction", "readOnly": true })), "end_to_end_id": Schema.optionalKey(Schema.String.annotate({ "description": "The end-to-end ID of the FedNow transaction, assigned by the sending bank, and is not guaranteed to be unique across payments.", "readOnly": true })), "description": Schema.optionalKey(Schema.String.annotate({ "description": "(ACH only) The description of the deposit that the customer sent", "readOnly": true })), "tracking_number": Schema.optionalKey(Schema.String.annotate({ "description": "The primary tracking identifier for this fiat transaction. Format varies by payment rail (e.g., UETR for SEPA/FPS, clave de rastreo for SPEI, end-to-end ID for PIX).", "readOnly": true })), "clabe": Schema.optionalKey(Schema.String.annotate({ "description": "(SPEI only) The 18-digit CLABE of the sender who initiated this SPEI transaction", "readOnly": true }).check(Schema.isMinLength(18).annotate({ "expected": "a value with a length of at least 18" })).check(Schema.isMaxLength(18).annotate({ "expected": "a value with a length of at most 18" })).check(Schema.isPattern(new RegExp("^[0-9]+$")).annotate({ "expected": "a string matching the RegExp ^[0-9]+$" }))), "bank_code": Schema.optionalKey(Schema.String.annotate({ "description": "(SPEI only) The bank code of the sender's bank that initiated this SPEI transaction.", "readOnly": true })), "transaction_id": Schema.optionalKey(Schema.String.annotate({ "description": "Deprecated: use tracking_number instead. The unique transaction identifier for this payment.", "readOnly": true })), "co_bank_transfer": Schema.optionalKey(Schema.Struct({ "redirect_url": Schema.String.annotate({ "description": "URL to redirect the customer to after completing the bank transfer", "writeOnly": true }), "expiry_date": Schema.optionalKey(Schema.String.annotate({ "description": "Optional ISO 8601 expiry timestamp for the payment session. Defaults to 24 hours from creation.", "writeOnly": true })), "sender_data": Schema.optionalKey(Schema.Struct({ "full_name": Schema.String.annotate({ "description": "Full name of the sender" }), "document_type": Schema.Literals(["cc", "ce", "nit", "rut", "pa", "ppt", "ti", "rc", "te", "die", "nd"]).annotate({ "description": "Colombian document type identifier. `cc` = Cédula de Ciudadanía, `ce` = Cédula de Extranjería, `nit` = NIT (tax ID), `rut` = RUT (worker registration), `pa` = Passport, `ppt` = Permiso de Protección Temporal.\n" }), "document_number": Schema.String.annotate({ "description": "Document number of the sender. Masked in responses (e.g. ***3456)." }), "email": Schema.String.annotate({ "description": "Email address of the sender" }), "phone_number": Schema.String.annotate({ "description": "Phone number of the sender in E.164 format (e.g. +573001234567)" }) }).annotate({ "description": "Sender information for the CO bank transfer. If omitted, the payer must manually provide this information via the payment link. If provided, fields will be pre-populated for the payer. Sensitive fields are masked in responses (e.g. document_number shows `***3456`)." })) }).annotate({ "description": "(co_bank_transfer only) Details for Colombian bank transfers." })), "payment_received_rail": Schema.optionalKey(Schema.Literals(["ach", "wire", "ach_push", "ach_same_day", "fednow", "arbitrum", "avalanche_c_chain", "base", "bre_b", "co_bank_transfer", "bridge_wallet", "celo", "ethereum", "faster_payments", "linea", "optimism", "pix", "polygon", "sepa", "solana", "spei", "stellar", "swift", "tempo", "tron", "xdc"]).annotate({ "description": "The rail on which the payment was actually received. Set once the funds have been onramped.", "readOnly": true })), "from_address": Schema.optionalKey(Schema.String.annotate({ "description": "The crypto wallet address that the customer will send funds from, in order to kick off this transfer" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "The source of the transfer, which could be an external bank account, a bridge account, or a crypto wallet address" }), "destination": Schema.StructWithRest(Schema.Struct({ "currency": Schema.Union([Schema.Literal("brl").annotate({ "description": "The destination currency" }), Schema.Literal("cop").annotate({ "description": "The destination currency" }), Schema.Literal("eur").annotate({ "description": "The destination currency" }), Schema.Literal("eurc").annotate({ "description": "The destination currency" }), Schema.Literal("gbp").annotate({ "description": "The destination currency" }), Schema.Literal("mxn").annotate({ "description": "The destination currency" }), Schema.Literal("pyusd").annotate({ "description": "The destination currency" }), Schema.Literal("usd").annotate({ "description": "The destination currency" }), Schema.Literal("usdb").annotate({ "description": "The destination currency" }), Schema.Literal("usdc").annotate({ "description": "The destination currency" }), Schema.Literal("usdt").annotate({ "description": "The destination currency" }), Schema.Literal("usdl_linea").annotate({ "description": "The destination currency" })]).annotate({ "description": "When `eur` is specified as the destination currency, the destination rail must be `sepa`." }), "payment_rail": Schema.Union([Schema.Literal("ach").annotate({ "description": "The destination payment rail" }), Schema.Literal("wire").annotate({ "description": "The destination payment rail" }), Schema.Literal("ach_push").annotate({ "description": "The destination payment rail" }), Schema.Literal("ach_same_day").annotate({ "description": "The destination payment rail" }), Schema.Literal("arbitrum").annotate({ "description": "The destination payment rail" }), Schema.Literal("avalanche_c_chain").annotate({ "description": "The destination payment rail" }), Schema.Literal("base").annotate({ "description": "The destination payment rail" }), Schema.Literal("bre_b").annotate({ "description": "The destination payment rail" }), Schema.Literal("co_bank_transfer").annotate({ "description": "The destination payment rail" }), Schema.Literal("celo").annotate({ "description": "The destination payment rail" }), Schema.Literal("ethereum").annotate({ "description": "The destination payment rail" }), Schema.Literal("fiat_deposit_return").annotate({ "description": "The destination payment rail" }), Schema.Literal("linea").annotate({ "description": "The destination payment rail" }), Schema.Literal("optimism").annotate({ "description": "The destination payment rail" }), Schema.Literal("polygon").annotate({ "description": "The destination payment rail" }), Schema.Literal("sepa").annotate({ "description": "The destination payment rail" }), Schema.Literal("solana").annotate({ "description": "The destination payment rail" }), Schema.Literal("spei").annotate({ "description": "The destination payment rail" }), Schema.Literal("stellar").annotate({ "description": "The destination payment rail" }), Schema.Literal("swift").annotate({ "description": "The destination payment rail" }), Schema.Literal("tempo").annotate({ "description": "The destination payment rail" }), Schema.Literal("tron").annotate({ "description": "The destination payment rail" }), Schema.Literal("xdc").annotate({ "description": "The destination payment rail" })]).annotate({ "description": "When `sepa` is specified as the destination payment rail, the destination currency must be `eur`; when `swift` is specified as the destination payment rail, the destination currency must be `usd`." }), "external_account_id": Schema.optionalKey(Schema.String.annotate({ "description": "External bank account Bridge should send the funds to. The currency associated with the External Account must match the destination currency." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "bridge_wallet_id": Schema.optionalKey(Schema.String.annotate({ "description": "The Bridge Wallet to which Bridge will send the funds. The chain associated with the Bridge Wallet must match the destination payment rail." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "omad": Schema.optionalKey(Schema.String.annotate({ "description": "(Wire only) The OMAD of a wire transfer, if available", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(40).annotate({ "expected": "a value with a length of at most 40" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "imad": Schema.optionalKey(Schema.String.annotate({ "description": "(Wire only) The IMAD of a wire transfer, if available", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(40).annotate({ "expected": "a value with a length of at most 40" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "trace_number": Schema.optionalKey(Schema.String.annotate({ "description": "The trace number of an ACH transfer", "readOnly": true }).check(Schema.isMinLength(15).annotate({ "expected": "a value with a length of at least 15" })).check(Schema.isMaxLength(15).annotate({ "expected": "a value with a length of at most 15" })).check(Schema.isPattern(new RegExp("[0-9]")).annotate({ "expected": "a string matching the RegExp [0-9]" }))), "end_to_end_id": Schema.optionalKey(Schema.String.annotate({ "description": "The end-to-end ID of the FedNow transaction, assigned by the sending bank, and is not guaranteed to be unique across payments.", "readOnly": true })), "wire_message": Schema.optionalKey(Schema.String.annotate({ "description": "A message to be sent with a wire transfer, only allowed when the payment rail is a wire. This message will be validated against 4 lines, each with a max length of 35 char according to the Fedwire standard." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" }))), "sepa_reference": Schema.optionalKey(Schema.String.annotate({ "description": "A reference message to be sent with a SEPA transaction. We recommend you set a unique value to help you and your customers track payments end to end. It must be from 6 to 140 characters. The allowed characters are `a-z`, `A-Z`, `0-9`, spaces, ampersand (`&`), hyphen (`-`), full stop (`.`), and solidus (`/`). If not populated, the default value is \"Payment via Bridge {unique_token}\"." }).check(Schema.isMinLength(6).annotate({ "expected": "a value with a length of at least 6" })).check(Schema.isMaxLength(140).annotate({ "expected": "a value with a length of at most 140" }))), "swift_reference": Schema.optionalKey(Schema.String.annotate({ "description": "A payment reference message or remittance information to be included in a SWIFT transaction. It can have at most 4 lines (separated by \"\\n\"), each line with a max length of 35 chars. The allowed characters are `a-z`, `A-Z`, `0-9`, special characters (`/` `-` `?` `:` `(` `)` `.` `,` `'` `+`), and space" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(140).annotate({ "expected": "a value with a length of at most 140" }))), "spei_reference": Schema.optionalKey(Schema.String.annotate({ "description": "A payment reference message or remittance information to be included in a SPEI transaction. The allowed characters are alphanumeric `a-z`, `A-Z`, `0-9`, and space" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(40).annotate({ "expected": "a value with a length of at most 40" }))), "reference": Schema.optionalKey(Schema.Union([Schema.String.annotate({ "title": "Faster Payments" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(18).annotate({ "expected": "a value with a length of at most 18" })), Schema.String.annotate({ "title": "Pix" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(100).annotate({ "expected": "a value with a length of at most 100" }))], { mode: "oneOf" }).annotate({ "description": "A payment reference message for newer payment rails (e.g. Pix, Faster Payments, and FedNow).\n" })), "charge_bearer": Schema.optionalKey(Schema.Literals(["our", "sha", "ben"]).annotate({ "description": "Which party bears the charges for the SWIFT transaction. Defaults to `sha` when not specified. Accepted on both request and response." })), "ach_reference": Schema.optionalKey(Schema.String.annotate({ "description": "A reference message to be sent with an ACH transaction. It can be at most 10 characters, A-Z, a-z, 0-9, and spaces." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(10).annotate({ "expected": "a value with a length of at most 10" }))), "uetr": Schema.optionalKey(Schema.String.annotate({ "description": "Deprecated: use tracking_number instead. The unique end-to-end transaction reference, for tracing purposes.", "readOnly": true })), "blockchain_memo": Schema.optionalKey(Schema.String.annotate({ "description": "A message to be sent with a crypto transaction, only allowed when the payment rail supports memo, e.g. Stellar." })), "deposit_id": Schema.optionalKey(Schema.String.annotate({ "description": "A UUID that uniquely identifies a deposit" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "tracking_number": Schema.optionalKey(Schema.String.annotate({ "description": "The primary tracking identifier for this fiat transaction. Format varies by payment rail (e.g., UETR for SEPA/FPS, clave de rastreo for SPEI, end-to-end ID for PIX).", "readOnly": true })), "transaction_id": Schema.optionalKey(Schema.String.annotate({ "description": "Deprecated: use tracking_number instead. The unique transaction identifier for this payment.", "readOnly": true })), "sending_institution_name": Schema.optionalKey(Schema.String.annotate({ "description": "The name of the institution sending the funds", "readOnly": true })), "amount": Schema.optionalKey(Schema.String.annotate({ "description": "The destination amount for the recipient to receive. Present when the transfer was created with a destination amount (Fixed Outputs).\n\nDenominated in the destination currency.\n\nExpressed as a decimal string. Examples include \"100.25\", \"0.1\", \"1.234567\", \"1.01\" etc.", "readOnly": true })), "to_address": Schema.optionalKey(Schema.String.annotate({ "description": "The crypto wallet address that the customer wishes to ultimately receive funds at, in order to complete this transfer" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "The destination of the transfer, which could be an external bank account, a bridge account, or a crypto wallet address" }), "state": Schema.Literals(["awaiting_funds", "in_review", "funds_received", "payment_submitted", "payment_processed", "canceled", "undeliverable", "returned", "refund_in_flight", "refund_failed", "refunded"]).annotate({ "description": "Status of the transfer. See [Transfer States](https://apidocs.bridge.xyz/platform/orchestration/transfers/transfer-states) for more details.", "readOnly": true }), "source_deposit_instructions": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "payment_rail": Schema.Union([Schema.Literal("ach").annotate({ "description": "The source payment rail" }), Schema.Literal("wire").annotate({ "description": "The source payment rail" }), Schema.Literal("ach_push").annotate({ "description": "The source payment rail" }), Schema.Literal("ach_same_day").annotate({ "description": "The source payment rail" }), Schema.Literal("arbitrum").annotate({ "description": "The source payment rail" }), Schema.Literal("avalanche_c_chain").annotate({ "description": "The source payment rail" }), Schema.Literal("base").annotate({ "description": "The source payment rail" }), Schema.Literal("bre_b").annotate({ "description": "The source payment rail" }), Schema.Literal("co_bank_transfer").annotate({ "description": "The source payment rail" }), Schema.Literal("celo").annotate({ "description": "The source payment rail" }), Schema.Literal("ethereum").annotate({ "description": "The source payment rail" }), Schema.Literal("optimism").annotate({ "description": "The source payment rail" }), Schema.Literal("pix").annotate({ "description": "The source payment rail" }), Schema.Literal("polygon").annotate({ "description": "The source payment rail" }), Schema.Literal("solana").annotate({ "description": "The source payment rail" }), Schema.Literal("spei").annotate({ "description": "The source payment rail" }), Schema.Literal("stellar").annotate({ "description": "The source payment rail" }), Schema.Literal("tempo").annotate({ "description": "The source payment rail" })]).annotate({ "description": "The payment rail that Bridge is expecting funds to arrive on. For a crypto based source on the transfer, this is the chain, i.e. ethereum or polygon" }), "amount": Schema.String.annotate({ "description": "Amount of the deposit, expressed as a decimal string. It's denominated in the source currency if that is a fiat currency, or in the fiat currency to which the source currency is pegged. Examples include \"100.25\", \"0.1\", \"1.234567\", \"1.01\" etc." }), "currency": Schema.Union([Schema.Literal("usdb").annotate({ "description": "The source currency" }), Schema.Literal("usdc").annotate({ "description": "The source currency" }), Schema.Literal("usdt").annotate({ "description": "The source currency" }), Schema.Literal("usdl_linea").annotate({ "description": "The source currency" }), Schema.Literal("usd").annotate({ "description": "The source currency" }), Schema.Literal("pyusd").annotate({ "description": "The source currency" })]), "from_address": Schema.optionalKey(Schema.String.annotate({ "description": "The crypto wallet address that the customer will send funds from, in order to kick off this transfer" })), "to_address": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "The crypto wallet address the customer will send funds to in order to initiate the payment processing" })), "memoless_to_address": Schema.optionalKey(Schema.String.annotate({ "description": "An alternative crypto wallet address that encodes the memo, allowing the customer to send funds without needing to include a separate memo. Currently only available for Stellar deposits." })), "deposit_message": Schema.optionalKey(Schema.String.annotate({ "description": "The message that the customer MUST include in their `wire memo/message`, `ach push description`, or `sepa reference`." })), "bank_name": Schema.optionalKey(Schema.String.annotate({ "description": "The name of the bank that the customer should send the deposit to" })), "bank_address": Schema.optionalKey(Schema.String.annotate({ "description": "The address of the bank that the customer should send the deposit to. For SEPA, the country in this address should be used for sending the deposit" })), "bank_routing_number": Schema.optionalKey(Schema.String.annotate({ "description": "The routing number of the bank that the customer should send the deposit to" })), "bank_account_number": Schema.optionalKey(Schema.String.annotate({ "description": "The account number of the bank that the customer should send the deposit to" })), "bank_beneficiary_name": Schema.optionalKey(Schema.String.annotate({ "description": "The name of the beneficiary of the bank account that the customer should send the deposit to" })), "bank_beneficiary_address": Schema.optionalKey(Schema.String.annotate({ "description": "The address of the beneficiary of the bank account that the customer should send the deposit to" })), "intermediary_bank_name": Schema.optionalKey(Schema.String.annotate({ "description": "For USD SWIFT, the name of the intermediary correspondent bank that the originating bank should route the payment through." })), "intermediary_bank_bic": Schema.optionalKey(Schema.String.annotate({ "description": "For USD SWIFT, the SWIFT/BIC of the intermediary correspondent bank" })), "intermediary_bank_routing_number": Schema.optionalKey(Schema.String.annotate({ "description": "For USD SWIFT, the ABA routing number of the intermediary correspondent bank" })), "iban": Schema.optionalKey(Schema.String.annotate({ "description": "For SEPA, the International Bank Account Number (IBAN) that the customer should use to send the deposit" })), "bic": Schema.optionalKey(Schema.String.annotate({ "description": "For SEPA, the Bank Identifier Code (BIC) that the customer should use to send the deposit" })), "clabe": Schema.optionalKey(Schema.String.annotate({ "description": "For SPEI, the CLABE (account number) that the customer should use to send the deposit" })), "account_holder_name": Schema.optionalKey(Schema.String.annotate({ "description": "For SEPA, the name of the bank account holder that the customer should use to send the deposit" })), "bre_b_key": Schema.optionalKey(Schema.String.annotate({ "description": "For Bre-B (Colombia), the Bre-B key that the customer should use to send the COP deposit" })), "start_url": Schema.optionalKey(Schema.String.annotate({ "description": "For co_bank_transfer (Colombia), the URL the customer should be redirected to in order to complete the bank transfer payment" })), "redirect_url": Schema.optionalKey(Schema.String.annotate({ "description": "For co_bank_transfer (Colombia), the merchant redirect URL provided when the transfer was created" })), "expires_at": Schema.optionalKey(Schema.String.annotate({ "description": "For Pix (Brazil) and co_bank_transfer (Colombia), the ISO 8601 timestamp when the payment session expires" })), "blockchain_memo": Schema.optionalKey(Schema.String.annotate({ "description": "If present, the message that the customer MUST include in their on chain transfer. Only used for memo-based blockchains such as Stellar and Tron" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "readOnly": true, "description": "Some transfers require a deposit to be made by the customer before Bridge can start the process. Instructions for how to kick off the transfer will be included here. The deposit must match these instructions exactly, or the transfer will fail." })), "receipt": Schema.StructWithRest(Schema.Struct({ "initial_amount": Schema.String.annotate({ "description": "The initial amount of the transfer from the source, represented as a decimal string. Examples include \"100.25\", \"0.1\", \"1.234567\", \"1.01\" etc." }), "developer_fee": Schema.String.annotate({ "description": "The fee, expressed as a decimal string, represents the amount of the transfer reserved for your own account. This fee is the final amount deducted from what your customer ultimately receives, rather than a percentage." }), "exchange_fee": Schema.String.annotate({ "description": "The fee, expressed as a decimal string, represents the amount Bridge charges for facilitating the transfer. This is the final amount deducted from what your customer ultimately receives, rather than a percentage. It can be deducted from the initial amount/currency or the converted amount/currency. " }), "developer_exchange_fee": Schema.optionalKey(Schema.Struct({ "amount": Schema.optionalKey(Schema.String.annotate({ "description": "Amount of the fee" })), "currency": Schema.optionalKey(Schema.String.annotate({ "description": "Currency of the fee" })) }).annotate({ "description": "For FixedOutput trades, the amount, expressed as a decimal string, of the traded money that was not necessary to deliver the fixed output, returned to the developer." })), "pre_conversion_subtotal_amount": Schema.optionalKey(Schema.String.annotate({ "description": "On transfers with a variable trade, the amount of money, expressed as a decimal string, that is passed into the trade itself. Equal to the initial amount less any fees applied on the input side of the trade" })), "mid_market_rate": Schema.optionalKey(Schema.String.annotate({ "description": "If the transfer includes a market rate trade, this is the mid-market rate used to calculate the output of the trade. It is expressed as a decimal string." })), "converted_amount": Schema.optionalKey(Schema.String.annotate({ "description": "If the transfer includes a variable trade, the amount of money, expressed as a decimal string, received after the trade, before any final fees are deducted." })), "subtotal_amount": Schema.String.annotate({ "description": "The amount, expressed as a decimal string, remaining from the converted amount after any remaining non-gas fees have been deducted. " }), "remaining_prefunded_balance": Schema.optionalKey(Schema.String.annotate({ "description": "For Prefunded Accounts, this value will represent the remaining account balance after the transfer." })), "gas_fee": Schema.optionalKey(Schema.String.annotate({ "description": "The fee, expressed as a decimal string. It's deducted from the withdrawn amount to pay for gas. Only nonzero to crypto withdrawals that cost gas (e.g. USDT), and only known when the transaction is confirmed on-chain. Will be missing if not yet known.\n\nIt's denominated in the fiat currency to which the destination currency is pegged." })), "final_amount": Schema.optionalKey(Schema.String.annotate({ "description": "The final amount of the transfer, expressed as a decimal string, equal to the subtotal_amount minus any gas fees. If the gas fee is not known, this field will be missing. Examples include \"100.25\", \"0.1\", \"1.234567\", \"1.01\" etc.\n\nIt's denominated in the destination currency if that is a fiat currency or the fiat currency to which the destination currency is pegged." })), "source_tx_hash": Schema.optionalKey(Schema.Json.annotate({ "expected": "JSON value", "description": "The hash of the on-chain deposit to the source address, where applicable" })), "destination_tx_hash": Schema.optionalKey(Schema.Json.annotate({ "expected": "JSON value", "description": "The hash of the on-chain transfer to the destination address, where applicable" })), "exchange_rate": Schema.optionalKey(Schema.Json.annotate({ "expected": "JSON value", "description": "The effective exchange rate can be calculated by dividing the converted amount by the amount available for conversion after deducting the developer fee. This rate includes a currency conversion spread and is subject to a rounding precision loss during the calculation. Currently it's populated for SEPA onramp/offramp transfers only." })), "url": Schema.optionalKey(Schema.String.annotate({ "description": "The URL of a user-facing copy of the receipt." })), "bank_details": Schema.optionalKey(Schema.Struct({ "sending_routing_number": Schema.optionalKey(Schema.String.annotate({ "description": "Routing number of the bank Bridge sent the payment from." })), "ach_description": Schema.optionalKey(Schema.String.annotate({ "description": "Statement descriptor on the outgoing ACH credit." })), "ach_trace_id": Schema.optionalKey(Schema.String.annotate({ "description": "ACH trace number, populated after submission to the Fed." })), "wire_message": Schema.optionalKey(Schema.String.annotate({ "description": "Message sent with the outgoing wire (beneficiary, FI-to-FI, or receiving-FI message)." })), "imad": Schema.optionalKey(Schema.String.annotate({ "description": "IMAD (Input Message Accountability Data) of the outgoing wire, populated after posting." })), "recipient_name": Schema.optionalKey(Schema.String.annotate({ "description": "Name on the receiving external account." })), "sending_bic": Schema.optionalKey(Schema.String.annotate({ "description": "BIC of the bank Bridge sent the SEPA payment from." })), "sepa_reference": Schema.optionalKey(Schema.String.annotate({ "description": "SEPA payment reference." })), "uetr": Schema.optionalKey(Schema.String.annotate({ "description": "Unique End-to-end Transaction Reference (UETR) of the SEPA payment." })), "receiving_account_last_four": Schema.optionalKey(Schema.String.annotate({ "description": "Last four digits of the receiving IBAN." })), "receiving_bic": Schema.optionalKey(Schema.String.annotate({ "description": "BIC of the receiving bank." })) }).annotate({ "description": "Bank-lookup details for fiat offramp receipts, to help the recipient's bank locate the payment. Present for enabled developers once the offramp's bank leg exists; individual fields may be null until they become available (e.g. the ACH trace ID before submission to the Fed)." })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Receipt information of a transfer" }), "return_details": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "reason": Schema.optionalKey(Schema.String.annotate({ "description": "The reason for the return, as given by the returning financial institution." })), "refund_reference_id": Schema.optionalKey(Schema.String.annotate({ "description": "A unique identifier (such as transaction hash) for the refund transaction." })), "risk_rejection_reason": Schema.optionalKey(Schema.String.annotate({ "description": "If the return is due to a risk rejection, this field will be populated with the reason for the risk rejection." })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Return information, if the transfer has been returned.", "readOnly": true })), "return_instructions": Schema.optionalKey(Schema.Struct({ "address": Schema.String.annotate({ "description": "The crypto wallet address to send returned funds to. Must be valid for the source payment rail's chain." }), "memo": Schema.optionalKey(Schema.String.annotate({ "description": "Memo to include with the return transaction. Required when the source payment rail is Stellar; optional for other memo-capable chains." })) }).annotate({ "description": "Optional return instructions configured when creating or updating the transfer.", "readOnly": true })), "exchange_details": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "fixed_rate": Schema.optionalKey(Schema.String.annotate({ "description": "The target exchange rate." })), "estimated_market_rate": Schema.optionalKey(Schema.String.annotate({ "description": "The estimated achievable rate based on current market conditions." })), "traded_market_rate": Schema.optionalKey(Schema.String.annotate({ "description": "The actual effective exchange rate achieved." })), "trade_at_market": Schema.optionalKey(Schema.Boolean.annotate({ "description": "Whether market-rate execution has been applied to this trade." })), "updated_at": Schema.optionalKey(Schema.String.annotate({ "description": "Timestamp of the last exchange details update.", "format": "date-time" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Exchange details for the associated trade, if applicable.", "readOnly": true })), "created_at": Schema.String.annotate({ "description": "Time of creation of the transfer", "readOnly": true, "format": "date-time" }), "updated_at": Schema.String.annotate({ "description": "Time of update of the transfer", "readOnly": true, "format": "date-time" }), "template_id": Schema.optionalKey(Schema.String.annotate({ "description": "The ID of the static template transfer from which this transfer was instantiated. Only present for transfers created from a template.", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "first_confirmed_at": Schema.optionalKey(Schema.String.annotate({ "description": "Time when the withdrawal transaction received its first on-chain confirmation. Only present for crypto withdrawal transfers where this feature is enabled for the developer.", "readOnly": true, "format": "date-time" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "identifier": "TransferResponse" }) +export type PlaidLinkRequest = { readonly "link_token"?: string, readonly "link_token_expires_at"?: string, readonly "callback_url"?: string } & { readonly [x: string]: Schema.Json } +export const PlaidLinkRequest = Schema.StructWithRest(Schema.Struct({ "link_token": Schema.optionalKey(Schema.String.annotate({ "description": "Link token generated via the Plaid Link SDK" })), "link_token_expires_at": Schema.optionalKey(Schema.String.annotate({ "description": "Expiration time of the link token", "format": "date-time" })), "callback_url": Schema.optionalKey(Schema.String.annotate({ "description": "URL to call through Plaid Link Flow's onSuccess callback with the public token passed in the body of the request" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "identifier": "PlaidLinkRequest" }) +export type PlaidExchangePublicToken = { readonly "public_token": string } & { readonly [x: string]: Schema.Json } +export const PlaidExchangePublicToken = Schema.StructWithRest(Schema.Struct({ "public_token": Schema.String.annotate({ "description": "Public token generated via the Plaid Link SDK" }) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "identifier": "PlaidExchangePublicToken" }) +export type TransferRequest = { readonly "id"?: string, readonly "client_reference_id"?: string, readonly "amount"?: string, readonly "on_behalf_of": string, readonly "developer_fee"?: string, readonly "developer_fee_percent"?: string, readonly "dry_run"?: boolean, readonly "source": { readonly "currency": "brl" | "cop" | "eur" | "eurc" | "gbp" | "mxn" | "pyusd" | "usd" | "usdb" | "usdc" | "usdt" | "usdl_linea", readonly "payment_rail": "ach" | "wire" | "ach_push" | "ach_same_day" | "fednow" | "arbitrum" | "avalanche_c_chain" | "base" | "bre_b" | "co_bank_transfer" | "bridge_wallet" | "celo" | "ethereum" | "faster_payments" | "linea" | "optimism" | "pix" | "polygon" | "sepa" | "solana" | "spei" | "stellar" | "swift" | "tempo" | "tron" | "xdc", readonly "payment_scheme"?: "sepa_credit" | "sepa_instant", readonly "omad"?: string, readonly "imad"?: string, readonly "trace_number"?: string, readonly "bank_beneficiary_name"?: string, readonly "bank_beneficiary_address"?: string, readonly "bank_routing_number"?: string, readonly "bank_name"?: string, readonly "originator_name"?: string, readonly "originator_address"?: string, readonly "wire_message"?: string, readonly "bridge_wallet_id"?: string, readonly "sender_name"?: string, readonly "sender_bank_routing_number"?: string, readonly "end_to_end_id"?: string, readonly "description"?: string, readonly "tracking_number"?: string, readonly "clabe"?: string, readonly "bank_code"?: string, readonly "transaction_id"?: string, readonly "co_bank_transfer"?: { readonly "redirect_url": string, readonly "expiry_date"?: string, readonly "sender_data"?: { readonly "full_name": string, readonly "document_type": "cc" | "ce" | "nit" | "rut" | "pa" | "ppt" | "ti" | "rc" | "te" | "die" | "nd", readonly "document_number": string, readonly "email": string, readonly "phone_number": string } }, readonly "from_address"?: string } & { readonly [x: string]: Schema.Json }, readonly "destination": { readonly "currency": "brl" | "cop" | "eur" | "eurc" | "gbp" | "mxn" | "pyusd" | "usd" | "usdb" | "usdc" | "usdt" | "usdl_linea", readonly "payment_rail": "ach" | "wire" | "ach_push" | "ach_same_day" | "fednow" | "arbitrum" | "avalanche_c_chain" | "base" | "bre_b" | "co_bank_transfer" | "celo" | "ethereum" | "fiat_deposit_return" | "linea" | "optimism" | "polygon" | "sepa" | "solana" | "spei" | "stellar" | "swift" | "tempo" | "tron" | "xdc", readonly "external_account_id"?: string, readonly "bridge_wallet_id"?: string, readonly "omad"?: string, readonly "imad"?: string, readonly "trace_number"?: string, readonly "end_to_end_id"?: string, readonly "wire_message"?: string, readonly "sepa_reference"?: string, readonly "swift_reference"?: string, readonly "spei_reference"?: string, readonly "reference"?: string | string, readonly "charge_bearer"?: "our" | "sha" | "ben", readonly "ach_reference"?: string, readonly "uetr"?: string, readonly "blockchain_memo"?: string, readonly "deposit_id"?: string, readonly "tracking_number"?: string, readonly "transaction_id"?: string, readonly "sending_institution_name"?: string, readonly "amount"?: string, readonly "to_address"?: string } & { readonly [x: string]: Schema.Json }, readonly "features"?: { readonly "flexible_amount"?: boolean, readonly "static_template"?: boolean, readonly "allow_any_from_address"?: boolean }, readonly "return_instructions"?: { readonly "address": string, readonly "memo"?: string }, readonly "initiation"?: { readonly "channel": "p2p_mobile_payment" | "other_mobile_payment" | "other", readonly "subchannel": "remote" | "non_remote", readonly "attestations": { readonly "sca": { readonly "outcome": "sca_used" | "payment_to_self" | "trusted_beneficiaries" | "recurring_transaction" | "contactless_low_value" | "unattended_terminal_for_transport" | "low_value" | "secure_corporate_payment" | "transaction_risk_analysis" | "merchant_initiated_transaction" | "not_applicable" | "other", readonly "auth_factors"?: ReadonlyArray<{ readonly "category": "knowledge" | "possession" | "inherence", readonly "authenticated_at": string, readonly "reference": string }> } } }, readonly "travel_rule_data"?: { readonly "originator"?: { readonly "is_self"?: boolean, readonly "name"?: string, readonly "address"?: { readonly "street_line_1"?: string, readonly "street_line_2"?: string, readonly "city"?: string, readonly "state"?: string, readonly "postal_code"?: string, readonly "country"?: string }, readonly "wallet_type"?: "hosted" | "external" | "self_custodied", readonly "wallet_attested_ownership_at"?: string, readonly "identifying_information"?: ReadonlyArray<{ readonly "type": "drivers_license" | "matriculate_id" | "military_id" | "national_id" | "passport" | "permanent_residency_id" | "state_or_provincial_id" | "visa" | "abn" | "acn" | "ahv" | "ak" | "aom" | "arbn" | "avs" | "bc" | "bce" | "bin" | "bir" | "bp" | "brn" | "bsn" | "bvn" | "cc" | "cdi" | "cedula_juridica" | "cf" | "cif" | "cin" | "cipc" | "cn" | "cnp" | "cnpj" | "cpf" | "cpr" | "crc" | "crib" | "crn" | "cro" | "cui" | "cuil" | "curp" | "cuit" | "cvr" | "edrpou" | "ein" | "embg" | "emirates_id" | "en" | "fin" | "fn" | "gstin" | "gui" | "hetu" | "hkid" | "hn" | "ic" | "ico" | "id" | "id_broj" | "idno" | "idnp" | "idnr" | "if" | "iin" | "ik" | "inn" | "ird" | "itin" | "itr" | "iva" | "jmbg" | "kbo" | "kvk" | "matricule" | "mf" | "mn" | "ms" | "mst" | "nic" | "nicn" | "nie" | "nif" | "nin" | "nino" | "nip" | "nipc" | "nipt" | "nit" | "npwp" | "nric" | "nrn" | "nrt" | "ntn" | "nuit" | "nzbn" | "oib" | "orgnr" | "other" | "pan" | "partita_iva" | "pesel" | "pib" | "pin" | "pk" | "ppsn" | "qid" | "rc" | "regon" | "rfc" | "ricn" | "rif" | "rn" | "rnc" | "rnokpp" | "rp" | "rrn" | "rtn" | "ruc" | "rut" | "si" | "sin" | "siren" | "siret" | "spi" | "ssm" | "ssn" | "steuer_id" | "strn" | "tckn" | "tfn" | "tin" | "tpin" | "trn" | "ucn" | "uen" | "uic" | "uid" | "usc" | "ust_idnr" | "utr" | "vat" | "vkn" | "voen" | "y_tunnus", readonly "issuing_country": string, readonly "number"?: string, readonly "description"?: string, readonly "expiration"?: string, readonly "image_front"?: string, readonly "image_back"?: string }>, readonly "birth_date"?: string, readonly "place_of_birth"?: { readonly "country"?: string, readonly "city"?: string }, readonly "legal_entity_identifier"?: string }, readonly "beneficiary"?: { readonly "is_self"?: boolean, readonly "name"?: string, readonly "address"?: { readonly "street_line_1"?: string, readonly "street_line_2"?: string, readonly "city"?: string, readonly "state"?: string, readonly "postal_code"?: string, readonly "country"?: string }, readonly "wallet_type"?: "hosted" | "external" | "self_custodied", readonly "wallet_attested_ownership_at"?: string, readonly "legal_entity_identifier"?: string } } } & { readonly [x: string]: Schema.Json } +export const TransferRequest = Schema.StructWithRest(Schema.Struct({ "id": Schema.optionalKey(Schema.String.annotate({ "description": "A UUID that uniquely identifies a resource", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "client_reference_id": Schema.optionalKey(Schema.String.annotate({ "description": "A client-provided reference ID that uniquely identifies a resource in the client's system" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" }))), "amount": Schema.optionalKey(Schema.String.annotate({ "description": "Amount of the transfer, expressed as a decimal string. Examples include \"100.25\", \"0.1\", \"1.234567\", \"1.01\" etc.\n\nIt is denominated in the source currency if that is a fiat currency, or in the fiat currency to which the source currency is pegged." })), "on_behalf_of": Schema.String.annotate({ "description": "The id of the Bridge customer that you are moving funds on behalf of." }), "developer_fee": Schema.optionalKey(Schema.String.annotate({ "description": "The fee, expressed as a decimal string, represents the amount you wish to reserve for your own account. This fee is the final amount deducted from what your customer ultimately receives, rather than a percentage.\n\nIt is denominated in the source currency if that is a fiat currency, or in the fiat currency to which the source currency is pegged." })), "developer_fee_percent": Schema.optionalKey(Schema.String.annotate({ "description": "The fee percent, expressed as a decimal string from `0.0` to `100.0`, represents the percentage of the transfer you wish to reserve for your own account.\n\nThis field must be set instead of `developer_fee` when using [Flexible Amounts](https://apidocs.bridge.xyz/platform/orchestration/fees-and-mins/devfees#transfers-with-fixed-amounts)." })), "dry_run": Schema.optionalKey(Schema.Boolean.annotate({ "description": "Whether to validate the transfer route without creating a transfer. If set to true, a valid transfer will return a `TransferRouteResponse` indicating the transfer would have been valid. The same error response will be returned for an invalid transfer as in the non-dry-run case." })), "source": Schema.StructWithRest(Schema.Struct({ "currency": Schema.Literals(["brl", "cop", "eur", "eurc", "gbp", "mxn", "pyusd", "usd", "usdb", "usdc", "usdt", "usdl_linea"]).annotate({ "description": "When `eur` is specified as the source currency:\n 1. the source rail must be `sepa`;\n 2. only `usdc` or `eurc` are supported as the destination currency" }), "payment_rail": Schema.Literals(["ach", "wire", "ach_push", "ach_same_day", "fednow", "arbitrum", "avalanche_c_chain", "base", "bre_b", "co_bank_transfer", "bridge_wallet", "celo", "ethereum", "faster_payments", "linea", "optimism", "pix", "polygon", "sepa", "solana", "spei", "stellar", "swift", "tempo", "tron", "xdc"]).annotate({ "description": "When `sepa` is specified as the source rail:\n 1. the source currency must be `eur`;\n 2. only `usdc` or `eurc` are supported as the destination currency \n\n **Note: This is the intended payment rail, and may differ from the actual payment rail used to onramp the funds.**" }), "payment_scheme": Schema.optionalKey(Schema.Literals(["sepa_credit", "sepa_instant"]).annotate({ "description": "(SEPA only) The payment scheme used for this transaction, such as SEPA Credit Transfer or SEPA Instant", "readOnly": true })), "omad": Schema.optionalKey(Schema.String.annotate({ "description": "(Wire only) The OMAD of a wire transfer, if available", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(40).annotate({ "expected": "a value with a length of at most 40" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "imad": Schema.optionalKey(Schema.String.annotate({ "description": "(Wire only) The IMAD of a wire transfer, if available", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(40).annotate({ "expected": "a value with a length of at most 40" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "trace_number": Schema.optionalKey(Schema.String.annotate({ "description": "The trace number of an ACH transfer", "readOnly": true }).check(Schema.isMinLength(15).annotate({ "expected": "a value with a length of at least 15" })).check(Schema.isMaxLength(15).annotate({ "expected": "a value with a length of at most 15" })).check(Schema.isPattern(new RegExp("[0-9]")).annotate({ "expected": "a string matching the RegExp [0-9]" }))), "bank_beneficiary_name": Schema.optionalKey(Schema.String.annotate({ "description": "(Wire only) The name of the beneficiary of the bank account that the customer sent the deposit to", "readOnly": true })), "bank_beneficiary_address": Schema.optionalKey(Schema.String.annotate({ "description": "(Wire only) The address of the beneficiary of the bank account that the customer sent the deposit to", "readOnly": true })), "bank_routing_number": Schema.optionalKey(Schema.String.annotate({ "description": "(Wire only) The routing number of the bank that the customer sent the deposit to", "readOnly": true })), "bank_name": Schema.optionalKey(Schema.String.annotate({ "description": "(Wire and SPEI only) The name of the bank that the customer sent the deposit from.", "readOnly": true })), "originator_name": Schema.optionalKey(Schema.String.annotate({ "description": "(Wire only) The originator name of this wire", "readOnly": true })), "originator_address": Schema.optionalKey(Schema.String.annotate({ "description": "(Wire only) The originator address of this wire", "readOnly": true })), "wire_message": Schema.optionalKey(Schema.String.annotate({ "description": "(Wire only) The memo for this wire", "readOnly": true })), "bridge_wallet_id": Schema.optionalKey(Schema.String.annotate({ "description": "(Bridge Wallet only) The ID of the Bridge Wallet to draw funds from" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "sender_name": Schema.optionalKey(Schema.String.annotate({ "description": "(ACH and FedNow only) The name of the business or individual who initiated the transaction", "readOnly": true })), "sender_bank_routing_number": Schema.optionalKey(Schema.String.annotate({ "description": "(ACH and FedNow only) The routing number of the entity that initiated this transaction", "readOnly": true })), "end_to_end_id": Schema.optionalKey(Schema.String.annotate({ "description": "The end-to-end ID of the FedNow transaction, assigned by the sending bank, and is not guaranteed to be unique across payments.", "readOnly": true })), "description": Schema.optionalKey(Schema.String.annotate({ "description": "(ACH only) The description of the deposit that the customer sent", "readOnly": true })), "tracking_number": Schema.optionalKey(Schema.String.annotate({ "description": "The primary tracking identifier for this fiat transaction. Format varies by payment rail (e.g., UETR for SEPA/FPS, clave de rastreo for SPEI, end-to-end ID for PIX).", "readOnly": true })), "clabe": Schema.optionalKey(Schema.String.annotate({ "description": "(SPEI only) The 18-digit CLABE of the sender who initiated this SPEI transaction", "readOnly": true }).check(Schema.isMinLength(18).annotate({ "expected": "a value with a length of at least 18" })).check(Schema.isMaxLength(18).annotate({ "expected": "a value with a length of at most 18" })).check(Schema.isPattern(new RegExp("^[0-9]+$")).annotate({ "expected": "a string matching the RegExp ^[0-9]+$" }))), "bank_code": Schema.optionalKey(Schema.String.annotate({ "description": "(SPEI only) The bank code of the sender's bank that initiated this SPEI transaction.", "readOnly": true })), "transaction_id": Schema.optionalKey(Schema.String.annotate({ "description": "Deprecated: use tracking_number instead. The unique transaction identifier for this payment.", "readOnly": true })), "co_bank_transfer": Schema.optionalKey(Schema.Struct({ "redirect_url": Schema.String.annotate({ "description": "URL to redirect the customer to after completing the bank transfer", "writeOnly": true }), "expiry_date": Schema.optionalKey(Schema.String.annotate({ "description": "Optional ISO 8601 expiry timestamp for the payment session. Defaults to 24 hours from creation.", "writeOnly": true })), "sender_data": Schema.optionalKey(Schema.Struct({ "full_name": Schema.String.annotate({ "description": "Full name of the sender" }), "document_type": Schema.Literals(["cc", "ce", "nit", "rut", "pa", "ppt", "ti", "rc", "te", "die", "nd"]).annotate({ "description": "Colombian document type identifier. `cc` = Cédula de Ciudadanía, `ce` = Cédula de Extranjería, `nit` = NIT (tax ID), `rut` = RUT (worker registration), `pa` = Passport, `ppt` = Permiso de Protección Temporal.\n" }), "document_number": Schema.String.annotate({ "description": "Document number of the sender. Masked in responses (e.g. ***3456)." }), "email": Schema.String.annotate({ "description": "Email address of the sender" }), "phone_number": Schema.String.annotate({ "description": "Phone number of the sender in E.164 format (e.g. +573001234567)" }) }).annotate({ "description": "Sender information for the CO bank transfer. If omitted, the payer must manually provide this information via the payment link. If provided, fields will be pre-populated for the payer. Sensitive fields are masked in responses (e.g. document_number shows `***3456`)." })) }).annotate({ "description": "(co_bank_transfer only) Details for Colombian bank transfers." })), "from_address": Schema.optionalKey(Schema.String.annotate({ "description": "The crypto wallet address that the customer will send funds from, in order to kick off this transfer." })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "The source of the transfer, which could be an external bank account, a bridge account, or a crypto wallet address." }), "destination": Schema.StructWithRest(Schema.Struct({ "currency": Schema.Literals(["brl", "cop", "eur", "eurc", "gbp", "mxn", "pyusd", "usd", "usdb", "usdc", "usdt", "usdl_linea"]).annotate({ "description": "When `eur` is specified as the destination currency, the destination rail must be `sepa`." }), "payment_rail": Schema.Literals(["ach", "wire", "ach_push", "ach_same_day", "fednow", "arbitrum", "avalanche_c_chain", "base", "bre_b", "co_bank_transfer", "celo", "ethereum", "fiat_deposit_return", "linea", "optimism", "polygon", "sepa", "solana", "spei", "stellar", "swift", "tempo", "tron", "xdc"]).annotate({ "description": "When `sepa` is specified as the destination payment rail, the destination currency must be `eur`; when `swift` is specified as the destination payment rail, the destination currency must be `usd`." }), "external_account_id": Schema.optionalKey(Schema.String.annotate({ "description": "External bank account Bridge should send the funds to. The currency associated with the External Account must match the destination currency." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "bridge_wallet_id": Schema.optionalKey(Schema.String.annotate({ "description": "The Bridge Wallet to which Bridge will send the funds. The chain associated with the Bridge Wallet must match the destination payment rail." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "omad": Schema.optionalKey(Schema.String.annotate({ "description": "(Wire only) The OMAD of a wire transfer, if available", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(40).annotate({ "expected": "a value with a length of at most 40" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "imad": Schema.optionalKey(Schema.String.annotate({ "description": "(Wire only) The IMAD of a wire transfer, if available", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(40).annotate({ "expected": "a value with a length of at most 40" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "trace_number": Schema.optionalKey(Schema.String.annotate({ "description": "The trace number of an ACH transfer", "readOnly": true }).check(Schema.isMinLength(15).annotate({ "expected": "a value with a length of at least 15" })).check(Schema.isMaxLength(15).annotate({ "expected": "a value with a length of at most 15" })).check(Schema.isPattern(new RegExp("[0-9]")).annotate({ "expected": "a string matching the RegExp [0-9]" }))), "end_to_end_id": Schema.optionalKey(Schema.String.annotate({ "description": "The end-to-end ID of the FedNow transaction, assigned by the sending bank, and is not guaranteed to be unique across payments.", "readOnly": true })), "wire_message": Schema.optionalKey(Schema.String.annotate({ "description": "A message to be sent with a wire transfer. It can have up to 140 characters. This message will be validated against 4 lines, each with a max length of 35 characters according to the Fedwire standard." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" }))), "sepa_reference": Schema.optionalKey(Schema.String.annotate({ "description": "A reference message to be sent with a SEPA transaction. We recommend you set a unique value to help you and your customers track payments end to end. It must be from 6 to 140 characters. The allowed characters are `a-z`, `A-Z`, `0-9`, spaces, ampersand (`&`), hyphen (`-`), full stop (`.`), and solidus (`/`). If not populated, the default value is \"Payment via Bridge {unique_token}\"." }).check(Schema.isMinLength(6).annotate({ "expected": "a value with a length of at least 6" })).check(Schema.isMaxLength(140).annotate({ "expected": "a value with a length of at most 140" }))), "swift_reference": Schema.optionalKey(Schema.String.annotate({ "description": "A payment reference message or remittance information to be included in a SWIFT transaction. It can have at most 4 lines (separated by \"\\n\"), each line with a max length of 35 chars. The allowed characters are `a-z`, `A-Z`, `0-9`, special characters (`/` `-` `?` `:` `(` `)` `.` `,` `'` `+`), and space" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(140).annotate({ "expected": "a value with a length of at most 140" }))), "spei_reference": Schema.optionalKey(Schema.String.annotate({ "description": "A payment reference message or remittance information to be included in a SPEI transaction. The allowed characters are alphanumeric `a-z`, `A-Z`, `0-9`, and space" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(40).annotate({ "expected": "a value with a length of at most 40" }))), "reference": Schema.optionalKey(Schema.Union([Schema.String.annotate({ "title": "Faster Payments" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(18).annotate({ "expected": "a value with a length of at most 18" })), Schema.String.annotate({ "title": "Pix" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(100).annotate({ "expected": "a value with a length of at most 100" }))], { mode: "oneOf" }).annotate({ "description": "A payment reference message for newer payment rails (e.g. Pix, Faster Payments, and FedNow).\n" })), "charge_bearer": Schema.optionalKey(Schema.Literals(["our", "sha", "ben"]).annotate({ "description": "Which party bears the charges for the SWIFT transaction. Defaults to `sha` when not specified. Accepted on both request and response." })), "ach_reference": Schema.optionalKey(Schema.String.annotate({ "description": "A reference message to be sent with an ACH transaction. It can be at most 10 characters, A-Z, a-z, 0-9, and spaces." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(10).annotate({ "expected": "a value with a length of at most 10" }))), "uetr": Schema.optionalKey(Schema.String.annotate({ "description": "Deprecated: use tracking_number instead. The unique end-to-end transaction reference, for tracing purposes.", "readOnly": true })), "blockchain_memo": Schema.optionalKey(Schema.String.annotate({ "description": "The memo to include when sending funds on chain. Only allowed for blockchains that support memos such as Stellar" })), "deposit_id": Schema.optionalKey(Schema.String.annotate({ "description": "A UUID that uniquely identifies a deposit" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "tracking_number": Schema.optionalKey(Schema.String.annotate({ "description": "The primary tracking identifier for this fiat transaction. Format varies by payment rail (e.g., UETR for SEPA/FPS, clave de rastreo for SPEI, end-to-end ID for PIX).", "readOnly": true })), "transaction_id": Schema.optionalKey(Schema.String.annotate({ "description": "Deprecated: use tracking_number instead. The unique transaction identifier for this payment.", "readOnly": true })), "sending_institution_name": Schema.optionalKey(Schema.String.annotate({ "description": "The name of the institution sending the funds", "readOnly": true })), "amount": Schema.optionalKey(Schema.String.annotate({ "description": "Specify the destination amount for the recipient to receive. Learn more at [Fixed Outputs Integration Guide](https://apidocs.bridge.xyz/get-started/guides/move-money/fixed_outputs_integration_guide).\n\nDenominated in the destination currency.\n\nExpressed as a decimal string. Examples include \"100.25\", \"0.1\", \"1.234567\", \"1.01\" etc." })), "to_address": Schema.optionalKey(Schema.String.annotate({ "description": "The crypto wallet address that the customer wishes to ultimately receive funds at, in order to complete this transfer" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "The destination of the transfer, which could be an external bank account, a bridge account, or a crypto wallet address." }), "features": Schema.optionalKey(Schema.Struct({ "flexible_amount": Schema.optionalKey(Schema.Boolean.annotate({ "description": "Allows for variable amounts to be accepted. When true, omit `amount` from the request body. Required to be `true` when the source payment rail is `swift`." })), "static_template": Schema.optionalKey(Schema.Boolean), "allow_any_from_address": Schema.optionalKey(Schema.Boolean) }).annotate({ "description": "Features that should be enabled for this transfer. See [Transfer Features](https://apidocs.bridge.xyz/platform/orchestration/transfers/transfer-features) for more details." })), "return_instructions": Schema.optionalKey(Schema.Struct({ "address": Schema.String.annotate({ "description": "The crypto wallet address to send returned funds to. Must be valid for the source payment rail's chain." }), "memo": Schema.optionalKey(Schema.String.annotate({ "description": "Memo to include with the return transaction. Required when the source payment rail is Stellar; optional for other memo-capable chains." })) }).annotate({ "description": "Optional instructions for where to send funds if the transfer is returned (e.g. refund). Only supported when the source payment rail is crypto. When the source is Stellar, `memo` is required." })), "initiation": Schema.optionalKey(Schema.Struct({ "channel": Schema.Literals(["p2p_mobile_payment", "other_mobile_payment", "other"]).annotate({ "description": "How the payment was initiated. Use `p2p_mobile_payment` for peer-to-peer transfers initiated on a mobile device; `other_mobile_payment` for non-P2P mobile-initiated payments (e.g. a merchant payment via a mobile app); `other` for payments not relying on a mobile device." }), "subchannel": Schema.Literals(["remote", "non_remote"]).annotate({ "description": "Whether the payment was made remotely or in person. Use `remote` for payments initiated from a distance (mobile app, online banking, or e-commerce checkout); `non_remote` for payments made in person (physical card, payment terminal, or contactless tap)." }), "attestations": Schema.Struct({ "sca": Schema.Struct({ "outcome": Schema.Literals(["sca_used", "payment_to_self", "trusted_beneficiaries", "recurring_transaction", "contactless_low_value", "unattended_terminal_for_transport", "low_value", "secure_corporate_payment", "transaction_risk_analysis", "merchant_initiated_transaction", "not_applicable", "other"]).annotate({ "description": "Whether Strong Customer Authentication (SCA) was applied or which regulatory exemption or non-applicability reason covers this payment. Use `sca_used` when the user authenticated with SCA. Otherwise, choose the value that applies: `payment_to_self` — payer and payee are the same person (remote only); `trusted_beneficiaries` — payee is on the user's pre-approved list; `recurring_transaction` — amount and payee match a previously SCA-authorized recurring series; `contactless_low_value` — contactless card payment below the low-value threshold (non-remote only); `unattended_terminal_for_transport` — automated terminal for transport fares or parking (non-remote only); `low_value` — remote payment below the low-value threshold (remote only); `secure_corporate_payment` — dedicated corporate payment process with controls equivalent to SCA (remote only); `transaction_risk_analysis` — PSP has performed real-time risk analysis and the transaction falls within permitted thresholds (remote only); `merchant_initiated_transaction` — payment triggered by the merchant without the payer present, on a pre-authorized mandate (remote only); `not_applicable` — this flow requires initiation context but SCA and SCA exemptions do not apply; `other` — another recognized exemption not listed above." }), "auth_factors": Schema.optionalKey(Schema.Array(Schema.Struct({ "category": Schema.Literals(["knowledge", "possession", "inherence"]).annotate({ "description": "The type of authentication factor used. Must be one of: `knowledge` (something only the user knows, e.g. a PIN or password), `possession` (something only the user has, e.g. a phone receiving an OTP or a hardware token), or `inherence` (something the user is, e.g. a fingerprint or face scan). When `outcome` is `sca_used`, the two factors in `auth_factors` must belong to two different categories." }), "authenticated_at": Schema.String.annotate({ "description": "The ISO 8601 timestamp when this factor was authenticated.", "format": "date-time" }), "reference": Schema.String.annotate({ "description": "Your internal identifier for this authentication event (e.g. a session ID, transaction ID, or audit log reference). Used for reconciliation; Bridge does not validate its format." }) })).annotate({ "description": "Authentication factor metadata. Optional when `outcome` is `sca_used`; if provided, it must contain at least two entries from different `category` values (e.g. one `possession` factor and one `knowledge` factor). Omit this field for any other outcome." }).check(Schema.isMinLength(2).annotate({ "expected": "a value with a length of at least 2" }))) }) }) }).annotate({ "description": "Payment initiation context required for transfers sourced from wallets where `initiation_required: true`. Captures how the payment was initiated (channel and subchannel) and whether Strong Customer Authentication was applied or which SCA exemption was used. This object is accepted on create only and is not returned in transfer responses.", "writeOnly": true })), "travel_rule_data": Schema.optionalKey(Schema.Struct({ "originator": Schema.optionalKey(Schema.Struct({ "is_self": Schema.optionalKey(Schema.Boolean.annotate({ "description": "Set to `true` when this party is the same person or business as the Bridge customer on the resource. When `true`, Bridge uses the customer's name and address on file instead of relying on `name` and `address` in this payload." })), "name": Schema.optionalKey(Schema.String.annotate({ "description": "Legal name of the originator or beneficiary. Usually omitted when `is_self` is `true`." })), "address": Schema.optionalKey(Schema.Struct({ "street_line_1": Schema.optionalKey(Schema.String), "street_line_2": Schema.optionalKey(Schema.String), "city": Schema.optionalKey(Schema.String), "state": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-2 subdivision code." })), "postal_code": Schema.optionalKey(Schema.String), "country": Schema.optionalKey(Schema.String.annotate({ "description": "Three-letter alpha-3 country code as defined in the ISO 3166-1 spec." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))) }).annotate({ "description": "Address for travel rule submissions. All fields are optional to support partial address data (e.g. country-only)." })), "wallet_type": Schema.optionalKey(Schema.Literals(["hosted", "external", "self_custodied"]).annotate({ "description": "Indicates the custody model for the wallet. Use `self_custodied` for customer-owned wallets (customer controls private keys), `hosted` for wallets managed by a developer or regulated entity on behalf of the customer, or `external` for wallets belonging to external exchanges or smart contracts." })), "wallet_attested_ownership_at": Schema.optionalKey(Schema.String.annotate({ "description": "Required when `wallet_type` is `self-custodied` or `hosted`. Must be a timestamp in the past indicating when wallet ownership was attested.", "format": "date-time" })), "identifying_information": Schema.optionalKey(Schema.Array(Schema.Struct({ "type": Schema.Literals(["drivers_license", "matriculate_id", "military_id", "national_id", "passport", "permanent_residency_id", "state_or_provincial_id", "visa", "abn", "acn", "ahv", "ak", "aom", "arbn", "avs", "bc", "bce", "bin", "bir", "bp", "brn", "bsn", "bvn", "cc", "cdi", "cedula_juridica", "cf", "cif", "cin", "cipc", "cn", "cnp", "cnpj", "cpf", "cpr", "crc", "crib", "crn", "cro", "cui", "cuil", "curp", "cuit", "cvr", "edrpou", "ein", "embg", "emirates_id", "en", "fin", "fn", "gstin", "gui", "hetu", "hkid", "hn", "ic", "ico", "id", "id_broj", "idno", "idnp", "idnr", "if", "iin", "ik", "inn", "ird", "itin", "itr", "iva", "jmbg", "kbo", "kvk", "matricule", "mf", "mn", "ms", "mst", "nic", "nicn", "nie", "nif", "nin", "nino", "nip", "nipc", "nipt", "nit", "npwp", "nric", "nrn", "nrt", "ntn", "nuit", "nzbn", "oib", "orgnr", "other", "pan", "partita_iva", "pesel", "pib", "pin", "pk", "ppsn", "qid", "rc", "regon", "rfc", "ricn", "rif", "rn", "rnc", "rnokpp", "rp", "rrn", "rtn", "ruc", "rut", "si", "sin", "siren", "siret", "spi", "ssm", "ssn", "steuer_id", "strn", "tckn", "tfn", "tin", "tpin", "trn", "ucn", "uen", "uic", "uid", "usc", "ust_idnr", "utr", "vat", "vkn", "voen", "y_tunnus"]).annotate({ "description": "Tax identification number type or government-issued ID document type (see enum). Country-specific tax and national ID lists: [Individuals](https://apidocs.bridge.xyz/docs/individual-tax-identification-numbers-by-country), [Businesses](https://apidocs.bridge.xyz/docs/business-tax-identification-numbers-by-country).\n\n**EEA / BBSA (policy in `eea_requirements.rb`):** In-scope individuals and UBOs need **both** a valid national-ID-type entry and a valid TIN per [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements). In-scope businesses need business registration **and** business tax ID types per country tables there. **TIN issuing country** must match residence (individuals) or incorporation (businesses). **Foreign tax** outside the incorporation country: set `has_foreign_tax_registration` on the business customer and add TIN objects per jurisdiction ([foreign tax / tax residency](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#tax-residency-status-foreign-tax-registry)).\n" }), "issuing_country": Schema.String.annotate({ "description": "The ISO 3166-1 (three-character) country code that issued the provided document." }), "number": Schema.optionalKey(Schema.String.annotate({ "description": "The unique identifier of the document. Required if this document is being used as a tax identification number (e.g., you are providing a passport or national_id with no other identification)." })), "description": Schema.optionalKey(Schema.String.annotate({ "description": "A description describing the provided document. This field is required when `other` is selected." })), "expiration": Schema.optionalKey(Schema.String.annotate({ "description": "The expiration date of the given document in yyyy-mm-dd format." })), "image_front": Schema.optionalKey(Schema.String.annotate({ "description": "This field is optionally accepted for tax_id types, but required for government_id types. Base64 encoded image* of the front side of the provided document, following the data-uri scheme i.e. data:image/[type];base64,[base_64_encoded_file_contents], with a minimum size of 200px x 200px \\n\\n*Maximum File Size: 15MB\\n\\n*Valid file types: .pdf, .jpeg, .jpg, .png, .heic, .tif\n\n_Note: When combined with an `image_back`, the combined size of both images must not exceed 24MB._\n" })), "image_back": Schema.optionalKey(Schema.String.annotate({ "description": "Base64 encoded image* of the back side of the provided document, following the data-uri scheme i.e. data:image/[type];base64,[base_64_encoded_file_contents], with a minimum size of 200px x 200px \\n\\n*Maximum File Size: 15MB\\n\\n*Valid file types: .pdf, .jpeg, .jpg, .png, .heic, .tif\n\n_Note: When combined with an `image_front`, the combined size of both images must not exceed 24MB._\n" })) })).annotate({ "title": "Identification Information", "writeOnly": true, "description": "List of identification objects for the originator. Do **not** include `image_front` or `image_back` fields in this context; those are not accepted in Travel Rule submissions.\n" })), "birth_date": Schema.optionalKey(Schema.String.annotate({ "description": "Date of birth in format yyyy-mm-dd." }).check(Schema.isMinLength(10).annotate({ "expected": "a value with a length of at least 10" })).check(Schema.isMaxLength(10).annotate({ "expected": "a value with a length of at most 10" }))), "place_of_birth": Schema.optionalKey(Schema.Struct({ "country": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-1 alpha-3 country code for the place of birth." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))), "city": Schema.optionalKey(Schema.String.annotate({ "description": "City of birth (recommended for EEA)." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))) }).annotate({ "description": "Country (and optionally city) of birth. **EEA / BBSA in-scope customers:** supply when onboarding individuals or associated persons under the [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#country-of-birth-and-city-of-birth). This is a sparse address — no street address. At least `country` should be present when the object is sent; `city` is recommended and will be required by EU law in 2027.\n" })), "legal_entity_identifier": Schema.optionalKey(Schema.String.annotate({ "description": "The Legal Entity Identifier (LEI) or equivalent (e.g. VAT number) of the originator. Provide this when the originator is a legal entity rather than an individual." })) }).annotate({ "description": "Travel Rule details for originator crypto movement." })), "beneficiary": Schema.optionalKey(Schema.Struct({ "is_self": Schema.optionalKey(Schema.Boolean.annotate({ "description": "Set to `true` when this party is the same person or business as the Bridge customer on the resource. When `true`, Bridge uses the customer's name and address on file instead of relying on `name` and `address` in this payload." })), "name": Schema.optionalKey(Schema.String.annotate({ "description": "Legal name of the originator or beneficiary. Usually omitted when `is_self` is `true`." })), "address": Schema.optionalKey(Schema.Struct({ "street_line_1": Schema.optionalKey(Schema.String), "street_line_2": Schema.optionalKey(Schema.String), "city": Schema.optionalKey(Schema.String), "state": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-2 subdivision code." })), "postal_code": Schema.optionalKey(Schema.String), "country": Schema.optionalKey(Schema.String.annotate({ "description": "Three-letter alpha-3 country code as defined in the ISO 3166-1 spec." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))) }).annotate({ "description": "Address for travel rule submissions. All fields are optional to support partial address data (e.g. country-only)." })), "wallet_type": Schema.optionalKey(Schema.Literals(["hosted", "external", "self_custodied"]).annotate({ "description": "Indicates the custody model for the wallet. Use `self_custodied` for customer-owned wallets (customer controls private keys), `hosted` for wallets managed by a developer or regulated entity on behalf of the customer, or `external` for wallets belonging to external exchanges or smart contracts." })), "wallet_attested_ownership_at": Schema.optionalKey(Schema.String.annotate({ "description": "Required when `wallet_type` is `self-custodied` or `hosted`. Must be a timestamp in the past indicating when wallet ownership was attested.", "format": "date-time" })), "legal_entity_identifier": Schema.optionalKey(Schema.String.annotate({ "description": "The Legal Entity Identifier (LEI) or equivalent (e.g. VAT number) of the beneficiary. Provide this when the beneficiary is a legal entity rather than an individual." })) }).annotate({ "description": "Travel Rule details for beneficiary crypto movement." })) }).annotate({ "description": "Travel Rule data for a crypto movement. Send this on create or update when the same counterparty should apply to every future use of a reusable resource, or send the same payload with `POST /travel_rule_data/{id}` when it belongs to one specific movement." })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "identifier": "TransferRequest" }) +export type TransferRouteResponse = { readonly "state": "valid" | "invalid", readonly "notes": ReadonlyArray } & { readonly [x: string]: Schema.Json } +export const TransferRouteResponse = Schema.StructWithRest(Schema.Struct({ "state": Schema.Literals(["valid", "invalid"]), "notes": Schema.Array(Schema.String) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "identifier": "TransferRouteResponse" }) +export type TransferUpdateRequest = { readonly "amount"?: string, readonly "developer_fee"?: string, readonly "developer_fee_percent"?: string, readonly "return_instructions"?: { readonly "address": string, readonly "memo"?: string } } & { readonly [x: string]: Schema.Json } +export const TransferUpdateRequest = Schema.StructWithRest(Schema.Struct({ "amount": Schema.optionalKey(Schema.String.annotate({ "description": "Amount of the transfer, expressed as a decimal string. Examples include \"100.25\", \"0.1\", \"1.234567\", \"1.01\" etc.\n\nIt is denominated in the source currency if that is a fiat currency, or in the fiat currency to which the source currency is pegged." })), "developer_fee": Schema.optionalKey(Schema.String.annotate({ "description": "The fee, expressed as a decimal string, represents the amount you wish to reserve for your own account. This fee is the final amount deducted from what your customer ultimately receives, rather than a percentage.\n\nIt is denominated in the source currency if that is a fiat currency, or in the fiat currency to which the source currency is pegged." })), "developer_fee_percent": Schema.optionalKey(Schema.String.annotate({ "description": "The fee percent, expressed as a decimal string from `0.0` to `100.0`, represents the percentage of the transfer you wish to reserve for your own account.\n\nThis field must be set instead of `developer_fee` when using [Flexible Amounts](https://apidocs.bridge.xyz/platform/orchestration/fees-and-mins/devfees#transfers-with-fixed-amounts)." })), "return_instructions": Schema.optionalKey(Schema.Struct({ "address": Schema.String.annotate({ "description": "The crypto wallet address to send returned funds to. Must be valid for the source payment rail's chain." }), "memo": Schema.optionalKey(Schema.String.annotate({ "description": "Memo to include with the return transaction. Required when the source payment rail is Stellar; optional for other memo-capable chains." })) }).annotate({ "description": "Optional instructions for where to send funds if the transfer is returned (e.g. refund). Only supported when the source payment rail is crypto. When the source is Stellar, `memo` is required." })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "identifier": "TransferUpdateRequest" }) +export type PrefundedAccount = { readonly "id": string, readonly "available_balance": string, readonly "currency": "usd", readonly "name": string } & { readonly [x: string]: Schema.Json } +export const PrefundedAccount = Schema.StructWithRest(Schema.Struct({ "id": Schema.String.annotate({ "description": "A UUID that uniquely identifies a resource", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" })), "available_balance": Schema.String.annotate({ "description": "Amount available for spending, represented as a dollar denominated string. Examples include \"100.25\", \"0.1\", \"1.234567\", \"1.01\" etc.", "readOnly": true }), "currency": Schema.Literal("usd").annotate({ "description": "currency associated with the bank account.", "readOnly": true }), "name": Schema.String.annotate({ "description": "Serialized name of the account which identifies the counterparty.", "readOnly": true }) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "identifier": "PrefundedAccount" }) +export type PrefundedAccountHistory = { readonly "id": string, readonly "amount": string, readonly "available_balance": string, readonly "currency": "usd", readonly "name": string, readonly "type": "funding" | "refunded transfer", readonly "created_at": string, readonly "withdrawal_id"?: string, readonly "deposit_id"?: string } & { readonly [x: string]: Schema.Json } +export const PrefundedAccountHistory = Schema.StructWithRest(Schema.Struct({ "id": Schema.String.annotate({ "description": "A UUID that uniquely identifies a resource", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" })), "amount": Schema.String.annotate({ "description": "Amount of the transaction, represented as a dollar denominated string. Examples include \"100.25\", \"0.1\", \"1.234567\", \"1.01\" etc.", "readOnly": true }), "available_balance": Schema.String.annotate({ "description": "Amount available for spending, represented as a dollar denominated string. Examples include \"100.25\", \"0.1\", \"1.234567\", \"1.01\" etc.", "readOnly": true }), "currency": Schema.Literal("usd").annotate({ "description": "currency associated with the bank account.", "readOnly": true }), "name": Schema.String.annotate({ "description": "Serialized name of the account.", "readOnly": true }), "type": Schema.Literals(["funding", "refunded transfer"]).annotate({ "description": "The type of the transaction.", "readOnly": true }), "created_at": Schema.String.annotate({ "description": "Time of creation of the External Account", "readOnly": true, "format": "date-time" }), "withdrawal_id": Schema.optionalKey(Schema.String.annotate({ "description": "The ID of the transfer which created this event. Exclusive with deposit_id.", "readOnly": true })), "deposit_id": Schema.optionalKey(Schema.String.annotate({ "description": "The ID of the transfer which created this event. Exclusive with withdrawal_id.", "readOnly": true })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "identifier": "PrefundedAccountHistory" }) +export type CreateBridgeWallet = { readonly "chain": "base" | "ethereum" | "linea" | "solana" | "tempo" | "tron" | "xdc" } & { readonly [x: string]: Schema.Json } +export const CreateBridgeWallet = Schema.StructWithRest(Schema.Struct({ "chain": Schema.Literals(["base", "ethereum", "linea", "solana", "tempo", "tron", "xdc"]) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "identifier": "CreateBridgeWallet" }) +export type CreateBridgeWalletResponse = { readonly "chain": "base" | "ethereum" | "linea" | "solana" | "tempo" | "tron" | "xdc", readonly "id"?: string, readonly "address"?: string, readonly "initiation_required"?: boolean, readonly "created_at"?: string, readonly "updated_at"?: string } & { readonly [x: string]: Schema.Json } +export const CreateBridgeWalletResponse = Schema.StructWithRest(Schema.Struct({ "chain": Schema.Literals(["base", "ethereum", "linea", "solana", "tempo", "tron", "xdc"]), "id": Schema.optionalKey(Schema.String.annotate({ "description": "A UUID that uniquely identifies a resource", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "address": Schema.optionalKey(Schema.String.annotate({ "description": "The blockchain address of the Bridge Wallet", "readOnly": true })), "initiation_required": Schema.optionalKey(Schema.Boolean.annotate({ "description": "When present, transfers sourced from this wallet must include an `initiation` object on the create request. Omitted for wallets that do not require initiation data.", "readOnly": true })), "created_at": Schema.optionalKey(Schema.String.annotate({ "description": "Time of creation of the Bridge Wallet", "readOnly": true, "format": "date-time" })), "updated_at": Schema.optionalKey(Schema.String.annotate({ "description": "Time of most recent update of the Bridge Wallet", "readOnly": true, "format": "date-time" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "identifier": "CreateBridgeWalletResponse" }) +export type LiquidationAddress = { readonly "id": string, readonly "currency": "usdb" | "usdc" | "usdt" | "usdl_linea" | "pyusd" | "eurc" | "all_supported", readonly "chain": "arbitrum" | "avalanche_c_chain" | "base" | "celo" | "ethereum" | "linea" | "optimism" | "polygon" | "solana" | "stellar" | "tempo" | "tron" | "xdc" | "evm", readonly "supported_currencies"?: { readonly [x: string]: ReadonlyArray<"usdb" | "usdc" | "usdt" | "usdl_linea" | "pyusd" | "eurc"> }, readonly "customer_id": string, readonly "external_account_id": string, readonly "prefunded_account_id"?: string, readonly "custom_developer_fee_percent"?: string | null, readonly "global_developer_fee_percent"?: { readonly "percent"?: string | null }, readonly "destination_wire_message"?: string, readonly "destination_sepa_reference"?: string, readonly "destination_spei_reference"?: string, readonly "destination_ach_reference"?: string, readonly "destination_swift_reference"?: string, readonly "destination_payment_rail": "ach" | "wire" | "ach_push" | "ach_same_day" | "arbitrum" | "avalanche_c_chain" | "base" | "bre_b" | "co_bank_transfer" | "celo" | "ethereum" | "faster_payments" | "fiat_deposit_return" | "linea" | "optimism" | "pix" | "polygon" | "sepa" | "solana" | "spei" | "stellar" | "swift" | "tempo" | "tron" | "xdc", readonly "destination_currency": "brl" | "cop" | "eur" | "eurc" | "gbp" | "mxn" | "pyusd" | "usd" | "usdb" | "usdc" | "usdt" | "usdl_linea", readonly "address": string, readonly "memoless_address"?: string, readonly "blockchain_memo"?: string, readonly "destination_address"?: string, readonly "destination_blockchain_memo"?: string, readonly "return_address"?: string | null, readonly "return_memo"?: string | null, readonly "state"?: string, readonly "created_at": string, readonly "updated_at": string } & { readonly [x: string]: Schema.Json } +export const LiquidationAddress = Schema.StructWithRest(Schema.Struct({ "id": Schema.String.annotate({ "description": "A UUID that uniquely identifies a resource", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" })), "currency": Schema.Literals(["usdb", "usdc", "usdt", "usdl_linea", "pyusd", "eurc", "all_supported"]), "chain": Schema.Literals(["arbitrum", "avalanche_c_chain", "base", "celo", "ethereum", "linea", "optimism", "polygon", "solana", "stellar", "tempo", "tron", "xdc", "evm"]), "supported_currencies": Schema.optionalKey(Schema.Record(Schema.String, Schema.Array(Schema.Literals(["usdb", "usdc", "usdt", "usdl_linea", "pyusd", "eurc"]))).annotate({ "description": "The currencies this Liquidation Address accepts on each chain. Keys are `LiquidationAddressSourceChain` values (e.g. `ethereum`, `polygon`, `base`). For a single-chain, single-currency address this is just that one chain and currency; for a multi-chain (`chain` is `evm`) or multi-currency (`currency` is `all_supported`) address it lists every currency actually accepted on each chain.\n", "examples": [{ "ethereum": ["usdc", "eurc"], "polygon": ["usdc"] }], "readOnly": true })), "customer_id": Schema.String.annotate({ "description": "The ID of the customer who owns this liquidation address" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" })), "external_account_id": Schema.String.annotate({ "description": "External bank account to which Bridge will send the funds. The currency associated with the External Account must match the destination currency." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" })), "prefunded_account_id": Schema.optionalKey(Schema.String.annotate({ "description": "The developer's prefunded account to which Bridge will send the funds." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "custom_developer_fee_percent": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "The developer fee percent that will be applied to this Liquidation Address or null to use the default fee. The value is a base 100 percentage, i.e. 10.2% is 10.2 in the API.", "format": "number" })), "global_developer_fee_percent": Schema.optionalKey(Schema.Struct({ "percent": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "examples": ["0.2"], "format": "number" })) }).annotate({ "description": "The developer fee percent that will be default applied to all Liquidation Addresses." })), "destination_wire_message": Schema.optionalKey(Schema.String.annotate({ "description": "A message to be sent with a wire transfer." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" }))), "destination_sepa_reference": Schema.optionalKey(Schema.String.annotate({ "description": "A reference message to be sent with a SEPA transaction. We recommend you set a unique value to help you and your customers track payments end to end. It must be from 6 to 140 characters. The allowed characters are `a-z`, `A-Z`, `0-9`, spaces, ampersand (`&`), hyphen (`-`), full stop (`.`), and solidus (`/`). If not populated, the default value is \"Payment via Bridge {unique_token}\"." }).check(Schema.isMinLength(6).annotate({ "expected": "a value with a length of at least 6" })).check(Schema.isMaxLength(140).annotate({ "expected": "a value with a length of at most 140" }))), "destination_spei_reference": Schema.optionalKey(Schema.String.annotate({ "description": "A payment reference message or remittance information to be included in a SPEI transaction. The allowed characters are alphanumeric `a-z`, `A-Z`, `0-9`, and space" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(40).annotate({ "expected": "a value with a length of at most 40" }))), "destination_ach_reference": Schema.optionalKey(Schema.String.annotate({ "description": "A reference message to be sent with an ACH transaction. It can be at most 10 characters, A-Z, a-z, 0-9, and spaces." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(10).annotate({ "expected": "a value with a length of at most 10" }))), "destination_swift_reference": Schema.optionalKey(Schema.String.annotate({ "description": "A payment reference message or remittance information to be included in a SWIFT transaction. It can have at most 4 lines (separated by \"\\n\"), each line with a max length of 35 chars. The allowed characters are `a-z`, `A-Z`, `0-9`, special characters (`/` `-` `?` `:` `(` `)` `.` `,` `'` `+`), and space" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(140).annotate({ "expected": "a value with a length of at most 140" }))), "destination_payment_rail": Schema.Literals(["ach", "wire", "ach_push", "ach_same_day", "arbitrum", "avalanche_c_chain", "base", "bre_b", "co_bank_transfer", "celo", "ethereum", "faster_payments", "fiat_deposit_return", "linea", "optimism", "pix", "polygon", "sepa", "solana", "spei", "stellar", "swift", "tempo", "tron", "xdc"]).annotate({ "description": "The payment rail that Bridge will use to send funds to the customer." }), "destination_currency": Schema.Literals(["brl", "cop", "eur", "eurc", "gbp", "mxn", "pyusd", "usd", "usdb", "usdc", "usdt", "usdl_linea"]).annotate({ "description": "The currency that Bridge will use to send funds to the customer." }), "address": Schema.String.annotate({ "description": "The crypto wallet address the customer will send funds to in order to initiate the payment processing", "readOnly": true }), "memoless_address": Schema.optionalKey(Schema.String.annotate({ "description": "An alternative crypto wallet address that encodes the memo, allowing the customer to send funds without needing to include a separate memo. Currently only available for Stellar deposits.", "readOnly": true })), "blockchain_memo": Schema.optionalKey(Schema.String.annotate({ "description": "The memo that must be included with the deposit transaction when sending funds to the deposit address. Only present for blockchains that require memos (such as Stellar).", "readOnly": true })), "destination_address": Schema.optionalKey(Schema.String.annotate({ "description": "The crypto wallet address that Bridge will use to send funds to the customer." })), "destination_blockchain_memo": Schema.optionalKey(Schema.String.annotate({ "description": "The memo to include in the transaction, for blockchains that support memos only" })), "return_address": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Deprecated: use `return_instructions` instead.\n\nThe crypto wallet address that Bridge will use to return funds to the customer in case of a failed transaction.\nMust be on the same chain as the liquidation address.\nCannot be used on Stellar — use `return_instructions` with a `memo` instead.\n" })), "return_memo": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "The memo included with return transactions. Present when `return_instructions` was set with a memo (e.g. required for Stellar to route funds to the correct end-customer)." })), "state": Schema.optionalKey(Schema.String.annotate({ "description": "The state of the liquidation address. It could be \"active\" or \"deactivated\"" })), "created_at": Schema.String.annotate({ "description": "Time of creation of the Liquidation Address", "readOnly": true, "format": "date-time" }), "updated_at": Schema.String.annotate({ "description": "Time of last update of the Liquidation Address", "readOnly": true, "format": "date-time" }) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "identifier": "LiquidationAddress" }) +export type CreateLiquidationAddress = { readonly "currency": "usdb" | "usdc" | "usdt" | "usdl_linea" | "pyusd" | "eurc" | "all_supported", readonly "chain": "arbitrum" | "avalanche_c_chain" | "base" | "celo" | "ethereum" | "linea" | "optimism" | "polygon" | "solana" | "stellar" | "tempo" | "tron" | "xdc" | "evm", readonly "external_account_id"?: string, readonly "prefunded_account_id"?: string, readonly "bridge_wallet_id"?: string, readonly "destination_wire_message"?: string, readonly "destination_sepa_reference"?: string, readonly "destination_ach_reference"?: string, readonly "destination_spei_reference"?: string, readonly "destination_swift_reference"?: string, readonly "destination_reference"?: string, readonly "destination_payment_rail"?: "ach" | "wire" | "ach_push" | "ach_same_day" | "arbitrum" | "avalanche_c_chain" | "base" | "bre_b" | "co_bank_transfer" | "celo" | "ethereum" | "faster_payments" | "fiat_deposit_return" | "linea" | "optimism" | "pix" | "polygon" | "sepa" | "solana" | "spei" | "stellar" | "swift" | "tempo" | "tron" | "xdc", readonly "destination_currency"?: "brl" | "cop" | "eur" | "eurc" | "gbp" | "mxn" | "pyusd" | "usd" | "usdb" | "usdc" | "usdt" | "usdl_linea", readonly "destination_address"?: string, readonly "destination_blockchain_memo"?: string, readonly "return_address"?: string | null, readonly "return_instructions"?: { readonly "address": string, readonly "memo"?: string }, readonly "custom_developer_fee_percent"?: string | null, readonly "travel_rule_data"?: { readonly "originator"?: { readonly "is_self"?: boolean, readonly "name"?: string, readonly "address"?: { readonly "street_line_1"?: string, readonly "street_line_2"?: string, readonly "city"?: string, readonly "state"?: string, readonly "postal_code"?: string, readonly "country"?: string }, readonly "wallet_type"?: "hosted" | "external" | "self_custodied", readonly "wallet_attested_ownership_at"?: string, readonly "identifying_information"?: ReadonlyArray<{ readonly "type": "drivers_license" | "matriculate_id" | "military_id" | "national_id" | "passport" | "permanent_residency_id" | "state_or_provincial_id" | "visa" | "abn" | "acn" | "ahv" | "ak" | "aom" | "arbn" | "avs" | "bc" | "bce" | "bin" | "bir" | "bp" | "brn" | "bsn" | "bvn" | "cc" | "cdi" | "cedula_juridica" | "cf" | "cif" | "cin" | "cipc" | "cn" | "cnp" | "cnpj" | "cpf" | "cpr" | "crc" | "crib" | "crn" | "cro" | "cui" | "cuil" | "curp" | "cuit" | "cvr" | "edrpou" | "ein" | "embg" | "emirates_id" | "en" | "fin" | "fn" | "gstin" | "gui" | "hetu" | "hkid" | "hn" | "ic" | "ico" | "id" | "id_broj" | "idno" | "idnp" | "idnr" | "if" | "iin" | "ik" | "inn" | "ird" | "itin" | "itr" | "iva" | "jmbg" | "kbo" | "kvk" | "matricule" | "mf" | "mn" | "ms" | "mst" | "nic" | "nicn" | "nie" | "nif" | "nin" | "nino" | "nip" | "nipc" | "nipt" | "nit" | "npwp" | "nric" | "nrn" | "nrt" | "ntn" | "nuit" | "nzbn" | "oib" | "orgnr" | "other" | "pan" | "partita_iva" | "pesel" | "pib" | "pin" | "pk" | "ppsn" | "qid" | "rc" | "regon" | "rfc" | "ricn" | "rif" | "rn" | "rnc" | "rnokpp" | "rp" | "rrn" | "rtn" | "ruc" | "rut" | "si" | "sin" | "siren" | "siret" | "spi" | "ssm" | "ssn" | "steuer_id" | "strn" | "tckn" | "tfn" | "tin" | "tpin" | "trn" | "ucn" | "uen" | "uic" | "uid" | "usc" | "ust_idnr" | "utr" | "vat" | "vkn" | "voen" | "y_tunnus", readonly "issuing_country": string, readonly "number"?: string, readonly "description"?: string, readonly "expiration"?: string, readonly "image_front"?: string, readonly "image_back"?: string }>, readonly "birth_date"?: string, readonly "place_of_birth"?: { readonly "country"?: string, readonly "city"?: string }, readonly "legal_entity_identifier"?: string }, readonly "beneficiary"?: { readonly "is_self"?: boolean, readonly "name"?: string, readonly "address"?: { readonly "street_line_1"?: string, readonly "street_line_2"?: string, readonly "city"?: string, readonly "state"?: string, readonly "postal_code"?: string, readonly "country"?: string }, readonly "wallet_type"?: "hosted" | "external" | "self_custodied", readonly "wallet_attested_ownership_at"?: string, readonly "legal_entity_identifier"?: string } } } & { readonly [x: string]: Schema.Json } +export const CreateLiquidationAddress = Schema.StructWithRest(Schema.Struct({ "currency": Schema.Literals(["usdb", "usdc", "usdt", "usdl_linea", "pyusd", "eurc", "all_supported"]), "chain": Schema.Literals(["arbitrum", "avalanche_c_chain", "base", "celo", "ethereum", "linea", "optimism", "polygon", "solana", "stellar", "tempo", "tron", "xdc", "evm"]), "external_account_id": Schema.optionalKey(Schema.String.annotate({ "description": "External bank account to which Bridge will send the funds. The currency associated with the External Account must match the destination currency." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "prefunded_account_id": Schema.optionalKey(Schema.String.annotate({ "description": "The developer's prefunded account id that Bridge will send the funds to." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "bridge_wallet_id": Schema.optionalKey(Schema.String.annotate({ "description": "The Bridge Wallet to which Bridge will send the funds. The chain associated with the Bridge Wallet must match the payment rail." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "destination_wire_message": Schema.optionalKey(Schema.String.annotate({ "description": "A message to be sent with a wire transfer. It can have up to 140 characters. This message will be validated against 4 lines, each with a max length of 35 characters according to the Fedwire standard." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" }))), "destination_sepa_reference": Schema.optionalKey(Schema.String.annotate({ "description": "A reference message to be sent with a SEPA transaction. We recommend you set a unique value to help you and your customers track payments end to end. It must be from 6 to 140 characters. The allowed characters are `a-z`, `A-Z`, `0-9`, spaces, ampersand (`&`), hyphen (`-`), full stop (`.`), and solidus (`/`). If not populated, the default value is \"Payment via Bridge {unique_token}\"." }).check(Schema.isMinLength(6).annotate({ "expected": "a value with a length of at least 6" })).check(Schema.isMaxLength(140).annotate({ "expected": "a value with a length of at most 140" }))), "destination_ach_reference": Schema.optionalKey(Schema.String.annotate({ "description": "A reference message to be sent with an ACH transaction. It can be at most 10 characters, A-Z, a-z, 0-9, and spaces." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(10).annotate({ "expected": "a value with a length of at most 10" }))), "destination_spei_reference": Schema.optionalKey(Schema.String.annotate({ "description": "A payment reference message or remittance information to be included in a SPEI transaction. The allowed characters are alphanumeric `a-z`, `A-Z`, `0-9`, and space" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(40).annotate({ "expected": "a value with a length of at most 40" }))), "destination_swift_reference": Schema.optionalKey(Schema.String.annotate({ "description": "A payment reference message or remittance information to be included in a SWIFT transaction. It can have at most 4 lines (separated by \"\\n\"), each line with a max length of 35 chars. The allowed characters are `a-z`, `A-Z`, `0-9`, special characters (`/` `-` `?` `:` `(` `)` `.` `,` `'` `+`), and space" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(140).annotate({ "expected": "a value with a length of at most 140" }))), "destination_reference": Schema.optionalKey(Schema.String.annotate({ "description": "A payment reference message for newer payment rails (e.g. Pix, Faster Payments, and FedNow)." })), "destination_payment_rail": Schema.optionalKey(Schema.Literals(["ach", "wire", "ach_push", "ach_same_day", "arbitrum", "avalanche_c_chain", "base", "bre_b", "co_bank_transfer", "celo", "ethereum", "faster_payments", "fiat_deposit_return", "linea", "optimism", "pix", "polygon", "sepa", "solana", "spei", "stellar", "swift", "tempo", "tron", "xdc"]).annotate({ "description": "The payment rail that Bridge will use to send funds to the customer. Will default to ACH if not specified." })), "destination_currency": Schema.optionalKey(Schema.Literals(["brl", "cop", "eur", "eurc", "gbp", "mxn", "pyusd", "usd", "usdb", "usdc", "usdt", "usdl_linea"]).annotate({ "description": "The currency that Bridge will use to send funds to the customer. Will default to USD if not specified." })), "destination_address": Schema.optionalKey(Schema.String.annotate({ "description": "The crypto wallet address that Bridge will use to send funds to the customer." })), "destination_blockchain_memo": Schema.optionalKey(Schema.String.annotate({ "description": "The memo to include in the transaction, for blockchains that support memos only" })), "return_address": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Deprecated: use `return_instructions` instead.\n\nThe crypto wallet address that Bridge will use to return funds to the customer in case of a failed transaction.\nMust be on the same chain as the liquidation address.\nCannot be used on Stellar — use `return_instructions` with a `memo` instead.\n" })), "return_instructions": Schema.optionalKey(Schema.Struct({ "address": Schema.String.annotate({ "description": "The crypto wallet address to send returned funds to. Must be valid for the source payment rail's chain." }), "memo": Schema.optionalKey(Schema.String.annotate({ "description": "Memo to include with the return transaction. Required when the source payment rail is Stellar; optional for other memo-capable chains." })) }).annotate({ "description": "Optional instructions for where to send funds if the transfer is returned (e.g. refund). Only supported when the source payment rail is crypto. Memo is required when the source payment rail is Stellar." })), "custom_developer_fee_percent": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "The developer fee percent that will be applied to this Liquidation Address or null to use the default fee. The value is a base 100 percentage, i.e. 10.2% is 10.2 in the API.", "format": "number" })), "travel_rule_data": Schema.optionalKey(Schema.Struct({ "originator": Schema.optionalKey(Schema.Struct({ "is_self": Schema.optionalKey(Schema.Boolean.annotate({ "description": "Set to `true` when this party is the same person or business as the Bridge customer on the resource. When `true`, Bridge uses the customer's name and address on file instead of relying on `name` and `address` in this payload." })), "name": Schema.optionalKey(Schema.String.annotate({ "description": "Legal name of the originator or beneficiary. Usually omitted when `is_self` is `true`." })), "address": Schema.optionalKey(Schema.Struct({ "street_line_1": Schema.optionalKey(Schema.String), "street_line_2": Schema.optionalKey(Schema.String), "city": Schema.optionalKey(Schema.String), "state": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-2 subdivision code." })), "postal_code": Schema.optionalKey(Schema.String), "country": Schema.optionalKey(Schema.String.annotate({ "description": "Three-letter alpha-3 country code as defined in the ISO 3166-1 spec." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))) }).annotate({ "description": "Address for travel rule submissions. All fields are optional to support partial address data (e.g. country-only)." })), "wallet_type": Schema.optionalKey(Schema.Literals(["hosted", "external", "self_custodied"]).annotate({ "description": "Indicates the custody model for the wallet. Use `self_custodied` for customer-owned wallets (customer controls private keys), `hosted` for wallets managed by a developer or regulated entity on behalf of the customer, or `external` for wallets belonging to external exchanges or smart contracts." })), "wallet_attested_ownership_at": Schema.optionalKey(Schema.String.annotate({ "description": "Required when `wallet_type` is `self-custodied` or `hosted`. Must be a timestamp in the past indicating when wallet ownership was attested.", "format": "date-time" })), "identifying_information": Schema.optionalKey(Schema.Array(Schema.Struct({ "type": Schema.Literals(["drivers_license", "matriculate_id", "military_id", "national_id", "passport", "permanent_residency_id", "state_or_provincial_id", "visa", "abn", "acn", "ahv", "ak", "aom", "arbn", "avs", "bc", "bce", "bin", "bir", "bp", "brn", "bsn", "bvn", "cc", "cdi", "cedula_juridica", "cf", "cif", "cin", "cipc", "cn", "cnp", "cnpj", "cpf", "cpr", "crc", "crib", "crn", "cro", "cui", "cuil", "curp", "cuit", "cvr", "edrpou", "ein", "embg", "emirates_id", "en", "fin", "fn", "gstin", "gui", "hetu", "hkid", "hn", "ic", "ico", "id", "id_broj", "idno", "idnp", "idnr", "if", "iin", "ik", "inn", "ird", "itin", "itr", "iva", "jmbg", "kbo", "kvk", "matricule", "mf", "mn", "ms", "mst", "nic", "nicn", "nie", "nif", "nin", "nino", "nip", "nipc", "nipt", "nit", "npwp", "nric", "nrn", "nrt", "ntn", "nuit", "nzbn", "oib", "orgnr", "other", "pan", "partita_iva", "pesel", "pib", "pin", "pk", "ppsn", "qid", "rc", "regon", "rfc", "ricn", "rif", "rn", "rnc", "rnokpp", "rp", "rrn", "rtn", "ruc", "rut", "si", "sin", "siren", "siret", "spi", "ssm", "ssn", "steuer_id", "strn", "tckn", "tfn", "tin", "tpin", "trn", "ucn", "uen", "uic", "uid", "usc", "ust_idnr", "utr", "vat", "vkn", "voen", "y_tunnus"]).annotate({ "description": "Tax identification number type or government-issued ID document type (see enum). Country-specific tax and national ID lists: [Individuals](https://apidocs.bridge.xyz/docs/individual-tax-identification-numbers-by-country), [Businesses](https://apidocs.bridge.xyz/docs/business-tax-identification-numbers-by-country).\n\n**EEA / BBSA (policy in `eea_requirements.rb`):** In-scope individuals and UBOs need **both** a valid national-ID-type entry and a valid TIN per [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements). In-scope businesses need business registration **and** business tax ID types per country tables there. **TIN issuing country** must match residence (individuals) or incorporation (businesses). **Foreign tax** outside the incorporation country: set `has_foreign_tax_registration` on the business customer and add TIN objects per jurisdiction ([foreign tax / tax residency](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#tax-residency-status-foreign-tax-registry)).\n" }), "issuing_country": Schema.String.annotate({ "description": "The ISO 3166-1 (three-character) country code that issued the provided document." }), "number": Schema.optionalKey(Schema.String.annotate({ "description": "The unique identifier of the document. Required if this document is being used as a tax identification number (e.g., you are providing a passport or national_id with no other identification)." })), "description": Schema.optionalKey(Schema.String.annotate({ "description": "A description describing the provided document. This field is required when `other` is selected." })), "expiration": Schema.optionalKey(Schema.String.annotate({ "description": "The expiration date of the given document in yyyy-mm-dd format." })), "image_front": Schema.optionalKey(Schema.String.annotate({ "description": "This field is optionally accepted for tax_id types, but required for government_id types. Base64 encoded image* of the front side of the provided document, following the data-uri scheme i.e. data:image/[type];base64,[base_64_encoded_file_contents], with a minimum size of 200px x 200px \\n\\n*Maximum File Size: 15MB\\n\\n*Valid file types: .pdf, .jpeg, .jpg, .png, .heic, .tif\n\n_Note: When combined with an `image_back`, the combined size of both images must not exceed 24MB._\n" })), "image_back": Schema.optionalKey(Schema.String.annotate({ "description": "Base64 encoded image* of the back side of the provided document, following the data-uri scheme i.e. data:image/[type];base64,[base_64_encoded_file_contents], with a minimum size of 200px x 200px \\n\\n*Maximum File Size: 15MB\\n\\n*Valid file types: .pdf, .jpeg, .jpg, .png, .heic, .tif\n\n_Note: When combined with an `image_front`, the combined size of both images must not exceed 24MB._\n" })) })).annotate({ "title": "Identification Information", "writeOnly": true, "description": "List of identification objects for the originator. Do **not** include `image_front` or `image_back` fields in this context; those are not accepted in Travel Rule submissions.\n" })), "birth_date": Schema.optionalKey(Schema.String.annotate({ "description": "Date of birth in format yyyy-mm-dd." }).check(Schema.isMinLength(10).annotate({ "expected": "a value with a length of at least 10" })).check(Schema.isMaxLength(10).annotate({ "expected": "a value with a length of at most 10" }))), "place_of_birth": Schema.optionalKey(Schema.Struct({ "country": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-1 alpha-3 country code for the place of birth." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))), "city": Schema.optionalKey(Schema.String.annotate({ "description": "City of birth (recommended for EEA)." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))) }).annotate({ "description": "Country (and optionally city) of birth. **EEA / BBSA in-scope customers:** supply when onboarding individuals or associated persons under the [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#country-of-birth-and-city-of-birth). This is a sparse address — no street address. At least `country` should be present when the object is sent; `city` is recommended and will be required by EU law in 2027.\n" })), "legal_entity_identifier": Schema.optionalKey(Schema.String.annotate({ "description": "The Legal Entity Identifier (LEI) or equivalent (e.g. VAT number) of the originator. Provide this when the originator is a legal entity rather than an individual." })) }).annotate({ "description": "Travel Rule details for originator crypto movement." })), "beneficiary": Schema.optionalKey(Schema.Struct({ "is_self": Schema.optionalKey(Schema.Boolean.annotate({ "description": "Set to `true` when this party is the same person or business as the Bridge customer on the resource. When `true`, Bridge uses the customer's name and address on file instead of relying on `name` and `address` in this payload." })), "name": Schema.optionalKey(Schema.String.annotate({ "description": "Legal name of the originator or beneficiary. Usually omitted when `is_self` is `true`." })), "address": Schema.optionalKey(Schema.Struct({ "street_line_1": Schema.optionalKey(Schema.String), "street_line_2": Schema.optionalKey(Schema.String), "city": Schema.optionalKey(Schema.String), "state": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-2 subdivision code." })), "postal_code": Schema.optionalKey(Schema.String), "country": Schema.optionalKey(Schema.String.annotate({ "description": "Three-letter alpha-3 country code as defined in the ISO 3166-1 spec." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))) }).annotate({ "description": "Address for travel rule submissions. All fields are optional to support partial address data (e.g. country-only)." })), "wallet_type": Schema.optionalKey(Schema.Literals(["hosted", "external", "self_custodied"]).annotate({ "description": "Indicates the custody model for the wallet. Use `self_custodied` for customer-owned wallets (customer controls private keys), `hosted` for wallets managed by a developer or regulated entity on behalf of the customer, or `external` for wallets belonging to external exchanges or smart contracts." })), "wallet_attested_ownership_at": Schema.optionalKey(Schema.String.annotate({ "description": "Required when `wallet_type` is `self-custodied` or `hosted`. Must be a timestamp in the past indicating when wallet ownership was attested.", "format": "date-time" })), "legal_entity_identifier": Schema.optionalKey(Schema.String.annotate({ "description": "The Legal Entity Identifier (LEI) or equivalent (e.g. VAT number) of the beneficiary. Provide this when the beneficiary is a legal entity rather than an individual." })) }).annotate({ "description": "Travel Rule details for beneficiary crypto movement." })) }).annotate({ "description": "Travel Rule data for a crypto movement. Send this on create or update when the same counterparty should apply to every future use of a reusable resource, or send the same payload with `POST /travel_rule_data/{id}` when it belongs to one specific movement." })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "identifier": "CreateLiquidationAddress" }) +export type CreateLiquidationAddressResponse = { readonly "currency": "usdb" | "usdc" | "usdt" | "usdl_linea" | "pyusd" | "eurc" | "all_supported", readonly "chain": "arbitrum" | "avalanche_c_chain" | "base" | "celo" | "ethereum" | "linea" | "optimism" | "polygon" | "solana" | "stellar" | "tempo" | "tron" | "xdc" | "evm", readonly "destination_payment_rail": "ach" | "wire" | "ach_push" | "ach_same_day" | "arbitrum" | "avalanche_c_chain" | "base" | "bre_b" | "co_bank_transfer" | "celo" | "ethereum" | "faster_payments" | "fiat_deposit_return" | "linea" | "optimism" | "pix" | "polygon" | "sepa" | "solana" | "spei" | "stellar" | "swift" | "tempo" | "tron" | "xdc", readonly "destination_currency": "brl" | "cop" | "eur" | "eurc" | "gbp" | "mxn" | "pyusd" | "usd" | "usdb" | "usdc" | "usdt" | "usdl_linea", readonly "external_account_id"?: string, readonly "prefunded_account_id"?: string, readonly "bridge_wallet_id"?: string, readonly "destination_wire_message"?: string, readonly "destination_sepa_reference"?: string, readonly "destination_ach_reference"?: string, readonly "destination_spei_reference"?: string, readonly "destination_swift_reference"?: string, readonly "destination_reference"?: string, readonly "destination_address"?: string, readonly "destination_blockchain_memo"?: string, readonly "return_address"?: string | null, readonly "return_instructions"?: { readonly "address": string, readonly "memo"?: string }, readonly "custom_developer_fee_percent"?: string | null, readonly "travel_rule_data"?: { readonly "originator"?: { readonly "is_self"?: boolean, readonly "name"?: string, readonly "address"?: { readonly "street_line_1"?: string, readonly "street_line_2"?: string, readonly "city"?: string, readonly "state"?: string, readonly "postal_code"?: string, readonly "country"?: string }, readonly "wallet_type"?: "hosted" | "external" | "self_custodied", readonly "wallet_attested_ownership_at"?: string, readonly "identifying_information"?: ReadonlyArray<{ readonly "type": "drivers_license" | "matriculate_id" | "military_id" | "national_id" | "passport" | "permanent_residency_id" | "state_or_provincial_id" | "visa" | "abn" | "acn" | "ahv" | "ak" | "aom" | "arbn" | "avs" | "bc" | "bce" | "bin" | "bir" | "bp" | "brn" | "bsn" | "bvn" | "cc" | "cdi" | "cedula_juridica" | "cf" | "cif" | "cin" | "cipc" | "cn" | "cnp" | "cnpj" | "cpf" | "cpr" | "crc" | "crib" | "crn" | "cro" | "cui" | "cuil" | "curp" | "cuit" | "cvr" | "edrpou" | "ein" | "embg" | "emirates_id" | "en" | "fin" | "fn" | "gstin" | "gui" | "hetu" | "hkid" | "hn" | "ic" | "ico" | "id" | "id_broj" | "idno" | "idnp" | "idnr" | "if" | "iin" | "ik" | "inn" | "ird" | "itin" | "itr" | "iva" | "jmbg" | "kbo" | "kvk" | "matricule" | "mf" | "mn" | "ms" | "mst" | "nic" | "nicn" | "nie" | "nif" | "nin" | "nino" | "nip" | "nipc" | "nipt" | "nit" | "npwp" | "nric" | "nrn" | "nrt" | "ntn" | "nuit" | "nzbn" | "oib" | "orgnr" | "other" | "pan" | "partita_iva" | "pesel" | "pib" | "pin" | "pk" | "ppsn" | "qid" | "rc" | "regon" | "rfc" | "ricn" | "rif" | "rn" | "rnc" | "rnokpp" | "rp" | "rrn" | "rtn" | "ruc" | "rut" | "si" | "sin" | "siren" | "siret" | "spi" | "ssm" | "ssn" | "steuer_id" | "strn" | "tckn" | "tfn" | "tin" | "tpin" | "trn" | "ucn" | "uen" | "uic" | "uid" | "usc" | "ust_idnr" | "utr" | "vat" | "vkn" | "voen" | "y_tunnus", readonly "issuing_country": string, readonly "number"?: string, readonly "description"?: string, readonly "expiration"?: string, readonly "image_front"?: string, readonly "image_back"?: string }>, readonly "birth_date"?: string, readonly "place_of_birth"?: { readonly "country"?: string, readonly "city"?: string }, readonly "legal_entity_identifier"?: string }, readonly "beneficiary"?: { readonly "is_self"?: boolean, readonly "name"?: string, readonly "address"?: { readonly "street_line_1"?: string, readonly "street_line_2"?: string, readonly "city"?: string, readonly "state"?: string, readonly "postal_code"?: string, readonly "country"?: string }, readonly "wallet_type"?: "hosted" | "external" | "self_custodied", readonly "wallet_attested_ownership_at"?: string, readonly "legal_entity_identifier"?: string } }, readonly "address"?: string, readonly "memoless_address"?: string, readonly "state"?: string, readonly "return_memo"?: string | null, readonly "supported_currencies"?: { readonly [x: string]: ReadonlyArray<"usdb" | "usdc" | "usdt" | "usdl_linea" | "pyusd" | "eurc"> } } & { readonly [x: string]: Schema.Json } +export const CreateLiquidationAddressResponse = Schema.StructWithRest(Schema.Struct({ "currency": Schema.Literals(["usdb", "usdc", "usdt", "usdl_linea", "pyusd", "eurc", "all_supported"]), "chain": Schema.Literals(["arbitrum", "avalanche_c_chain", "base", "celo", "ethereum", "linea", "optimism", "polygon", "solana", "stellar", "tempo", "tron", "xdc", "evm"]), "destination_payment_rail": Schema.Literals(["ach", "wire", "ach_push", "ach_same_day", "arbitrum", "avalanche_c_chain", "base", "bre_b", "co_bank_transfer", "celo", "ethereum", "faster_payments", "fiat_deposit_return", "linea", "optimism", "pix", "polygon", "sepa", "solana", "spei", "stellar", "swift", "tempo", "tron", "xdc"]).annotate({ "description": "The payment rail that Bridge will use to send funds to the customer." }), "destination_currency": Schema.Literals(["brl", "cop", "eur", "eurc", "gbp", "mxn", "pyusd", "usd", "usdb", "usdc", "usdt", "usdl_linea"]).annotate({ "description": "The currency that Bridge will use to send funds to the customer." }), "external_account_id": Schema.optionalKey(Schema.String.annotate({ "description": "External bank account to which Bridge will send the funds." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "prefunded_account_id": Schema.optionalKey(Schema.String.annotate({ "description": "The developer's prefunded account to which Bridge will send the funds." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "bridge_wallet_id": Schema.optionalKey(Schema.String.annotate({ "description": "The Bridge Wallet to which Bridge will send the funds. The chain associated with the Bridge Wallet must match the payment rail." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "destination_wire_message": Schema.optionalKey(Schema.String.annotate({ "description": "A message to be sent with a wire transfer." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" }))), "destination_sepa_reference": Schema.optionalKey(Schema.String.annotate({ "description": "A reference message to be sent with a SEPA transaction." }).check(Schema.isMinLength(6).annotate({ "expected": "a value with a length of at least 6" })).check(Schema.isMaxLength(140).annotate({ "expected": "a value with a length of at most 140" }))), "destination_ach_reference": Schema.optionalKey(Schema.String.annotate({ "description": "A reference message to be sent with an ACH transaction. It can be at most 10 characters, A-Z, a-z, 0-9, and spaces." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(10).annotate({ "expected": "a value with a length of at most 10" }))), "destination_spei_reference": Schema.optionalKey(Schema.String.annotate({ "description": "A payment reference message or remittance information to be included in a SPEI transaction. The allowed characters are alphanumeric `a-z`, `A-Z`, `0-9`, and space" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(40).annotate({ "expected": "a value with a length of at most 40" }))), "destination_swift_reference": Schema.optionalKey(Schema.String.annotate({ "description": "A payment reference message or remittance information to be included in a SWIFT transaction. It can have at most 4 lines (separated by \"\\n\"), each line with a max length of 35 chars. The allowed characters are `a-z`, `A-Z`, `0-9`, special characters (`/` `-` `?` `:` `(` `)` `.` `,` `'` `+`), and space" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(140).annotate({ "expected": "a value with a length of at most 140" }))), "destination_reference": Schema.optionalKey(Schema.String.annotate({ "description": "A payment reference message for newer payment rails (e.g. Pix, Faster Payments, and FedNow)." })), "destination_address": Schema.optionalKey(Schema.String.annotate({ "description": "The crypto wallet address that Bridge will use to send funds to the customer." })), "destination_blockchain_memo": Schema.optionalKey(Schema.String.annotate({ "description": "The memo to include in the transaction, for blockchains that support memos only" })), "return_address": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Deprecated: use `return_instructions` instead.\n\nThe crypto wallet address that Bridge will use to return funds to the customer in case of a failed transaction.\nMust be on the same chain as the liquidation address.\nCannot be used on Stellar — use `return_instructions` with a `memo` instead.\n" })), "return_instructions": Schema.optionalKey(Schema.Struct({ "address": Schema.String.annotate({ "description": "The crypto wallet address to send returned funds to. Must be valid for the source payment rail's chain." }), "memo": Schema.optionalKey(Schema.String.annotate({ "description": "Memo to include with the return transaction. Required when the source payment rail is Stellar; optional for other memo-capable chains." })) }).annotate({ "description": "Optional instructions for where to send funds if the transfer is returned (e.g. refund). Only supported when the source payment rail is crypto. Memo is required when the source payment rail is Stellar." })), "custom_developer_fee_percent": Schema.optionalKey(Schema.Union([Schema.String.annotate({ "description": "The developer fee percent that will be applied to this Liquidation Address or null to use the default fee. The value is a base 100 percentage, i.e. 10.2% is 10.2 in the API.", "format": "number" }), Schema.Null.annotate({ "description": "The developer fee percent that will be applied to this Liquidation Address or null to use the default fee. The value is a base 100 percentage, i.e. 10.2% is 10.2 in the API.", "format": "number" })]).annotate({ "description": "The developer fee percent that will be applied to this Liquidation Address or null to use the default fee. The value is a base 100 percentage, i.e. 10.2% is 10.2 in the API.", "format": "number" })), "travel_rule_data": Schema.optionalKey(Schema.Struct({ "originator": Schema.optionalKey(Schema.Struct({ "is_self": Schema.optionalKey(Schema.Boolean.annotate({ "description": "Set to `true` when this party is the same person or business as the Bridge customer on the resource. When `true`, Bridge uses the customer's name and address on file instead of relying on `name` and `address` in this payload." })), "name": Schema.optionalKey(Schema.String.annotate({ "description": "Legal name of the originator or beneficiary. Usually omitted when `is_self` is `true`." })), "address": Schema.optionalKey(Schema.Struct({ "street_line_1": Schema.optionalKey(Schema.String), "street_line_2": Schema.optionalKey(Schema.String), "city": Schema.optionalKey(Schema.String), "state": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-2 subdivision code." })), "postal_code": Schema.optionalKey(Schema.String), "country": Schema.optionalKey(Schema.String.annotate({ "description": "Three-letter alpha-3 country code as defined in the ISO 3166-1 spec." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))) }).annotate({ "description": "Address for travel rule submissions. All fields are optional to support partial address data (e.g. country-only)." })), "wallet_type": Schema.optionalKey(Schema.Literals(["hosted", "external", "self_custodied"]).annotate({ "description": "Indicates the custody model for the wallet. Use `self_custodied` for customer-owned wallets (customer controls private keys), `hosted` for wallets managed by a developer or regulated entity on behalf of the customer, or `external` for wallets belonging to external exchanges or smart contracts." })), "wallet_attested_ownership_at": Schema.optionalKey(Schema.String.annotate({ "description": "Required when `wallet_type` is `self-custodied` or `hosted`. Must be a timestamp in the past indicating when wallet ownership was attested.", "format": "date-time" })), "identifying_information": Schema.optionalKey(Schema.Array(Schema.Struct({ "type": Schema.Literals(["drivers_license", "matriculate_id", "military_id", "national_id", "passport", "permanent_residency_id", "state_or_provincial_id", "visa", "abn", "acn", "ahv", "ak", "aom", "arbn", "avs", "bc", "bce", "bin", "bir", "bp", "brn", "bsn", "bvn", "cc", "cdi", "cedula_juridica", "cf", "cif", "cin", "cipc", "cn", "cnp", "cnpj", "cpf", "cpr", "crc", "crib", "crn", "cro", "cui", "cuil", "curp", "cuit", "cvr", "edrpou", "ein", "embg", "emirates_id", "en", "fin", "fn", "gstin", "gui", "hetu", "hkid", "hn", "ic", "ico", "id", "id_broj", "idno", "idnp", "idnr", "if", "iin", "ik", "inn", "ird", "itin", "itr", "iva", "jmbg", "kbo", "kvk", "matricule", "mf", "mn", "ms", "mst", "nic", "nicn", "nie", "nif", "nin", "nino", "nip", "nipc", "nipt", "nit", "npwp", "nric", "nrn", "nrt", "ntn", "nuit", "nzbn", "oib", "orgnr", "other", "pan", "partita_iva", "pesel", "pib", "pin", "pk", "ppsn", "qid", "rc", "regon", "rfc", "ricn", "rif", "rn", "rnc", "rnokpp", "rp", "rrn", "rtn", "ruc", "rut", "si", "sin", "siren", "siret", "spi", "ssm", "ssn", "steuer_id", "strn", "tckn", "tfn", "tin", "tpin", "trn", "ucn", "uen", "uic", "uid", "usc", "ust_idnr", "utr", "vat", "vkn", "voen", "y_tunnus"]).annotate({ "description": "Tax identification number type or government-issued ID document type (see enum). Country-specific tax and national ID lists: [Individuals](https://apidocs.bridge.xyz/docs/individual-tax-identification-numbers-by-country), [Businesses](https://apidocs.bridge.xyz/docs/business-tax-identification-numbers-by-country).\n\n**EEA / BBSA (policy in `eea_requirements.rb`):** In-scope individuals and UBOs need **both** a valid national-ID-type entry and a valid TIN per [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements). In-scope businesses need business registration **and** business tax ID types per country tables there. **TIN issuing country** must match residence (individuals) or incorporation (businesses). **Foreign tax** outside the incorporation country: set `has_foreign_tax_registration` on the business customer and add TIN objects per jurisdiction ([foreign tax / tax residency](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#tax-residency-status-foreign-tax-registry)).\n" }), "issuing_country": Schema.String.annotate({ "description": "The ISO 3166-1 (three-character) country code that issued the provided document." }), "number": Schema.optionalKey(Schema.String.annotate({ "description": "The unique identifier of the document. Required if this document is being used as a tax identification number (e.g., you are providing a passport or national_id with no other identification)." })), "description": Schema.optionalKey(Schema.String.annotate({ "description": "A description describing the provided document. This field is required when `other` is selected." })), "expiration": Schema.optionalKey(Schema.String.annotate({ "description": "The expiration date of the given document in yyyy-mm-dd format." })), "image_front": Schema.optionalKey(Schema.String.annotate({ "description": "This field is optionally accepted for tax_id types, but required for government_id types. Base64 encoded image* of the front side of the provided document, following the data-uri scheme i.e. data:image/[type];base64,[base_64_encoded_file_contents], with a minimum size of 200px x 200px \\n\\n*Maximum File Size: 15MB\\n\\n*Valid file types: .pdf, .jpeg, .jpg, .png, .heic, .tif\n\n_Note: When combined with an `image_back`, the combined size of both images must not exceed 24MB._\n" })), "image_back": Schema.optionalKey(Schema.String.annotate({ "description": "Base64 encoded image* of the back side of the provided document, following the data-uri scheme i.e. data:image/[type];base64,[base_64_encoded_file_contents], with a minimum size of 200px x 200px \\n\\n*Maximum File Size: 15MB\\n\\n*Valid file types: .pdf, .jpeg, .jpg, .png, .heic, .tif\n\n_Note: When combined with an `image_front`, the combined size of both images must not exceed 24MB._\n" })) })).annotate({ "title": "Identification Information", "writeOnly": true, "description": "List of identification objects for the originator. Do **not** include `image_front` or `image_back` fields in this context; those are not accepted in Travel Rule submissions.\n" })), "birth_date": Schema.optionalKey(Schema.String.annotate({ "description": "Date of birth in format yyyy-mm-dd." }).check(Schema.isMinLength(10).annotate({ "expected": "a value with a length of at least 10" })).check(Schema.isMaxLength(10).annotate({ "expected": "a value with a length of at most 10" }))), "place_of_birth": Schema.optionalKey(Schema.Struct({ "country": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-1 alpha-3 country code for the place of birth." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))), "city": Schema.optionalKey(Schema.String.annotate({ "description": "City of birth (recommended for EEA)." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))) }).annotate({ "description": "Country (and optionally city) of birth. **EEA / BBSA in-scope customers:** supply when onboarding individuals or associated persons under the [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#country-of-birth-and-city-of-birth). This is a sparse address — no street address. At least `country` should be present when the object is sent; `city` is recommended and will be required by EU law in 2027.\n" })), "legal_entity_identifier": Schema.optionalKey(Schema.String.annotate({ "description": "The Legal Entity Identifier (LEI) or equivalent (e.g. VAT number) of the originator. Provide this when the originator is a legal entity rather than an individual." })) }).annotate({ "description": "Travel Rule details for originator crypto movement." })), "beneficiary": Schema.optionalKey(Schema.Struct({ "is_self": Schema.optionalKey(Schema.Boolean.annotate({ "description": "Set to `true` when this party is the same person or business as the Bridge customer on the resource. When `true`, Bridge uses the customer's name and address on file instead of relying on `name` and `address` in this payload." })), "name": Schema.optionalKey(Schema.String.annotate({ "description": "Legal name of the originator or beneficiary. Usually omitted when `is_self` is `true`." })), "address": Schema.optionalKey(Schema.Struct({ "street_line_1": Schema.optionalKey(Schema.String), "street_line_2": Schema.optionalKey(Schema.String), "city": Schema.optionalKey(Schema.String), "state": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-2 subdivision code." })), "postal_code": Schema.optionalKey(Schema.String), "country": Schema.optionalKey(Schema.String.annotate({ "description": "Three-letter alpha-3 country code as defined in the ISO 3166-1 spec." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))) }).annotate({ "description": "Address for travel rule submissions. All fields are optional to support partial address data (e.g. country-only)." })), "wallet_type": Schema.optionalKey(Schema.Literals(["hosted", "external", "self_custodied"]).annotate({ "description": "Indicates the custody model for the wallet. Use `self_custodied` for customer-owned wallets (customer controls private keys), `hosted` for wallets managed by a developer or regulated entity on behalf of the customer, or `external` for wallets belonging to external exchanges or smart contracts." })), "wallet_attested_ownership_at": Schema.optionalKey(Schema.String.annotate({ "description": "Required when `wallet_type` is `self-custodied` or `hosted`. Must be a timestamp in the past indicating when wallet ownership was attested.", "format": "date-time" })), "legal_entity_identifier": Schema.optionalKey(Schema.String.annotate({ "description": "The Legal Entity Identifier (LEI) or equivalent (e.g. VAT number) of the beneficiary. Provide this when the beneficiary is a legal entity rather than an individual." })) }).annotate({ "description": "Travel Rule details for beneficiary crypto movement." })) }).annotate({ "description": "Travel Rule data for a crypto movement. Send this on create or update when the same counterparty should apply to every future use of a reusable resource, or send the same payload with `POST /travel_rule_data/{id}` when it belongs to one specific movement." })), "address": Schema.optionalKey(Schema.String.annotate({ "description": "The blockchain address the customer will send funds to." })), "memoless_address": Schema.optionalKey(Schema.String.annotate({ "description": "An alternative crypto wallet address that encodes the memo, allowing the customer to send funds without needing to include a separate memo. Currently only available for Stellar deposits." })), "state": Schema.optionalKey(Schema.String.annotate({ "description": "The state of the liquidation address. It could be \"active\" or \"deactivated\"" })), "return_memo": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "The memo included with return transactions. Present when `return_instructions` was set with a memo (e.g. required for Stellar to route funds to the correct end-customer)." })), "supported_currencies": Schema.optionalKey(Schema.Record(Schema.String, Schema.Array(Schema.Literals(["usdb", "usdc", "usdt", "usdl_linea", "pyusd", "eurc"]))).annotate({ "description": "The currencies this Liquidation Address accepts on each chain. Keys are `LiquidationAddressSourceChain` values (e.g. `ethereum`, `polygon`, `base`). For a single-chain, single-currency address this is just that one chain and currency; for a multi-chain (`chain` is `evm`) or multi-currency (`currency` is `all_supported`) address it lists every currency actually accepted on each chain.\n", "examples": [{ "ethereum": ["usdc", "eurc"], "polygon": ["usdc"] }], "readOnly": true })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "identifier": "CreateLiquidationAddressResponse" }) +export type UpdateLiquidationAddress = { readonly "external_account_id"?: string, readonly "custom_developer_fee_percent"?: string | null, readonly "destination"?: { readonly "currency": "usdb" | "usdc" | "usdt" | "usdl_linea" | "usd" | "pyusd" }, readonly "destination_ach_reference"?: string, readonly "destination_wire_message"?: string, readonly "destination_sepa_reference"?: string, readonly "destination_spei_reference"?: string, readonly "destination_swift_reference"?: string, readonly "destination_reference"?: string | null, readonly "return_address"?: string | null, readonly "return_instructions"?: { readonly "address": string, readonly "memo"?: string } } & { readonly [x: string]: Schema.Json } +export const UpdateLiquidationAddress = Schema.StructWithRest(Schema.Struct({ "external_account_id": Schema.optionalKey(Schema.String.annotate({ "description": "An optional identifier for the external account you wish to associate with this liquidation schedule.\n\n**Note**: Only one liquidation address can be associated with an external account per (customer, chain, currency).\n" })), "custom_developer_fee_percent": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "The developer fee percent that will be applied to this Liquidation Address or null to use the default fee. The value is a base 100 percentage, i.e. 10.2% is 10.2 in the API.", "format": "number" })), "destination": Schema.optionalKey(Schema.Struct({ "currency": Schema.Literals(["usdb", "usdc", "usdt", "usdl_linea", "usd", "pyusd"]).annotate({ "description": "The new destination currency. Must be deployed on the existing destination chain and accessible to the customer." }) }).annotate({ "description": "Update the destination currency for a crypto liquidation address. Only `currency` is required;\nchanging the payment rail or address is not currently supported.\n" })), "destination_ach_reference": Schema.optionalKey(Schema.String.annotate({ "description": "An ACH reference to include with each payout. Send `null` to clear an existing reference." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(10).annotate({ "expected": "a value with a length of at most 10" }))), "destination_wire_message": Schema.optionalKey(Schema.String.annotate({ "description": "A wire message to include with each payout. Send `null` to clear an existing message." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" }))), "destination_sepa_reference": Schema.optionalKey(Schema.String.annotate({ "description": "A SEPA reference to include with each payout. Send `null` to clear an existing reference." }).check(Schema.isMinLength(6).annotate({ "expected": "a value with a length of at least 6" })).check(Schema.isMaxLength(140).annotate({ "expected": "a value with a length of at most 140" }))), "destination_spei_reference": Schema.optionalKey(Schema.String.annotate({ "description": "A SPEI reference to include with each payout. Send `null` to clear an existing reference." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(40).annotate({ "expected": "a value with a length of at most 40" }))), "destination_swift_reference": Schema.optionalKey(Schema.String.annotate({ "description": "A SWIFT payment reference to include with each payout. Send `null` to clear an existing reference." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(140).annotate({ "expected": "a value with a length of at most 140" }))), "destination_reference": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "A payment reference message for newer payment rails (e.g. Pix, Faster Payments, and FedNow). Send `null` to clear an existing reference." })), "return_address": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Deprecated: use `return_instructions` instead.\n\nThe crypto wallet address that Bridge will use to return funds to the customer in case of a failed transaction.\nMust be on the same chain as the liquidation address.\nCannot be used on Stellar — use `return_instructions` with a `memo` instead.\n" })), "return_instructions": Schema.optionalKey(Schema.Struct({ "address": Schema.String.annotate({ "description": "The crypto wallet address to send returned funds to. Must be valid for the source payment rail's chain." }), "memo": Schema.optionalKey(Schema.String.annotate({ "description": "Memo to include with the return transaction. Required when the source payment rail is Stellar; optional for other memo-capable chains." })) }).annotate({ "description": "Optional instructions for where to send funds if the transfer is returned (e.g. refund). Only supported when the source payment rail is crypto. Memo is required when the source payment rail is Stellar." })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "identifier": "UpdateLiquidationAddress" }) +export type Drain = { readonly "id": string, readonly "amount": string, readonly "customer_id": string, readonly "liquidation_address_id": string, readonly "currency": "brl" | "cop" | "eur" | "eurc" | "gbp" | "mxn" | "pyusd" | "usd" | "usdb" | "usdc" | "usdt" | "usdl_linea", readonly "state": "awaiting_funds" | "in_review" | "funds_received" | "payment_submitted" | "payment_processed" | "canceled" | "error" | "undeliverable" | "returned" | "refund_in_flight" | "refund_failed" | "refunded", readonly "created_at"?: string, readonly "updated_at"?: string, readonly "deposit_tx_hash"?: string, readonly "from_address"?: string, readonly "source_payment_rail"?: string, readonly "destination"?: { readonly "payment_rail": "ach" | "wire" | "ach_push" | "ach_same_day" | "arbitrum" | "avalanche_c_chain" | "base" | "bre_b" | "co_bank_transfer" | "celo" | "ethereum" | "optimism" | "pix" | "polygon" | "solana" | "spei" | "stellar" | "tempo", readonly "currency": "usdb" | "usdc" | "usdt" | "usdl_linea" | "usd" | "pyusd", readonly "to_address"?: string, readonly "blockchain_memo"?: string, readonly "external_account_id"?: string, readonly "wire_message"?: string, readonly "sepa_reference"?: string, readonly "swift_reference"?: string, readonly "spei_reference"?: string, readonly "reference"?: string | string, readonly "ach_reference"?: string, readonly "imad"?: string, readonly "trace_number"?: string, readonly "tracking_number"?: string, readonly "transaction_id"?: string, readonly "sending_institution_name"?: string, readonly "uetr"?: string } & { readonly [x: string]: Schema.Json }, readonly "destination_tx_hash"?: string, readonly "refund_tx_hash"?: string, readonly "return_details"?: { readonly "reason"?: string, readonly "risk_rejection_reason"?: string } & { readonly [x: string]: Schema.Json }, readonly "receipt"?: { readonly "initial_amount": string, readonly "developer_fee": string, readonly "subtotal_amount": string, readonly "gas_fee"?: string, readonly "converted_amount": string, readonly "exchange_rate": Schema.Json, readonly "outgoing_amount": string, readonly "destination_currency": "usdb" | "usdc" | "usdt" | "usdl_linea" | "usd" | "pyusd", readonly "url"?: string } & { readonly [x: string]: Schema.Json }, readonly "exchange_details"?: { readonly "fixed_rate"?: string, readonly "estimated_market_rate"?: string, readonly "traded_market_rate"?: string, readonly "trade_at_market"?: boolean, readonly "updated_at"?: string } & { readonly [x: string]: Schema.Json } } & { readonly [x: string]: Schema.Json } +export const Drain = Schema.StructWithRest(Schema.Struct({ "id": Schema.String.annotate({ "description": "A UUID that uniquely identifies a resource", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" })), "amount": Schema.String.annotate({ "description": "Amount of the drain, represented as a dollar denominated string. Examples include \"100.25\", \"0.1\", \"1.234567\", \"1.01\" etc." }), "customer_id": Schema.String.annotate({ "description": "A UUID that uniquely identifies a resource", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" })), "liquidation_address_id": Schema.String.annotate({ "description": "A UUID that uniquely identifies a resource", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" })), "currency": Schema.Literals(["brl", "cop", "eur", "eurc", "gbp", "mxn", "pyusd", "usd", "usdb", "usdc", "usdt", "usdl_linea"]), "state": Schema.Literals(["awaiting_funds", "in_review", "funds_received", "payment_submitted", "payment_processed", "canceled", "error", "undeliverable", "returned", "refund_in_flight", "refund_failed", "refunded"]).annotate({ "description": "Status of the drain", "readOnly": true }), "created_at": Schema.optionalKey(Schema.String.annotate({ "description": "Time of creation of the drain", "readOnly": true, "format": "date-time" })), "updated_at": Schema.optionalKey(Schema.String.annotate({ "description": "Time of last update of the drain", "readOnly": true, "format": "date-time" })), "deposit_tx_hash": Schema.optionalKey(Schema.String.annotate({ "description": "Hash of the Liquidation Address deposit that triggered this drain", "readOnly": true })), "from_address": Schema.optionalKey(Schema.String.annotate({ "description": "The blockchain address that sent funds to the Liquidation Address", "readOnly": true })), "source_payment_rail": Schema.optionalKey(Schema.String.annotate({ "description": "The source payment rail where the funds originated from", "readOnly": true })), "destination": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "payment_rail": Schema.Literals(["ach", "wire", "ach_push", "ach_same_day", "arbitrum", "avalanche_c_chain", "base", "bre_b", "co_bank_transfer", "celo", "ethereum", "optimism", "pix", "polygon", "solana", "spei", "stellar", "tempo"]), "currency": Schema.Literals(["usdb", "usdc", "usdt", "usdl_linea", "usd", "pyusd"]), "to_address": Schema.optionalKey(Schema.String.annotate({ "description": "The crypto wallet address that the customer will ultimately receive funds at" })), "blockchain_memo": Schema.optionalKey(Schema.String.annotate({ "description": "The memo to include in the transaction, for blockchains that support memos only" })), "external_account_id": Schema.optionalKey(Schema.String.annotate({ "description": "External bank account to which Bridge will send the funds." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "wire_message": Schema.optionalKey(Schema.String.annotate({ "description": "A message to be sent with a wire transfer." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" }))), "sepa_reference": Schema.optionalKey(Schema.String.annotate({ "description": "A reference message to be sent with a SEPA transaction. We recommend you set a unique value to help you and your customers track payments end to end. It must be from 6 to 140 characters. The allowed characters are `a-z`, `A-Z`, `0-9`, spaces, ampersand (`&`), hyphen (`-`), full stop (`.`), and solidus (`/`). If not populated, the default value is \"Payment via Bridge {unique_token}\"." }).check(Schema.isMinLength(6).annotate({ "expected": "a value with a length of at least 6" })).check(Schema.isMaxLength(140).annotate({ "expected": "a value with a length of at most 140" }))), "swift_reference": Schema.optionalKey(Schema.String.annotate({ "description": "A payment reference message or remittance information to be included in a SWIFT transaction. It can have at most 4 lines (separated by \"\\n\"), each line with a max length of 35 chars. The allowed characters are `a-z`, `A-Z`, `0-9`, special characters (`/` `-` `?` `:` `(` `)` `.` `,` `'` `+`), and space" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(140).annotate({ "expected": "a value with a length of at most 140" }))), "spei_reference": Schema.optionalKey(Schema.String.annotate({ "description": "A payment reference message or remittance information to be included in a SPEI transaction. The allowed characters are alphanumeric `a-z`, `A-Z`, `0-9`, and space" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(40).annotate({ "expected": "a value with a length of at most 40" }))), "reference": Schema.optionalKey(Schema.Union([Schema.String.annotate({ "title": "Faster Payments" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(18).annotate({ "expected": "a value with a length of at most 18" })), Schema.String.annotate({ "title": "Pix" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(100).annotate({ "expected": "a value with a length of at most 100" }))], { mode: "oneOf" }).annotate({ "description": "A payment reference message for newer payment rails (e.g. Pix, Faster Payments, and FedNow).\n" })), "ach_reference": Schema.optionalKey(Schema.String.annotate({ "description": "A reference message to be sent with an ACH transaction. It can be at most 10 characters, A-Z, a-z, 0-9, and spaces." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(10).annotate({ "expected": "a value with a length of at most 10" }))), "imad": Schema.optionalKey(Schema.String.annotate({ "description": "(Wire only) The IMAD of a wire transfer, if available" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(40).annotate({ "expected": "a value with a length of at most 40" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "trace_number": Schema.optionalKey(Schema.String.annotate({ "description": "The trace number of an ACH transfer", "readOnly": true }).check(Schema.isMinLength(15).annotate({ "expected": "a value with a length of at least 15" })).check(Schema.isMaxLength(15).annotate({ "expected": "a value with a length of at most 15" })).check(Schema.isPattern(new RegExp("[0-9]")).annotate({ "expected": "a string matching the RegExp [0-9]" }))), "tracking_number": Schema.optionalKey(Schema.String.annotate({ "description": "The primary tracking identifier for this fiat transaction. Format varies by payment rail (e.g., UETR for SEPA/FPS, clave de rastreo for SPEI, end-to-end ID for PIX).", "readOnly": true })), "transaction_id": Schema.optionalKey(Schema.String.annotate({ "description": "Deprecated: use tracking_number instead. The unique transaction identifier for this payment.", "readOnly": true })), "sending_institution_name": Schema.optionalKey(Schema.String.annotate({ "description": "The name of the institution sending the funds", "readOnly": true })), "uetr": Schema.optionalKey(Schema.String.annotate({ "description": "Deprecated: use tracking_number instead. The unique end-to-end transaction reference, for tracing purposes.", "readOnly": true })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Destination information of a drain.", "readOnly": true })), "destination_tx_hash": Schema.optionalKey(Schema.String.annotate({ "description": "Hash of withdrawal of funds to the destination", "readOnly": true })), "refund_tx_hash": Schema.optionalKey(Schema.String.annotate({ "description": "Hash of refund, if the drain has been returned", "readOnly": true })), "return_details": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "reason": Schema.optionalKey(Schema.String.annotate({ "description": "The reason for the return, as given by the returning financial institution." })), "risk_rejection_reason": Schema.optionalKey(Schema.String.annotate({ "description": "If the return is due to a risk rejection, this field will be populated with the reason for the risk rejection." })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Return information, if the drain has been returned.", "readOnly": true })), "receipt": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "initial_amount": Schema.String.annotate({ "description": "The initial amount of the drain, denominated in the fiat currency to which the currency of the Liquidation Address is pegged. Examples include \"100.25\", \"0.1\", \"1.234567\", \"1.000000000000000001\" etc." }), "developer_fee": Schema.String.annotate({ "description": "The developer fee, denominated in the fiat currency to which the currency of the Liquidation Address is pegged. This fee is a specific amount deducted from the initial total before conversion, rather than a percentage." }), "subtotal_amount": Schema.String.annotate({ "description": "The initial amount of the drain less the `developer_fee`, denominated in the fiat currency to which the Liquidation Address currency is pegged. Examples include \"100.25\", \"0.1\", \"1.234567\", \"1.000000000000000001\" etc." }), "gas_fee": Schema.optionalKey(Schema.String.annotate({ "description": "The fee that is deducted from the withdrawn amount to pay for gas. Only included for crypto withdrawals that cost gas (e.g. USDT). It's denominated in the fiat currency to which the destination currency is pegged." })), "converted_amount": Schema.String.annotate({ "description": "The converted amount of the drain. It's denominated in the destination currency or its pegged fiat currency." }), "exchange_rate": Schema.Json.annotate({ "expected": "JSON value", "description": "The effective exchange rate that can be calculated by dividing the converted amount by the amount available for conversion after deducting the developer fee." }), "outgoing_amount": Schema.String.annotate({ "description": "The final amount of the drain, equal to the `converted_amount` minus any gas fees. It's denominated in the destination currency or its pegged fiat currency." }), "destination_currency": Schema.Literals(["usdb", "usdc", "usdt", "usdl_linea", "usd", "pyusd"]).annotate({ "description": "The currency of the fund sent to the customer." }), "url": Schema.optionalKey(Schema.String.annotate({ "description": "The URL of a user-facing copy of the receipt." })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Receipt information of a drain.", "readOnly": true })), "exchange_details": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "fixed_rate": Schema.optionalKey(Schema.String.annotate({ "description": "The target exchange rate." })), "estimated_market_rate": Schema.optionalKey(Schema.String.annotate({ "description": "The estimated achievable rate based on current market conditions." })), "traded_market_rate": Schema.optionalKey(Schema.String.annotate({ "description": "The actual effective exchange rate achieved." })), "trade_at_market": Schema.optionalKey(Schema.Boolean.annotate({ "description": "Whether market-rate execution has been applied to this trade." })), "updated_at": Schema.optionalKey(Schema.String.annotate({ "description": "Timestamp of the last exchange details update.", "format": "date-time" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Exchange details for the associated trade, if applicable.", "readOnly": true })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "identifier": "Drain" }) +export type Balance = { readonly "active_balance"?: string, readonly "pending_balance"?: string } & { readonly [x: string]: Schema.Json } +export const Balance = Schema.StructWithRest(Schema.Struct({ "active_balance": Schema.optionalKey(Schema.String.annotate({ "description": "Active Balance (Money currently not being processed) of a Liquidation Address" })), "pending_balance": Schema.optionalKey(Schema.String.annotate({ "description": "Pending Balance (Money being processed) of a Liquidation Address" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "identifier": "Balance" }) +export type VirtualAccountActivationStatus = "activated" | "deactivated" +export const VirtualAccountActivationStatus = Schema.Literals(["activated", "deactivated"]).annotate({ "description": "The activation status of the Virtual Account", "identifier": "VirtualAccountActivationStatus" }) +export type VirtualAccountResponse = { readonly "id"?: string, readonly "status"?: "activated" | "deactivated", readonly "developer_fee_percent"?: string, readonly "fee_config"?: { readonly "source"?: { readonly [x: string]: { readonly "fee_percent"?: string, readonly "fee_amount"?: string, readonly "minimum_fee"?: string, readonly "maximum_fee"?: string } } }, readonly "customer_id"?: string, readonly "created_at"?: string, readonly "source_deposit_instructions"?: { readonly "bank_account_number": string, readonly "bank_routing_number": string, readonly "bank_beneficiary_name": string, readonly "bank_beneficiary_address": string, readonly "currency": "usd", readonly "payment_rail"?: "ach_push" | "bre_b" | "faster_payments" | "pix" | "sepa" | "spei" | "wire", readonly "payment_rails": ReadonlyArray<"ach_push" | "fednow" | "wire">, readonly "bank_name": string, readonly "bank_address": string } & { readonly [x: string]: Schema.Json } | { readonly "iban": string, readonly "bic": string, readonly "account_holder_name": string, readonly "bank_beneficiary_name"?: string, readonly "bank_beneficiary_address"?: string, readonly "currency": "eur", readonly "payment_rails": "sepa", readonly "bank_name": string, readonly "bank_address": string } & { readonly [x: string]: Schema.Json } | { readonly "clabe": string, readonly "account_holder_name": string, readonly "currency": "mxn", readonly "payment_rails": ReadonlyArray<"spei">, readonly "bank_name": string, readonly "bank_address": string } & { readonly [x: string]: Schema.Json } | { readonly "br_code": string, readonly "account_holder_name": string, readonly "currency": "brl", readonly "payment_rails": ReadonlyArray<"pix">, readonly "bank_name": string, readonly "bank_address": string } & { readonly [x: string]: Schema.Json } | { readonly "account_number": string, readonly "sort_code": string, readonly "account_holder_name": string, readonly "bank_beneficiary_name"?: string, readonly "bank_beneficiary_address"?: string, readonly "currency": "gbp", readonly "payment_rails": "faster_payments", readonly "bank_name": string, readonly "bank_address": string } & { readonly [x: string]: Schema.Json } | { readonly "bre_b_key": string, readonly "account_holder_name": string, readonly "deposit_message"?: string, readonly "currency": "cop", readonly "payment_rails": ReadonlyArray<"bre_b">, readonly "bank_name": string, readonly "bank_address": string } & { readonly [x: string]: Schema.Json }, readonly "destination"?: { readonly "currency": "usdb" | "usdc" | "usdt" | "usdl_linea" | "pyusd" | "eurc", readonly "payment_rail": "arbitrum" | "avalanche_c_chain" | "base" | "celo" | "ethereum" | "linea" | "optimism" | "polygon" | "solana" | "stellar" | "tempo" | "tron" | "xdc", readonly "address"?: string, readonly "blockchain_memo"?: string, readonly "bridge_wallet_id"?: string, readonly "prefunded_account_id"?: string } & { readonly [x: string]: Schema.Json } } & { readonly [x: string]: Schema.Json } +export const VirtualAccountResponse = Schema.StructWithRest(Schema.Struct({ "id": Schema.optionalKey(Schema.String.annotate({ "description": "A UUID that uniquely identifies a resource", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "status": Schema.optionalKey(Schema.Literals(["activated", "deactivated"]).annotate({ "description": "The activation status of the Virtual Account" })), "developer_fee_percent": Schema.optionalKey(Schema.String.annotate({ "description": "The developer fee percent that will be applied to this Virtual Account. The value is a base 100 percentage, i.e. 10.2% is 10.2 in the API.", "examples": ["0.1"], "format": "number" })), "fee_config": Schema.optionalKey(Schema.Struct({ "source": Schema.optionalKey(Schema.Record(Schema.String, Schema.Struct({ "fee_percent": Schema.optionalKey(Schema.String.annotate({ "description": "Percentage fee (0-100, exclusive). Applied to the amount remaining after any flat fee deduction.", "examples": ["1.5"], "format": "number" })), "fee_amount": Schema.optionalKey(Schema.String.annotate({ "description": "Flat fee amount deducted before percentage calculation", "examples": ["10.00"], "format": "number" })), "minimum_fee": Schema.optionalKey(Schema.String.annotate({ "description": "Minimum total fee floor", "examples": ["1.00"], "format": "number" })), "maximum_fee": Schema.optionalKey(Schema.String.annotate({ "description": "Maximum total fee cap", "examples": ["1000.00"], "format": "number" })) }).annotate({ "description": "Fee parameters for a specific payment rail or default configuration" })).annotate({ "description": "Source-side fee configuration keyed by payment rail or `default`", "examples": [{ "default": { "fee_percent": "0.5", "minimum_fee": "1.00" }, "wire": { "fee_amount": "10.00", "fee_percent": "1.0" } }] })) }).annotate({ "description": "Developer fee configuration. Available by request only. Contact Bridge to enable this feature for your developer account. Responses render source-side fees keyed by payment rail, using `default` for a catch-all configuration." })), "customer_id": Schema.optionalKey(Schema.String.annotate({ "description": "A UUID that uniquely identifies a resource" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "created_at": Schema.optionalKey(Schema.String.annotate({ "description": "Time of creation of the virtual account", "readOnly": true, "format": "date-time" })), "source_deposit_instructions": Schema.optionalKey(Schema.Union([Schema.StructWithRest(Schema.Struct({ "bank_account_number": Schema.String.annotate({ "description": "The account number of the bank that the customer should send the deposit to" }), "bank_routing_number": Schema.String.annotate({ "description": "The routing number of the bank that the customer should send the deposit to" }), "bank_beneficiary_name": Schema.String.annotate({ "description": "If available, the name of the beneficiary of the bank account that the customer should send the deposit to" }), "bank_beneficiary_address": Schema.String.annotate({ "description": "If available, the address of the beneficiary of the bank account that the customer should send the deposit to" }), "currency": Schema.Literal("usd"), "payment_rail": Schema.optionalKey(Schema.Literals(["ach_push", "bre_b", "faster_payments", "pix", "sepa", "spei", "wire"])), "payment_rails": Schema.Array(Schema.Literals(["ach_push", "fednow", "wire"])).annotate({ "description": "The payment rails supported by these deposit instructions" }), "bank_name": Schema.String.annotate({ "description": "The name of the bank that the customer should send the deposit to" }), "bank_address": Schema.String.annotate({ "description": "The address of the bank that the customer should send the deposit to" }) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "title": "Virtual Account US", "examples": [{ "currency": "usd", "payment_rails": ["ach_push", "fednow", "wire"], "bank_name": "Lead Bank", "bank_address": "1801 Main St., Kansas City, MO 64108", "bank_beneficiary_name": "Customer Name", "bank_beneficiary_address": "1234 Main St., Kansas City, MO 64108", "bank_account_number": "123456789", "bank_routing_number": "87654321" }], "readOnly": true }), Schema.StructWithRest(Schema.Struct({ "iban": Schema.String.annotate({ "description": "he IBAN of the account that the customer should send the deposit to" }), "bic": Schema.String.annotate({ "description": "The BIC of the bank that the customer should send the deposit to" }), "account_holder_name": Schema.String.annotate({ "description": "The name of the account owner that the deposit must be sent to." }), "bank_beneficiary_name": Schema.optionalKey(Schema.String.annotate({ "description": "The account beneficiary name — the customer for POBO accounts, otherwise the Bridge legal entity. Senders should match this name." })), "bank_beneficiary_address": Schema.optionalKey(Schema.String.annotate({ "description": "The account beneficiary address. Present for POBO accounts (the customer's registered address)." })), "currency": Schema.Literal("eur"), "payment_rails": Schema.Literal("sepa"), "bank_name": Schema.String.annotate({ "description": "The name of the bank that the customer should send the deposit to" }), "bank_address": Schema.String.annotate({ "description": "The address of the bank that the customer should send the deposit to" }) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "title": "Virtual IBAN", "readOnly": true }), Schema.StructWithRest(Schema.Struct({ "clabe": Schema.String.annotate({ "description": "The CLABE (account number) of the account that the customer should send the deposit to" }), "account_holder_name": Schema.String.annotate({ "description": "The name of the account owner that the deposit must be sent to." }), "currency": Schema.Literal("mxn"), "payment_rails": Schema.Array(Schema.Literal("spei")).annotate({ "description": "The payment rails supported by these deposit instructions" }), "bank_name": Schema.String.annotate({ "description": "The name of the bank that the customer should send the deposit to" }), "bank_address": Schema.String.annotate({ "description": "The address of the bank that the customer should send the deposit to" }) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "title": "Virtual Account MX", "readOnly": true }), Schema.StructWithRest(Schema.Struct({ "br_code": Schema.String.annotate({ "description": "The BR Code that the customer should send the deposit to" }), "account_holder_name": Schema.String.annotate({ "description": "The name of the account owner that the deposit must be sent to." }), "currency": Schema.Literal("brl"), "payment_rails": Schema.Array(Schema.Literal("pix")).annotate({ "description": "The payment rails supported by these deposit instructions" }), "bank_name": Schema.String.annotate({ "description": "The name of the bank that the customer should send the deposit to" }), "bank_address": Schema.String.annotate({ "description": "The address of the bank that the customer should send the deposit to" }) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "title": "Virtual Account BR", "readOnly": true }), Schema.StructWithRest(Schema.Struct({ "account_number": Schema.String.annotate({ "description": "The bank account number" }).check(Schema.isMinLength(8).annotate({ "expected": "a value with a length of at least 8" })).check(Schema.isMaxLength(8).annotate({ "expected": "a value with a length of at most 8" })), "sort_code": Schema.String.annotate({ "description": "The sort code, without hyphens" }).check(Schema.isMinLength(6).annotate({ "expected": "a value with a length of at least 6" })).check(Schema.isMaxLength(6).annotate({ "expected": "a value with a length of at most 6" })), "account_holder_name": Schema.String.annotate({ "description": "The name of the account owner that the deposit must be sent to." }), "bank_beneficiary_name": Schema.optionalKey(Schema.String.annotate({ "description": "The account beneficiary name — the customer for POBO accounts, otherwise the Bridge legal entity. Senders should match this name." })), "bank_beneficiary_address": Schema.optionalKey(Schema.String.annotate({ "description": "The account beneficiary address. Present for POBO accounts (the customer's registered address)." })), "currency": Schema.Literal("gbp"), "payment_rails": Schema.Literal("faster_payments"), "bank_name": Schema.String.annotate({ "description": "The name of the bank that the customer should send the deposit to" }), "bank_address": Schema.String.annotate({ "description": "The address of the bank that the customer should send the deposit to" }) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "title": "gb", "readOnly": true }), Schema.StructWithRest(Schema.Struct({ "bre_b_key": Schema.String.annotate({ "description": "The Bre-B key of the Colombian bank account for receiving COP deposits" }), "account_holder_name": Schema.String.annotate({ "description": "The name of the account owner that the deposit must be sent to." }), "deposit_message": Schema.optionalKey(Schema.String.annotate({ "description": "The reference message to include with the COP deposit" })), "currency": Schema.Literal("cop"), "payment_rails": Schema.Array(Schema.Literal("bre_b")).annotate({ "description": "The payment rails supported by these deposit instructions" }), "bank_name": Schema.String.annotate({ "description": "The name of the bank that the customer should send the deposit to" }), "bank_address": Schema.String.annotate({ "description": "The address of the bank that the customer should send the deposit to" }) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "title": "Virtual Account CO (Bre-B)", "readOnly": true })], { mode: "oneOf" }).annotate({ "title": "Source Deposit Instructions", "readOnly": true })), "destination": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "currency": Schema.Literals(["usdb", "usdc", "usdt", "usdl_linea", "pyusd", "eurc"]), "payment_rail": Schema.Literals(["arbitrum", "avalanche_c_chain", "base", "celo", "ethereum", "linea", "optimism", "polygon", "solana", "stellar", "tempo", "tron", "xdc"]), "address": Schema.optionalKey(Schema.String.annotate({ "description": "The crypto wallet address that the customer wishes to ultimately receive funds at" })), "blockchain_memo": Schema.optionalKey(Schema.String.annotate({ "description": "The memo to include when sending funds on chain. Only allowed for blockchains that support memos such as Stellar" })), "bridge_wallet_id": Schema.optionalKey(Schema.String.annotate({ "description": "The Bridge Wallet to which Bridge will send the funds. The chain associated with the Bridge Wallet must match the payment rail." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "prefunded_account_id": Schema.optionalKey(Schema.String.annotate({ "description": "The id of the prefunded account to which the funds will be sent. Use 'prefunded' as the payment rail and 'usd' as the currency when specifying a prefunded account id." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "examples": [{ "currency": "usdc", "payment_rail": "polygon", "address": "0xdeadbeef" }] })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "identifier": "VirtualAccountResponse" }) +export type CreateVirtualAccount = { readonly "developer_fee_percent"?: string, readonly "fee_config"?: { readonly "source"?: { readonly "fee_percent"?: string, readonly "fee_amount"?: string, readonly "minimum_fee"?: string, readonly "maximum_fee"?: string } | { readonly [x: string]: { readonly "fee_percent"?: string, readonly "fee_amount"?: string, readonly "minimum_fee"?: string, readonly "maximum_fee"?: string } } }, readonly "source": { readonly "currency": "usd" | "eur" | "mxn" | "brl" | "cop" | "gbp" } & { readonly [x: string]: Schema.Json }, readonly "destination": { readonly "currency": "usdb" | "usdc" | "usdt" | "usdl_linea" | "pyusd" | "eurc", readonly "payment_rail": "arbitrum" | "avalanche_c_chain" | "base" | "celo" | "ethereum" | "linea" | "optimism" | "polygon" | "solana" | "stellar" | "tempo" | "tron" | "xdc", readonly "address"?: string, readonly "blockchain_memo"?: string, readonly "bridge_wallet_id"?: string, readonly "prefunded_account_id"?: string } & { readonly [x: string]: Schema.Json }, readonly "travel_rule_data"?: { readonly "originator"?: { readonly "is_self"?: boolean, readonly "name"?: string, readonly "address"?: { readonly "street_line_1"?: string, readonly "street_line_2"?: string, readonly "city"?: string, readonly "state"?: string, readonly "postal_code"?: string, readonly "country"?: string }, readonly "wallet_type"?: "hosted" | "external" | "self_custodied", readonly "wallet_attested_ownership_at"?: string, readonly "identifying_information"?: ReadonlyArray<{ readonly "type": "drivers_license" | "matriculate_id" | "military_id" | "national_id" | "passport" | "permanent_residency_id" | "state_or_provincial_id" | "visa" | "abn" | "acn" | "ahv" | "ak" | "aom" | "arbn" | "avs" | "bc" | "bce" | "bin" | "bir" | "bp" | "brn" | "bsn" | "bvn" | "cc" | "cdi" | "cedula_juridica" | "cf" | "cif" | "cin" | "cipc" | "cn" | "cnp" | "cnpj" | "cpf" | "cpr" | "crc" | "crib" | "crn" | "cro" | "cui" | "cuil" | "curp" | "cuit" | "cvr" | "edrpou" | "ein" | "embg" | "emirates_id" | "en" | "fin" | "fn" | "gstin" | "gui" | "hetu" | "hkid" | "hn" | "ic" | "ico" | "id" | "id_broj" | "idno" | "idnp" | "idnr" | "if" | "iin" | "ik" | "inn" | "ird" | "itin" | "itr" | "iva" | "jmbg" | "kbo" | "kvk" | "matricule" | "mf" | "mn" | "ms" | "mst" | "nic" | "nicn" | "nie" | "nif" | "nin" | "nino" | "nip" | "nipc" | "nipt" | "nit" | "npwp" | "nric" | "nrn" | "nrt" | "ntn" | "nuit" | "nzbn" | "oib" | "orgnr" | "other" | "pan" | "partita_iva" | "pesel" | "pib" | "pin" | "pk" | "ppsn" | "qid" | "rc" | "regon" | "rfc" | "ricn" | "rif" | "rn" | "rnc" | "rnokpp" | "rp" | "rrn" | "rtn" | "ruc" | "rut" | "si" | "sin" | "siren" | "siret" | "spi" | "ssm" | "ssn" | "steuer_id" | "strn" | "tckn" | "tfn" | "tin" | "tpin" | "trn" | "ucn" | "uen" | "uic" | "uid" | "usc" | "ust_idnr" | "utr" | "vat" | "vkn" | "voen" | "y_tunnus", readonly "issuing_country": string, readonly "number"?: string, readonly "description"?: string, readonly "expiration"?: string, readonly "image_front"?: string, readonly "image_back"?: string }>, readonly "birth_date"?: string, readonly "place_of_birth"?: { readonly "country"?: string, readonly "city"?: string }, readonly "legal_entity_identifier"?: string }, readonly "beneficiary"?: { readonly "is_self"?: boolean, readonly "name"?: string, readonly "address"?: { readonly "street_line_1"?: string, readonly "street_line_2"?: string, readonly "city"?: string, readonly "state"?: string, readonly "postal_code"?: string, readonly "country"?: string }, readonly "wallet_type"?: "hosted" | "external" | "self_custodied", readonly "wallet_attested_ownership_at"?: string, readonly "legal_entity_identifier"?: string } } } & { readonly [x: string]: Schema.Json } +export const CreateVirtualAccount = Schema.StructWithRest(Schema.Struct({ "developer_fee_percent": Schema.optionalKey(Schema.String.annotate({ "description": "The developer fee percent that will be applied to this Virtual Account. The value is a base 100 percentage, i.e. 10.2% is 10.2 in the API.", "examples": ["0.1"], "format": "number" })), "fee_config": Schema.optionalKey(Schema.Struct({ "source": Schema.optionalKey(Schema.Union([Schema.Struct({ "fee_percent": Schema.optionalKey(Schema.String.annotate({ "description": "Percentage fee (0-100, exclusive). Applied to the amount remaining after any flat fee deduction.", "examples": ["1.5"], "format": "number" })), "fee_amount": Schema.optionalKey(Schema.String.annotate({ "description": "Flat fee amount deducted before percentage calculation", "examples": ["10.00"], "format": "number" })), "minimum_fee": Schema.optionalKey(Schema.String.annotate({ "description": "Minimum total fee floor", "examples": ["1.00"], "format": "number" })), "maximum_fee": Schema.optionalKey(Schema.String.annotate({ "description": "Maximum total fee cap", "examples": ["1000.00"], "format": "number" })) }).annotate({ "description": "Fee parameters for a specific payment rail or default configuration" }), Schema.Record(Schema.String, Schema.Struct({ "fee_percent": Schema.optionalKey(Schema.String.annotate({ "description": "Percentage fee (0-100, exclusive). Applied to the amount remaining after any flat fee deduction.", "examples": ["1.5"], "format": "number" })), "fee_amount": Schema.optionalKey(Schema.String.annotate({ "description": "Flat fee amount deducted before percentage calculation", "examples": ["10.00"], "format": "number" })), "minimum_fee": Schema.optionalKey(Schema.String.annotate({ "description": "Minimum total fee floor", "examples": ["1.00"], "format": "number" })), "maximum_fee": Schema.optionalKey(Schema.String.annotate({ "description": "Maximum total fee cap", "examples": ["1000.00"], "format": "number" })) }).annotate({ "description": "Fee parameters for a specific payment rail or default configuration" }))]).annotate({ "description": "Source-side fee configuration. Supports direct fee params under `source`, an explicit `default` key, payment-rail keys such as `ach_push` and `wire`, or a mixed default-plus-override form.", "examples": [{ "fee_percent": "0.5", "minimum_fee": "1.00", "wire": { "fee_amount": "10.00", "fee_percent": "1.0" } }] })) }).annotate({ "description": "Developer fee configuration. Available by request only. Contact Bridge to enable this feature for your developer account. The `source` object supports direct fee parameters as a shorthand for a default fee, an explicit `default` key, payment-rail keys (e.g. `ach_push`, `wire`), or a mixed default-plus-override form." })), "source": Schema.StructWithRest(Schema.Struct({ "currency": Schema.Literals(["usd", "eur", "mxn", "brl", "cop", "gbp"]) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "examples": [{ "currency": "usd" }] }), "destination": Schema.StructWithRest(Schema.Struct({ "currency": Schema.Literals(["usdb", "usdc", "usdt", "usdl_linea", "pyusd", "eurc"]), "payment_rail": Schema.Literals(["arbitrum", "avalanche_c_chain", "base", "celo", "ethereum", "linea", "optimism", "polygon", "solana", "stellar", "tempo", "tron", "xdc"]), "address": Schema.optionalKey(Schema.String.annotate({ "description": "The crypto wallet address that the customer wishes to ultimately receive funds at" })), "blockchain_memo": Schema.optionalKey(Schema.String.annotate({ "description": "The memo to include when sending funds on chain. Only allowed for blockchains that support memos such as Stellar" })), "bridge_wallet_id": Schema.optionalKey(Schema.String.annotate({ "description": "The Bridge Wallet to which Bridge will send the funds. The chain associated with the Bridge Wallet must match the payment rail." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "prefunded_account_id": Schema.optionalKey(Schema.String.annotate({ "description": "The id of the prefunded account to which the funds will be sent. Use 'prefunded' as the payment rail and 'usd' as the currency when specifying a prefunded account id." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "examples": [{ "currency": "usdc", "payment_rail": "polygon", "address": "0xdeadbeef" }] }), "travel_rule_data": Schema.optionalKey(Schema.Struct({ "originator": Schema.optionalKey(Schema.Struct({ "is_self": Schema.optionalKey(Schema.Boolean.annotate({ "description": "Set to `true` when this party is the same person or business as the Bridge customer on the resource. When `true`, Bridge uses the customer's name and address on file instead of relying on `name` and `address` in this payload." })), "name": Schema.optionalKey(Schema.String.annotate({ "description": "Legal name of the originator or beneficiary. Usually omitted when `is_self` is `true`." })), "address": Schema.optionalKey(Schema.Struct({ "street_line_1": Schema.optionalKey(Schema.String), "street_line_2": Schema.optionalKey(Schema.String), "city": Schema.optionalKey(Schema.String), "state": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-2 subdivision code." })), "postal_code": Schema.optionalKey(Schema.String), "country": Schema.optionalKey(Schema.String.annotate({ "description": "Three-letter alpha-3 country code as defined in the ISO 3166-1 spec." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))) }).annotate({ "description": "Address for travel rule submissions. All fields are optional to support partial address data (e.g. country-only)." })), "wallet_type": Schema.optionalKey(Schema.Literals(["hosted", "external", "self_custodied"]).annotate({ "description": "Indicates the custody model for the wallet. Use `self_custodied` for customer-owned wallets (customer controls private keys), `hosted` for wallets managed by a developer or regulated entity on behalf of the customer, or `external` for wallets belonging to external exchanges or smart contracts." })), "wallet_attested_ownership_at": Schema.optionalKey(Schema.String.annotate({ "description": "Required when `wallet_type` is `self-custodied` or `hosted`. Must be a timestamp in the past indicating when wallet ownership was attested.", "format": "date-time" })), "identifying_information": Schema.optionalKey(Schema.Array(Schema.Struct({ "type": Schema.Literals(["drivers_license", "matriculate_id", "military_id", "national_id", "passport", "permanent_residency_id", "state_or_provincial_id", "visa", "abn", "acn", "ahv", "ak", "aom", "arbn", "avs", "bc", "bce", "bin", "bir", "bp", "brn", "bsn", "bvn", "cc", "cdi", "cedula_juridica", "cf", "cif", "cin", "cipc", "cn", "cnp", "cnpj", "cpf", "cpr", "crc", "crib", "crn", "cro", "cui", "cuil", "curp", "cuit", "cvr", "edrpou", "ein", "embg", "emirates_id", "en", "fin", "fn", "gstin", "gui", "hetu", "hkid", "hn", "ic", "ico", "id", "id_broj", "idno", "idnp", "idnr", "if", "iin", "ik", "inn", "ird", "itin", "itr", "iva", "jmbg", "kbo", "kvk", "matricule", "mf", "mn", "ms", "mst", "nic", "nicn", "nie", "nif", "nin", "nino", "nip", "nipc", "nipt", "nit", "npwp", "nric", "nrn", "nrt", "ntn", "nuit", "nzbn", "oib", "orgnr", "other", "pan", "partita_iva", "pesel", "pib", "pin", "pk", "ppsn", "qid", "rc", "regon", "rfc", "ricn", "rif", "rn", "rnc", "rnokpp", "rp", "rrn", "rtn", "ruc", "rut", "si", "sin", "siren", "siret", "spi", "ssm", "ssn", "steuer_id", "strn", "tckn", "tfn", "tin", "tpin", "trn", "ucn", "uen", "uic", "uid", "usc", "ust_idnr", "utr", "vat", "vkn", "voen", "y_tunnus"]).annotate({ "description": "Tax identification number type or government-issued ID document type (see enum). Country-specific tax and national ID lists: [Individuals](https://apidocs.bridge.xyz/docs/individual-tax-identification-numbers-by-country), [Businesses](https://apidocs.bridge.xyz/docs/business-tax-identification-numbers-by-country).\n\n**EEA / BBSA (policy in `eea_requirements.rb`):** In-scope individuals and UBOs need **both** a valid national-ID-type entry and a valid TIN per [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements). In-scope businesses need business registration **and** business tax ID types per country tables there. **TIN issuing country** must match residence (individuals) or incorporation (businesses). **Foreign tax** outside the incorporation country: set `has_foreign_tax_registration` on the business customer and add TIN objects per jurisdiction ([foreign tax / tax residency](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#tax-residency-status-foreign-tax-registry)).\n" }), "issuing_country": Schema.String.annotate({ "description": "The ISO 3166-1 (three-character) country code that issued the provided document." }), "number": Schema.optionalKey(Schema.String.annotate({ "description": "The unique identifier of the document. Required if this document is being used as a tax identification number (e.g., you are providing a passport or national_id with no other identification)." })), "description": Schema.optionalKey(Schema.String.annotate({ "description": "A description describing the provided document. This field is required when `other` is selected." })), "expiration": Schema.optionalKey(Schema.String.annotate({ "description": "The expiration date of the given document in yyyy-mm-dd format." })), "image_front": Schema.optionalKey(Schema.String.annotate({ "description": "This field is optionally accepted for tax_id types, but required for government_id types. Base64 encoded image* of the front side of the provided document, following the data-uri scheme i.e. data:image/[type];base64,[base_64_encoded_file_contents], with a minimum size of 200px x 200px \\n\\n*Maximum File Size: 15MB\\n\\n*Valid file types: .pdf, .jpeg, .jpg, .png, .heic, .tif\n\n_Note: When combined with an `image_back`, the combined size of both images must not exceed 24MB._\n" })), "image_back": Schema.optionalKey(Schema.String.annotate({ "description": "Base64 encoded image* of the back side of the provided document, following the data-uri scheme i.e. data:image/[type];base64,[base_64_encoded_file_contents], with a minimum size of 200px x 200px \\n\\n*Maximum File Size: 15MB\\n\\n*Valid file types: .pdf, .jpeg, .jpg, .png, .heic, .tif\n\n_Note: When combined with an `image_front`, the combined size of both images must not exceed 24MB._\n" })) })).annotate({ "title": "Identification Information", "writeOnly": true, "description": "List of identification objects for the originator. Do **not** include `image_front` or `image_back` fields in this context; those are not accepted in Travel Rule submissions.\n" })), "birth_date": Schema.optionalKey(Schema.String.annotate({ "description": "Date of birth in format yyyy-mm-dd." }).check(Schema.isMinLength(10).annotate({ "expected": "a value with a length of at least 10" })).check(Schema.isMaxLength(10).annotate({ "expected": "a value with a length of at most 10" }))), "place_of_birth": Schema.optionalKey(Schema.Struct({ "country": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-1 alpha-3 country code for the place of birth." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))), "city": Schema.optionalKey(Schema.String.annotate({ "description": "City of birth (recommended for EEA)." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))) }).annotate({ "description": "Country (and optionally city) of birth. **EEA / BBSA in-scope customers:** supply when onboarding individuals or associated persons under the [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#country-of-birth-and-city-of-birth). This is a sparse address — no street address. At least `country` should be present when the object is sent; `city` is recommended and will be required by EU law in 2027.\n" })), "legal_entity_identifier": Schema.optionalKey(Schema.String.annotate({ "description": "The Legal Entity Identifier (LEI) or equivalent (e.g. VAT number) of the originator. Provide this when the originator is a legal entity rather than an individual." })) }).annotate({ "description": "Travel Rule details for originator crypto movement." })), "beneficiary": Schema.optionalKey(Schema.Struct({ "is_self": Schema.optionalKey(Schema.Boolean.annotate({ "description": "Set to `true` when this party is the same person or business as the Bridge customer on the resource. When `true`, Bridge uses the customer's name and address on file instead of relying on `name` and `address` in this payload." })), "name": Schema.optionalKey(Schema.String.annotate({ "description": "Legal name of the originator or beneficiary. Usually omitted when `is_self` is `true`." })), "address": Schema.optionalKey(Schema.Struct({ "street_line_1": Schema.optionalKey(Schema.String), "street_line_2": Schema.optionalKey(Schema.String), "city": Schema.optionalKey(Schema.String), "state": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-2 subdivision code." })), "postal_code": Schema.optionalKey(Schema.String), "country": Schema.optionalKey(Schema.String.annotate({ "description": "Three-letter alpha-3 country code as defined in the ISO 3166-1 spec." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))) }).annotate({ "description": "Address for travel rule submissions. All fields are optional to support partial address data (e.g. country-only)." })), "wallet_type": Schema.optionalKey(Schema.Literals(["hosted", "external", "self_custodied"]).annotate({ "description": "Indicates the custody model for the wallet. Use `self_custodied` for customer-owned wallets (customer controls private keys), `hosted` for wallets managed by a developer or regulated entity on behalf of the customer, or `external` for wallets belonging to external exchanges or smart contracts." })), "wallet_attested_ownership_at": Schema.optionalKey(Schema.String.annotate({ "description": "Required when `wallet_type` is `self-custodied` or `hosted`. Must be a timestamp in the past indicating when wallet ownership was attested.", "format": "date-time" })), "legal_entity_identifier": Schema.optionalKey(Schema.String.annotate({ "description": "The Legal Entity Identifier (LEI) or equivalent (e.g. VAT number) of the beneficiary. Provide this when the beneficiary is a legal entity rather than an individual." })) }).annotate({ "description": "Travel Rule details for beneficiary crypto movement." })) }).annotate({ "description": "Travel Rule data for a crypto movement. Send this on create or update when the same counterparty should apply to every future use of a reusable resource, or send the same payload with `POST /travel_rule_data/{id}` when it belongs to one specific movement." })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "identifier": "CreateVirtualAccount" }) +export type UpdateVirtualAccount = { readonly "destination"?: { readonly "currency"?: "usdb" | "usdc" | "usdt" | "usdl_linea" | "pyusd" | "eurc", readonly "payment_rail"?: "arbitrum" | "avalanche_c_chain" | "base" | "celo" | "ethereum" | "linea" | "optimism" | "polygon" | "solana" | "stellar" | "tempo" | "tron" | "xdc", readonly "address"?: string, readonly "blockchain_memo"?: string, readonly "bridge_wallet_id"?: string } & { readonly [x: string]: Schema.Json }, readonly "developer_fee_percent"?: string, readonly "fee_config"?: { readonly "source"?: { readonly "fee_percent"?: string, readonly "fee_amount"?: string, readonly "minimum_fee"?: string, readonly "maximum_fee"?: string } | { readonly [x: string]: { readonly "fee_percent"?: string, readonly "fee_amount"?: string, readonly "minimum_fee"?: string, readonly "maximum_fee"?: string } } } } & { readonly [x: string]: Schema.Json } +export const UpdateVirtualAccount = Schema.StructWithRest(Schema.Struct({ "destination": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "currency": Schema.optionalKey(Schema.Literals(["usdb", "usdc", "usdt", "usdl_linea", "pyusd", "eurc"])), "payment_rail": Schema.optionalKey(Schema.Literals(["arbitrum", "avalanche_c_chain", "base", "celo", "ethereum", "linea", "optimism", "polygon", "solana", "stellar", "tempo", "tron", "xdc"])), "address": Schema.optionalKey(Schema.String.annotate({ "description": "The crypto wallet address that the customer wishes to ultimately receive funds at" })), "blockchain_memo": Schema.optionalKey(Schema.String.annotate({ "description": "The memo to include when sending funds on chain. Only allowed for blockchains that support memos such as Stellar" })), "bridge_wallet_id": Schema.optionalKey(Schema.String.annotate({ "description": "The Bridge Wallet to which Bridge will send the funds. The chain associated with the Bridge Wallet must match the payment rail." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "examples": [{ "currency": "usdc", "payment_rail": "polygon", "address": "0xdeadbeef", "blockchain_memo": "from_bridge" }] })), "developer_fee_percent": Schema.optionalKey(Schema.String.annotate({ "description": "The developer fee percent that will be applied to this Virtual Account. The value is a base 100 percentage, i.e. 10.2% is 10.2 in the API.", "examples": ["0.1"], "format": "number" })), "fee_config": Schema.optionalKey(Schema.Struct({ "source": Schema.optionalKey(Schema.Union([Schema.Struct({ "fee_percent": Schema.optionalKey(Schema.String.annotate({ "description": "Percentage fee (0-100, exclusive). Applied to the amount remaining after any flat fee deduction.", "examples": ["1.5"], "format": "number" })), "fee_amount": Schema.optionalKey(Schema.String.annotate({ "description": "Flat fee amount deducted before percentage calculation", "examples": ["10.00"], "format": "number" })), "minimum_fee": Schema.optionalKey(Schema.String.annotate({ "description": "Minimum total fee floor", "examples": ["1.00"], "format": "number" })), "maximum_fee": Schema.optionalKey(Schema.String.annotate({ "description": "Maximum total fee cap", "examples": ["1000.00"], "format": "number" })) }).annotate({ "description": "Fee parameters for a specific payment rail or default configuration" }), Schema.Record(Schema.String, Schema.Struct({ "fee_percent": Schema.optionalKey(Schema.String.annotate({ "description": "Percentage fee (0-100, exclusive). Applied to the amount remaining after any flat fee deduction.", "examples": ["1.5"], "format": "number" })), "fee_amount": Schema.optionalKey(Schema.String.annotate({ "description": "Flat fee amount deducted before percentage calculation", "examples": ["10.00"], "format": "number" })), "minimum_fee": Schema.optionalKey(Schema.String.annotate({ "description": "Minimum total fee floor", "examples": ["1.00"], "format": "number" })), "maximum_fee": Schema.optionalKey(Schema.String.annotate({ "description": "Maximum total fee cap", "examples": ["1000.00"], "format": "number" })) }).annotate({ "description": "Fee parameters for a specific payment rail or default configuration" }))]).annotate({ "description": "Source-side fee configuration. Supports direct fee params under `source`, an explicit `default` key, payment-rail keys such as `ach_push` and `wire`, or a mixed default-plus-override form.", "examples": [{ "fee_percent": "0.5", "minimum_fee": "1.00", "wire": { "fee_amount": "10.00", "fee_percent": "1.0" } }] })) }).annotate({ "description": "Developer fee configuration. Available by request only. Contact Bridge to enable this feature for your developer account. The `source` object supports direct fee parameters as a shorthand for a default fee, an explicit `default` key, payment-rail keys (e.g. `ach_push`, `wire`), or a mixed default-plus-override form." })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "identifier": "UpdateVirtualAccount" }) +export type VirtualAccountEvent = { readonly "id": string, readonly "type"?: "funds_scheduled" | "funds_received" | "payment_submitted" | "payment_processed" | "in_review" | "refund" | "refund_in_flight" | "refund_failed" | "microdeposit" | "account_update" | "deactivation" | "activation", readonly "customer_id"?: string, readonly "virtual_account_id"?: string, readonly "amount"?: string, readonly "currency"?: "usdb" | "usdc" | "usdt" | "usdl_linea" | "usd" | "pyusd", readonly "developer_fee_amount"?: string, readonly "exchange_fee_amount"?: string, readonly "subtotal_amount"?: string, readonly "gas_fee"?: string, readonly "deposit_id"?: string, readonly "destination_tx_hash"?: string, readonly "destination_payment_rail"?: string, readonly "source"?: { readonly "payment_rail": "ach_push" | "bre_b" | "faster_payments" | "fednow" | "pix" | "sepa" | "spei" | "wire", readonly "description"?: string, readonly "sender_name"?: string, readonly "sender_bank_routing_number"?: string, readonly "end_to_end_id"?: string, readonly "trace_number"?: string, readonly "recipient_name"?: string, readonly "bank_routing_number"?: string, readonly "bank_name"?: string, readonly "bank_code"?: string, readonly "bank_beneficiary_name"?: string, readonly "bank_beneficiary_address"?: string, readonly "originator_name"?: string, readonly "originator_address"?: string, readonly "wire_message"?: string, readonly "imad"?: string, readonly "charge_bearer"?: "our" | "sha" | "ben", readonly "bic"?: string, readonly "iban"?: string, readonly "iban_last_4"?: string, readonly "clabe"?: string, readonly "reference"?: string, readonly "tracking_number"?: string, readonly "payment_scheme"?: "sepa_credit" | "sepa_instant", readonly "uetr"?: string } & { readonly [x: string]: Schema.Json }, readonly "created_at"?: string, readonly "receipt"?: { readonly "initial_amount": string, readonly "developer_fee": string, readonly "exchange_fee": string, readonly "developer_exchange_fee"?: { readonly "amount"?: string, readonly "currency"?: string }, readonly "pre_conversion_subtotal_amount"?: string, readonly "mid_market_rate"?: string, readonly "converted_amount"?: string, readonly "subtotal_amount": string, readonly "remaining_prefunded_balance"?: string, readonly "gas_fee"?: string, readonly "final_amount"?: string, readonly "source_tx_hash"?: Schema.Json, readonly "destination_tx_hash"?: Schema.Json, readonly "exchange_rate"?: Schema.Json, readonly "url"?: string, readonly "bank_details"?: { readonly "sending_routing_number"?: string, readonly "ach_description"?: string, readonly "ach_trace_id"?: string, readonly "wire_message"?: string, readonly "imad"?: string, readonly "recipient_name"?: string, readonly "sending_bic"?: string, readonly "sepa_reference"?: string, readonly "uetr"?: string, readonly "receiving_account_last_four"?: string, readonly "receiving_bic"?: string } } & { readonly [x: string]: Schema.Json }, readonly "refund"?: { readonly "code": string, readonly "reason": string, readonly "refunded_at": string, readonly "risk_rejection_reason"?: string } & { readonly [x: string]: Schema.Json } } & { readonly [x: string]: Schema.Json } +export const VirtualAccountEvent = Schema.StructWithRest(Schema.Struct({ "id": Schema.String.annotate({ "description": "A UUID that uniquely identifies a resource", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" })), "type": Schema.optionalKey(Schema.Literals(["funds_scheduled", "funds_received", "payment_submitted", "payment_processed", "in_review", "refund", "refund_in_flight", "refund_failed", "microdeposit", "account_update", "deactivation", "activation"]).annotate({ "description": "The type of activity" })), "customer_id": Schema.optionalKey(Schema.String.annotate({ "description": "A UUID that uniquely identifies a resource" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" })).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1", "description": "The id of the Bridge customer that this Virtual Account event belongs to", "readOnly": true }))), "virtual_account_id": Schema.optionalKey(Schema.String.annotate({ "description": "A UUID that uniquely identifies a resource" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" })).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1", "description": "The id of the Virtual Account that this Virtual Account event belongs to", "readOnly": true }))), "amount": Schema.optionalKey(Schema.String.annotate({ "description": "Amount for that event, represented as a dollar denominated string. Examples include \"100.25\", \"0.1\", \"1.234567\" etc. For \"incoming\" events such as funds_received or under_review, this is the initial amount received. For \"outgoing\" events such as payment_submitted and payment_processed, this is the amount of funds sent to the destination. For non-transactional events such as account_update, this will be zero." })), "currency": Schema.optionalKey(Schema.Literals(["usdb", "usdc", "usdt", "usdl_linea", "usd", "pyusd"])), "developer_fee_amount": Schema.optionalKey(Schema.String.annotate({ "description": "Amount of the developer fee if any, represented as a dollar denominated string. This is the final amount taken out of what is ultimately received by your customer, not a percentage. Examples include \"100.25\", \"0.1\", \"1.234567\" etc." })), "exchange_fee_amount": Schema.optionalKey(Schema.String.annotate({ "description": "Amount of the exchange fee if any, represented as a dollar denominated string. Examples include \"100.25\", \"0.1\", \"1.234567\" etc." })), "subtotal_amount": Schema.optionalKey(Schema.String.annotate({ "description": "Amount of the subtotal, represented as a dollar denominated string. Examples include \"100.25\", \"0.1\", \"1.234567\" etc." })), "gas_fee": Schema.optionalKey(Schema.String.annotate({ "description": "Amount of the gas fee if any, represented as a dollar denominated string. Examples include \"100.25\", \"0.1\", \"1.234567\" etc." })), "deposit_id": Schema.optionalKey(Schema.String.annotate({ "description": "The id of the deposit related to this event. This id can be used to link multiple events to the same transaction. Omitted for some `refund` cases." })), "destination_tx_hash": Schema.optionalKey(Schema.String.annotate({ "description": "The hash of the on-chain transfer to the destination address" })), "destination_payment_rail": Schema.optionalKey(Schema.String.annotate({ "description": "The destination payment rail where the funds are deposited to" })), "source": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "payment_rail": Schema.Literals(["ach_push", "bre_b", "faster_payments", "fednow", "pix", "sepa", "spei", "wire"]), "description": Schema.optionalKey(Schema.String.annotate({ "description": "(ACH, SPEI, and FedNow only) The description of the deposit that the customer sent", "readOnly": true })), "sender_name": Schema.optionalKey(Schema.String.annotate({ "description": "(ACH, SEPA, SPEI, and FedNow only) The name of the business or individual who initiated the transaction", "readOnly": true })), "sender_bank_routing_number": Schema.optionalKey(Schema.String.annotate({ "description": "(ACH and FedNow only) The routing number of the entity that initiated this transaction", "readOnly": true })), "end_to_end_id": Schema.optionalKey(Schema.String.annotate({ "description": "The end-to-end ID of the FedNow transaction, assigned by the sending bank, and is not guaranteed to be unique across payments.", "readOnly": true })), "trace_number": Schema.optionalKey(Schema.String.annotate({ "description": "(ACH only) The unique, a 15-digit number associated with each ACH transaction that is used for tracking and reconciling transactions", "readOnly": true })), "recipient_name": Schema.optionalKey(Schema.String.annotate({ "description": "(ACH, SEPA, and Faster Payments only) The name of the recipient of the deposit", "readOnly": true })), "bank_routing_number": Schema.optionalKey(Schema.String.annotate({ "description": "(Wire only) The routing number of the bank that sent the wire to the Virtual Account", "readOnly": true })), "bank_name": Schema.optionalKey(Schema.String.annotate({ "description": "(Wire and SPEI only) The name of the bank that sent the deposit.", "readOnly": true })), "bank_code": Schema.optionalKey(Schema.String.annotate({ "description": "(SPEI only) The bank code of the sender's bank that initiated this SPEI transaction.", "readOnly": true })), "bank_beneficiary_name": Schema.optionalKey(Schema.String.annotate({ "description": "(Wire only) The beneficiary name of this wire", "readOnly": true })), "bank_beneficiary_address": Schema.optionalKey(Schema.String.annotate({ "description": "(Wire only) The beneficiary address of this wire", "readOnly": true })), "originator_name": Schema.optionalKey(Schema.String.annotate({ "description": "(Wire only) The originator name of this wire", "readOnly": true })), "originator_address": Schema.optionalKey(Schema.String.annotate({ "description": "(Wire only) The originator address of this wire", "readOnly": true })), "wire_message": Schema.optionalKey(Schema.String.annotate({ "description": "(Wire only) The memo for this wire", "readOnly": true })), "imad": Schema.optionalKey(Schema.String.annotate({ "description": "(Wire only) The IMAD of a wire transfer, if available", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(40).annotate({ "expected": "a value with a length of at most 40" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "charge_bearer": Schema.optionalKey(Schema.Literals(["our", "sha", "ben"]).annotate({ "description": "(Wire only) Which party bore the SWIFT wire's charges", "readOnly": true })), "bic": Schema.optionalKey(Schema.String.annotate({ "description": "(SEPA and Wire only) The BIC of the bank that initiated this transaction. For wires this is the originating bank's BIC, reported for international (SWIFT) wires, and can differ from the US correspondent bank in bank_name and bank_routing_number", "readOnly": true })), "iban": Schema.optionalKey(Schema.String.annotate({ "description": "(SEPA only) The full IBAN of the account that initiated this transaction", "readOnly": true })), "iban_last_4": Schema.optionalKey(Schema.String.annotate({ "description": "(SEPA only) The last 4 digits of the IBAN of the account that initiated this transaction", "readOnly": true })), "clabe": Schema.optionalKey(Schema.String.annotate({ "description": "(SPEI only) The CLABE (account number) of the account that initiated this transaction", "readOnly": true })), "reference": Schema.optionalKey(Schema.String.annotate({ "description": "(SEPA and SPEI only) The SEPA/SPEI (concepto de pago) reference field set by the initiator of this transaction", "readOnly": true }).check(Schema.isMinLength(6).annotate({ "expected": "a value with a length of at least 6" })).check(Schema.isMaxLength(140).annotate({ "expected": "a value with a length of at most 140" }))), "tracking_number": Schema.optionalKey(Schema.String.annotate({ "description": "(SPEI only) The clave de rastreo or tracking number of the SPEI transaction", "readOnly": true })), "payment_scheme": Schema.optionalKey(Schema.Literals(["sepa_credit", "sepa_instant"]).annotate({ "description": "(SEPA only) The payment scheme used for this transaction, such as SEPA Credit Transfer or SEPA Instant" })), "uetr": Schema.optionalKey(Schema.String.annotate({ "description": "Deprecated: use tracking_number instead. The unique end-to-end transaction reference, for tracing purposes.", "readOnly": true })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))])), "created_at": Schema.optionalKey(Schema.String.annotate({ "description": "Time of creation of the event", "readOnly": true, "format": "date-time" })), "receipt": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "initial_amount": Schema.String.annotate({ "description": "The initial amount of the transfer from the source, represented as a decimal string. Examples include \"100.25\", \"0.1\", \"1.234567\", \"1.01\" etc." }), "developer_fee": Schema.String.annotate({ "description": "The fee, expressed as a decimal string, represents the amount of the transfer reserved for your own account. This fee is the final amount deducted from what your customer ultimately receives, rather than a percentage." }), "exchange_fee": Schema.String.annotate({ "description": "The fee, expressed as a decimal string, represents the amount Bridge charges for facilitating the transfer. This is the final amount deducted from what your customer ultimately receives, rather than a percentage. It can be deducted from the initial amount/currency or the converted amount/currency. " }), "developer_exchange_fee": Schema.optionalKey(Schema.Struct({ "amount": Schema.optionalKey(Schema.String.annotate({ "description": "Amount of the fee" })), "currency": Schema.optionalKey(Schema.String.annotate({ "description": "Currency of the fee" })) }).annotate({ "description": "For FixedOutput trades, the amount, expressed as a decimal string, of the traded money that was not necessary to deliver the fixed output, returned to the developer." })), "pre_conversion_subtotal_amount": Schema.optionalKey(Schema.String.annotate({ "description": "On transfers with a variable trade, the amount of money, expressed as a decimal string, that is passed into the trade itself. Equal to the initial amount less any fees applied on the input side of the trade" })), "mid_market_rate": Schema.optionalKey(Schema.String.annotate({ "description": "If the transfer includes a market rate trade, this is the mid-market rate used to calculate the output of the trade. It is expressed as a decimal string." })), "converted_amount": Schema.optionalKey(Schema.String.annotate({ "description": "If the transfer includes a variable trade, the amount of money, expressed as a decimal string, received after the trade, before any final fees are deducted." })), "subtotal_amount": Schema.String.annotate({ "description": "The amount, expressed as a decimal string, remaining from the converted amount after any remaining non-gas fees have been deducted. " }), "remaining_prefunded_balance": Schema.optionalKey(Schema.String.annotate({ "description": "For Prefunded Accounts, this value will represent the remaining account balance after the transfer." })), "gas_fee": Schema.optionalKey(Schema.String.annotate({ "description": "The fee, expressed as a decimal string. It's deducted from the withdrawn amount to pay for gas. Only nonzero to crypto withdrawals that cost gas (e.g. USDT), and only known when the transaction is confirmed on-chain. Will be missing if not yet known.\n\nIt's denominated in the fiat currency to which the destination currency is pegged." })), "final_amount": Schema.optionalKey(Schema.String.annotate({ "description": "The final amount of the transfer, expressed as a decimal string, equal to the subtotal_amount minus any gas fees. If the gas fee is not known, this field will be missing. Examples include \"100.25\", \"0.1\", \"1.234567\", \"1.01\" etc.\n\nIt's denominated in the destination currency if that is a fiat currency or the fiat currency to which the destination currency is pegged." })), "source_tx_hash": Schema.optionalKey(Schema.Json.annotate({ "expected": "JSON value", "description": "The hash of the on-chain deposit to the source address, where applicable" })), "destination_tx_hash": Schema.optionalKey(Schema.Json.annotate({ "expected": "JSON value", "description": "The hash of the on-chain transfer to the destination address, where applicable" })), "exchange_rate": Schema.optionalKey(Schema.Json.annotate({ "expected": "JSON value", "description": "The effective exchange rate can be calculated by dividing the converted amount by the amount available for conversion after deducting the developer fee. This rate includes a currency conversion spread and is subject to a rounding precision loss during the calculation. Currently it's populated for SEPA onramp/offramp transfers only." })), "url": Schema.optionalKey(Schema.String.annotate({ "description": "The URL of a user-facing copy of the receipt." })), "bank_details": Schema.optionalKey(Schema.Struct({ "sending_routing_number": Schema.optionalKey(Schema.String.annotate({ "description": "Routing number of the bank Bridge sent the payment from." })), "ach_description": Schema.optionalKey(Schema.String.annotate({ "description": "Statement descriptor on the outgoing ACH credit." })), "ach_trace_id": Schema.optionalKey(Schema.String.annotate({ "description": "ACH trace number, populated after submission to the Fed." })), "wire_message": Schema.optionalKey(Schema.String.annotate({ "description": "Message sent with the outgoing wire (beneficiary, FI-to-FI, or receiving-FI message)." })), "imad": Schema.optionalKey(Schema.String.annotate({ "description": "IMAD (Input Message Accountability Data) of the outgoing wire, populated after posting." })), "recipient_name": Schema.optionalKey(Schema.String.annotate({ "description": "Name on the receiving external account." })), "sending_bic": Schema.optionalKey(Schema.String.annotate({ "description": "BIC of the bank Bridge sent the SEPA payment from." })), "sepa_reference": Schema.optionalKey(Schema.String.annotate({ "description": "SEPA payment reference." })), "uetr": Schema.optionalKey(Schema.String.annotate({ "description": "Unique End-to-end Transaction Reference (UETR) of the SEPA payment." })), "receiving_account_last_four": Schema.optionalKey(Schema.String.annotate({ "description": "Last four digits of the receiving IBAN." })), "receiving_bic": Schema.optionalKey(Schema.String.annotate({ "description": "BIC of the receiving bank." })) }).annotate({ "description": "Bank-lookup details for fiat offramp receipts, to help the recipient's bank locate the payment. Present for enabled developers once the offramp's bank leg exists; individual fields may be null until they become available (e.g. the ACH trace ID before submission to the Fed)." })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Receipt information of a virtual account event. Available for drain and payment_processed events.", "readOnly": true })), "refund": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "code": Schema.String.annotate({ "description": "The code of the refund" }), "reason": Schema.String.annotate({ "description": "The reason of the refund" }), "refunded_at": Schema.String.annotate({ "description": "The time of the refund" }), "risk_rejection_reason": Schema.optionalKey(Schema.String.annotate({ "description": "If the return is due to a risk rejection, this field will be populated with the reason for the risk rejection." })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Refund information of a virtual account event. Available for refund events.", "readOnly": true })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "identifier": "VirtualAccountEvent" }) +export type StaticMemoResponse = { readonly "id"?: string, readonly "developer_fee_percent"?: string, readonly "source_deposit_instructions"?: { readonly "currency"?: "usd", readonly "payment_rails"?: ReadonlyArray<"ach" | "wire" | "ach_push" | "ach_same_day" | "arbitrum" | "avalanche_c_chain" | "base" | "bre_b" | "co_bank_transfer" | "celo" | "ethereum" | "optimism" | "pix" | "polygon" | "solana" | "spei" | "stellar" | "tempo">, readonly "deposit_message"?: string, readonly "bank_name"?: string, readonly "bank_address"?: string, readonly "bank_routing_number"?: string, readonly "bank_account_number"?: string, readonly "bank_beneficiary_name"?: string, readonly "bank_beneficiary_address"?: string } & { readonly [x: string]: Schema.Json }, readonly "destination"?: { readonly "currency": "usdb" | "usdc" | "usdt" | "usdl_linea" | "pyusd" | "eurc", readonly "payment_rail": "arbitrum" | "avalanche_c_chain" | "base" | "celo" | "ethereum" | "linea" | "optimism" | "polygon" | "solana" | "stellar" | "tempo" | "tron" | "xdc", readonly "address": string, readonly "bridge_wallet_id"?: string, readonly "blockchain_memo"?: string } & { readonly [x: string]: Schema.Json }, readonly "created_at"?: string } & { readonly [x: string]: Schema.Json } +export const StaticMemoResponse = Schema.StructWithRest(Schema.Struct({ "id": Schema.optionalKey(Schema.String.annotate({ "description": "A UUID that uniquely identifies a resource", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "developer_fee_percent": Schema.optionalKey(Schema.String.annotate({ "description": "The developer fee percent that will be applied to this Virtual Account. The value is a base 100 percentage, i.e. 10.2% is 10.2 in the API.", "examples": ["0.1"], "format": "number" })), "source_deposit_instructions": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "currency": Schema.optionalKey(Schema.Literal("usd")), "payment_rails": Schema.optionalKey(Schema.Array(Schema.Literals(["ach", "wire", "ach_push", "ach_same_day", "arbitrum", "avalanche_c_chain", "base", "bre_b", "co_bank_transfer", "celo", "ethereum", "optimism", "pix", "polygon", "solana", "spei", "stellar", "tempo"])).annotate({ "description": "All supported payment rails for deposits" })), "deposit_message": Schema.optionalKey(Schema.String.annotate({ "description": "The message that the customer MUST include in their wire memo/message or ACH description." })), "bank_name": Schema.optionalKey(Schema.String.annotate({ "description": "The name of the bank that the customer should send the deposit to" })), "bank_address": Schema.optionalKey(Schema.String.annotate({ "description": "The address of the bank that the customer should send the deposit to" })), "bank_routing_number": Schema.optionalKey(Schema.String.annotate({ "description": "The routing number of the bank that the customer should send the deposit to" })), "bank_account_number": Schema.optionalKey(Schema.String.annotate({ "description": "The account number of the bank that the customer should send the deposit to" })), "bank_beneficiary_name": Schema.optionalKey(Schema.String.annotate({ "description": "The name of the beneficiary of the bank account that the customer should send the deposit to" })), "bank_beneficiary_address": Schema.optionalKey(Schema.String.annotate({ "description": "The address of the beneficiary of the bank account that the customer should send the deposit to" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "examples": [{ "currency": "usd", "payment_rails": ["ach_push", "wire"], "deposit_message": "EXAMPLE_MEMO_MESSAGE", "bank_name": "Lead Bank", "bank_address": "1801 Main St., Kansas City, MO 64108", "bank_beneficiary_name": "Bridge Ventures Inc", "bank_beneficiary_address": "21750 Hardy Oak Blvd, Ste 104 PMB 77950, San Antonio, Texas, 78258-4946", "bank_account_number": "123456789", "bank_routing_number": "87654321" }], "readOnly": true })), "destination": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "currency": Schema.Literals(["usdb", "usdc", "usdt", "usdl_linea", "pyusd", "eurc"]), "payment_rail": Schema.Literals(["arbitrum", "avalanche_c_chain", "base", "celo", "ethereum", "linea", "optimism", "polygon", "solana", "stellar", "tempo", "tron", "xdc"]), "address": Schema.String.annotate({ "description": "The crypto wallet address that the customer wishes to ultimately receive funds at" }), "bridge_wallet_id": Schema.optionalKey(Schema.String.annotate({ "description": "The Bridge Wallet to which Bridge will send the funds. payment_rail must match the chain of the Bridge Wallet." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "blockchain_memo": Schema.optionalKey(Schema.String.annotate({ "description": "The memo to include when sending funds on chain. Only allowed for blockchains that support memos such as Stellar" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "examples": [{ "currency": "usdc", "payment_rail": "polygon", "address": "0xdeadbeef" }] })), "created_at": Schema.optionalKey(Schema.String.annotate({ "description": "Time of creation of the static memo", "readOnly": true, "format": "date-time" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "identifier": "StaticMemoResponse" }) +export type CreateStaticMemo = { readonly "developer_fee_percent"?: string, readonly "source": { readonly "currency": "usd", readonly "payment_rail"?: "ach" | "wire" | "ach_push" | "ach_same_day" | "arbitrum" | "avalanche_c_chain" | "base" | "bre_b" | "co_bank_transfer" | "celo" | "ethereum" | "optimism" | "pix" | "polygon" | "solana" | "spei" | "stellar" | "tempo" } & { readonly [x: string]: Schema.Json }, readonly "destination": { readonly "currency": "usdb" | "usdc" | "usdt" | "usdl_linea" | "pyusd" | "eurc", readonly "payment_rail": "arbitrum" | "avalanche_c_chain" | "base" | "celo" | "ethereum" | "linea" | "optimism" | "polygon" | "solana" | "stellar" | "tempo" | "tron" | "xdc", readonly "address": string, readonly "bridge_wallet_id"?: string, readonly "blockchain_memo"?: string } & { readonly [x: string]: Schema.Json } } & { readonly [x: string]: Schema.Json } +export const CreateStaticMemo = Schema.StructWithRest(Schema.Struct({ "developer_fee_percent": Schema.optionalKey(Schema.String.annotate({ "description": "The developer fee percent that will be applied to this Virtual Account. The value is a base 100 percentage, i.e. 10.2% is 10.2 in the API.", "examples": ["0.1"], "format": "number" })), "source": Schema.StructWithRest(Schema.Struct({ "currency": Schema.Literal("usd"), "payment_rail": Schema.optionalKey(Schema.Literals(["ach", "wire", "ach_push", "ach_same_day", "arbitrum", "avalanche_c_chain", "base", "bre_b", "co_bank_transfer", "celo", "ethereum", "optimism", "pix", "polygon", "solana", "spei", "stellar", "tempo"]).annotate({ "description": "Static memos support both wire and ACH push regardless of this value." })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "examples": [{ "currency": "usd", "payment_rail": "wire" }] }), "destination": Schema.StructWithRest(Schema.Struct({ "currency": Schema.Literals(["usdb", "usdc", "usdt", "usdl_linea", "pyusd", "eurc"]), "payment_rail": Schema.Literals(["arbitrum", "avalanche_c_chain", "base", "celo", "ethereum", "linea", "optimism", "polygon", "solana", "stellar", "tempo", "tron", "xdc"]), "address": Schema.String.annotate({ "description": "The crypto wallet address that the customer wishes to ultimately receive funds at" }), "bridge_wallet_id": Schema.optionalKey(Schema.String.annotate({ "description": "The Bridge Wallet to which Bridge will send the funds. payment_rail must match the chain of the Bridge Wallet." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "blockchain_memo": Schema.optionalKey(Schema.String.annotate({ "description": "The memo to include when sending funds on chain. Only allowed for blockchains that support memos such as Stellar" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "examples": [{ "currency": "usdc", "payment_rail": "polygon", "address": "0xdeadbeef" }] }) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "identifier": "CreateStaticMemo" }) +export type UpdateStaticMemo = { readonly "destination"?: { readonly "currency"?: "usdb" | "usdc" | "usdt" | "usdl_linea" | "pyusd" | "eurc", readonly "payment_rail"?: "arbitrum" | "avalanche_c_chain" | "base" | "celo" | "ethereum" | "linea" | "optimism" | "polygon" | "solana" | "stellar" | "tempo" | "tron" | "xdc", readonly "address"?: string } & { readonly [x: string]: Schema.Json }, readonly "developer_fee_percent"?: string } & { readonly [x: string]: Schema.Json } +export const UpdateStaticMemo = Schema.StructWithRest(Schema.Struct({ "destination": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "currency": Schema.optionalKey(Schema.Literals(["usdb", "usdc", "usdt", "usdl_linea", "pyusd", "eurc"])), "payment_rail": Schema.optionalKey(Schema.Literals(["arbitrum", "avalanche_c_chain", "base", "celo", "ethereum", "linea", "optimism", "polygon", "solana", "stellar", "tempo", "tron", "xdc"])), "address": Schema.optionalKey(Schema.String.annotate({ "description": "The crypto wallet address that the customer wishes to ultimately receive funds at" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "examples": [{ "currency": "usdc", "payment_rail": "polygon", "address": "0xdeadbeef" }] })), "developer_fee_percent": Schema.optionalKey(Schema.String.annotate({ "description": "The developer fee percent that will be applied to this Virtual Account. The value is a base 100 percentage, i.e. 10.2% is 10.2 in the API.", "examples": ["0.1"], "format": "number" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "identifier": "UpdateStaticMemo" }) +export type CardPinUpdateResponse = { readonly "url": string } +export const CardPinUpdateResponse = Schema.Struct({ "url": Schema.String.annotate({ "description": "Single-use, time-limited URL that can be used to securely update the card PIN in an iframe", "examples": ["https://secure.example.com/update-pin?token=xyz789"], "format": "uri" }) }).annotate({ "description": "Response containing a secure URL to update a card's PIN", "identifier": "CardPinUpdateResponse" }) +export type PostCardAccountEphemeralKeyInput = { readonly "client_nonce": string } & { readonly [x: string]: Schema.Json } +export const PostCardAccountEphemeralKeyInput = Schema.StructWithRest(Schema.Struct({ "client_nonce": Schema.String.annotate({ "description": "The client-side nonce that will be associated with the ephemeral key. This must be generated from the client secret and timestamp as per the [integration guide](https://apidocs.bridge.xyz/docs/safely-reveal-card-details-to-customers) in order to be usable for revealing card details." }) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "The request to create an ephemeral key to reveal card details", "identifier": "PostCardAccountEphemeralKeyInput" }) +export type CardAccountEphemeralKeyResponse = { readonly "ephemeral_key": string } & { readonly [x: string]: Schema.Json } +export const CardAccountEphemeralKeyResponse = Schema.StructWithRest(Schema.Struct({ "ephemeral_key": Schema.String.annotate({ "description": "The ephemeral key to reveal card details. This key is only valid for 5 minutes. Your backend should return this key to the frontend instead of directly using it, to avoid putting your backend in PCI compliance scope. Please see the integration guide on [safely revealing card details](/platform/cards/additional/safely-reveal-card-details) for more information." }) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "A response containing the ephemeral key to reveal card details", "identifier": "CardAccountEphemeralKeyResponse" }) +export type StaticMemoEvent = { readonly "id": string, readonly "type"?: "funds_received" | "payment_submitted" | "payment_processed" | "in_review" | "refunded" | "refund_in_flight" | "refund_failed" | "account_update", readonly "customer_id"?: string, readonly "static_memo_id"?: string, readonly "amount"?: string, readonly "currency"?: "usdb" | "usdc" | "usdt" | "usdl_linea" | "usd" | "pyusd", readonly "developer_fee_amount"?: string, readonly "exchange_fee_amount"?: string, readonly "subtotal_amount"?: string, readonly "gas_fee"?: string, readonly "deposit_id"?: string, readonly "destination_tx_hash"?: string, readonly "destination_payment_rail"?: string, readonly "source_deposit_instructions"?: { readonly "deposit_message": string } & { readonly [x: string]: Schema.Json }, readonly "source"?: { readonly "payment_rail": "ach" | "wire" | "ach_push" | "ach_same_day" | "arbitrum" | "avalanche_c_chain" | "base" | "bre_b" | "co_bank_transfer" | "celo" | "ethereum" | "optimism" | "pix" | "polygon" | "solana" | "spei" | "stellar" | "tempo", readonly "description"?: string, readonly "sender_name"?: string, readonly "sender_bank_routing_number"?: string, readonly "trace_number"?: string, readonly "bank_routing_number"?: string, readonly "bank_name"?: string, readonly "bank_beneficiary_name"?: string, readonly "bank_beneficiary_address"?: string, readonly "originator_name"?: string, readonly "originator_address"?: string, readonly "wire_message"?: string, readonly "imad"?: string, readonly "omad"?: string } & { readonly [x: string]: Schema.Json }, readonly "created_at"?: string } & { readonly [x: string]: Schema.Json } +export const StaticMemoEvent = Schema.StructWithRest(Schema.Struct({ "id": Schema.String.annotate({ "description": "A UUID that uniquely identifies a resource", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" })), "type": Schema.optionalKey(Schema.Literals(["funds_received", "payment_submitted", "payment_processed", "in_review", "refunded", "refund_in_flight", "refund_failed", "account_update"]).annotate({ "description": "The type of activity" })), "customer_id": Schema.optionalKey(Schema.String.annotate({ "description": "A UUID that uniquely identifies a resource" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" })).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1", "description": "The id of the Bridge customer that this static memo event belongs to", "readOnly": true }))), "static_memo_id": Schema.optionalKey(Schema.String.annotate({ "description": "A UUID that uniquely identifies a resource" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" })).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1", "description": "The id of the Static Memo that this event belongs to", "readOnly": true }))), "amount": Schema.optionalKey(Schema.String.annotate({ "description": "Amount for that event, represented as a dollar denominated string. Examples include \"100.25\", \"0.1\", \"1.234567\" etc. For \"incoming\" events such as funds_received or under_review, this is the initial amount received. For \"outgoing\" events such as payment_submitted and payment_processed, this is the amount of funds sent to the destination. For non-transactional events such as account_update, this will be zero." })), "currency": Schema.optionalKey(Schema.Literals(["usdb", "usdc", "usdt", "usdl_linea", "usd", "pyusd"])), "developer_fee_amount": Schema.optionalKey(Schema.String.annotate({ "description": "Amount of the developer fee if any, represented as a dollar denominated string. This is the final amount taken out of what is ultimately received by your customer, not a percentage. Examples include \"100.25\", \"0.1\", \"1.234567\" etc." })), "exchange_fee_amount": Schema.optionalKey(Schema.String.annotate({ "description": "Amount of the exchange fee if any, represented as a dollar denominated string. Examples include \"100.25\", \"0.1\", \"1.234567\" etc." })), "subtotal_amount": Schema.optionalKey(Schema.String.annotate({ "description": "Amount of the subtotal, represented as a dollar denominated string. Examples include \"100.25\", \"0.1\", \"1.234567\" etc." })), "gas_fee": Schema.optionalKey(Schema.String.annotate({ "description": "Amount of the gas fee if any, represented as a dollar denominated string. Examples include \"100.25\", \"0.1\", \"1.234567\" etc." })), "deposit_id": Schema.optionalKey(Schema.String.annotate({ "description": "The id of the deposit related to this event. This id can be used to link multiple events to the same transaction" })), "destination_tx_hash": Schema.optionalKey(Schema.String.annotate({ "description": "The hash of the on-chain transfer to the destination address" })), "destination_payment_rail": Schema.optionalKey(Schema.String.annotate({ "description": "The destination payment rail where the funds are deposited to" })), "source_deposit_instructions": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "deposit_message": Schema.String.annotate({ "description": "The message that the customer MUST include in their wire memo/message or ach push description" }) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))])), "source": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "payment_rail": Schema.Literals(["ach", "wire", "ach_push", "ach_same_day", "arbitrum", "avalanche_c_chain", "base", "bre_b", "co_bank_transfer", "celo", "ethereum", "optimism", "pix", "polygon", "solana", "spei", "stellar", "tempo"]), "description": Schema.optionalKey(Schema.String.annotate({ "description": "(ACH only) The description of the deposit that the customer sent" })), "sender_name": Schema.optionalKey(Schema.String.annotate({ "description": "(ACH only) The name of the business or individual who initiated the transaction", "readOnly": true })), "sender_bank_routing_number": Schema.optionalKey(Schema.String.annotate({ "description": "(ACH only) The routing number of the entity that initiated this ACH transaction", "readOnly": true })), "trace_number": Schema.optionalKey(Schema.String.annotate({ "description": "(ACH only) The unique, a 15-digit number associated with each ACH transaction that is used for tracking and reconciling transactions", "readOnly": true })), "bank_routing_number": Schema.optionalKey(Schema.String.annotate({ "description": "(Wire only) The routing number of the bank that the customer sent the deposit to", "readOnly": true })), "bank_name": Schema.optionalKey(Schema.String.annotate({ "description": "(Wire only) The name of the bank that the customer sent the deposit to", "readOnly": true })), "bank_beneficiary_name": Schema.optionalKey(Schema.String.annotate({ "description": "(Wire only) The beneficiary name of this deposit", "readOnly": true })), "bank_beneficiary_address": Schema.optionalKey(Schema.String.annotate({ "description": "(Wire only) The beneficiary address of this deposit", "readOnly": true })), "originator_name": Schema.optionalKey(Schema.String.annotate({ "description": "(Wire only) The originator name of this deposit", "readOnly": true })), "originator_address": Schema.optionalKey(Schema.String.annotate({ "description": "(Wire only) The originator address of this deposit", "readOnly": true })), "wire_message": Schema.optionalKey(Schema.String.annotate({ "description": "(Wire only) The memo for this wire", "readOnly": true })), "imad": Schema.optionalKey(Schema.String.annotate({ "description": "(Wire only) The IMAD of a wire transfer, if available" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(40).annotate({ "expected": "a value with a length of at most 40" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "omad": Schema.optionalKey(Schema.String.annotate({ "description": "(Wire only) The OMAD of a wire transfer, if available" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(40).annotate({ "expected": "a value with a length of at most 40" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))])), "created_at": Schema.optionalKey(Schema.String.annotate({ "description": "Time of creation of the event", "readOnly": true, "format": "date-time" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "identifier": "StaticMemoEvent" }) +export type CreateBatchSettlementSchedule = { readonly "destination": { readonly "currency": "brl" | "cop" | "eur" | "eurc" | "gbp" | "mxn" | "pyusd" | "usd" | "usdb" | "usdc" | "usdt" | "usdl_linea", readonly "payment_rail": "ach" | "wire" | "ach_push" | "ach_same_day" | "fednow" | "arbitrum" | "avalanche_c_chain" | "base" | "bre_b" | "co_bank_transfer" | "celo" | "ethereum" | "fiat_deposit_return" | "linea" | "optimism" | "polygon" | "sepa" | "solana" | "spei" | "stellar" | "swift" | "tempo" | "tron" | "xdc", readonly "external_account_id"?: string, readonly "bridge_wallet_id"?: string, readonly "omad"?: string, readonly "imad"?: string, readonly "trace_number"?: string, readonly "end_to_end_id"?: string, readonly "wire_message"?: string, readonly "sepa_reference"?: string, readonly "swift_reference"?: string, readonly "spei_reference"?: string, readonly "reference"?: string | string, readonly "charge_bearer"?: "our" | "sha" | "ben", readonly "ach_reference"?: string, readonly "uetr"?: string, readonly "blockchain_memo"?: string, readonly "deposit_id"?: string, readonly "tracking_number"?: string, readonly "transaction_id"?: string, readonly "sending_institution_name"?: string } & { readonly [x: string]: Schema.Json } } & { readonly [x: string]: Schema.Json } +export const CreateBatchSettlementSchedule = Schema.StructWithRest(Schema.Struct({ "destination": Schema.StructWithRest(Schema.Struct({ "currency": Schema.Literals(["brl", "cop", "eur", "eurc", "gbp", "mxn", "pyusd", "usd", "usdb", "usdc", "usdt", "usdl_linea"]).annotate({ "description": "When `eur` is specified as the destination currency, the destination rail must be `sepa`." }), "payment_rail": Schema.Literals(["ach", "wire", "ach_push", "ach_same_day", "fednow", "arbitrum", "avalanche_c_chain", "base", "bre_b", "co_bank_transfer", "celo", "ethereum", "fiat_deposit_return", "linea", "optimism", "polygon", "sepa", "solana", "spei", "stellar", "swift", "tempo", "tron", "xdc"]).annotate({ "description": "When `sepa` is specified as the destination payment rail, the destination currency must be `eur`; when `swift` is specified as the destination payment rail, the destination currency must be `usd`." }), "external_account_id": Schema.optionalKey(Schema.String.annotate({ "description": "External bank account Bridge should send the funds to. The currency associated with the External Account must match the destination currency." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "bridge_wallet_id": Schema.optionalKey(Schema.String.annotate({ "description": "The Bridge Wallet to which Bridge will send the funds. The chain associated with the Bridge Wallet must match the destination payment rail." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "omad": Schema.optionalKey(Schema.String.annotate({ "description": "(Wire only) The OMAD of a wire transfer, if available", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(40).annotate({ "expected": "a value with a length of at most 40" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "imad": Schema.optionalKey(Schema.String.annotate({ "description": "(Wire only) The IMAD of a wire transfer, if available", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(40).annotate({ "expected": "a value with a length of at most 40" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "trace_number": Schema.optionalKey(Schema.String.annotate({ "description": "The trace number of an ACH transfer", "readOnly": true }).check(Schema.isMinLength(15).annotate({ "expected": "a value with a length of at least 15" })).check(Schema.isMaxLength(15).annotate({ "expected": "a value with a length of at most 15" })).check(Schema.isPattern(new RegExp("[0-9]")).annotate({ "expected": "a string matching the RegExp [0-9]" }))), "end_to_end_id": Schema.optionalKey(Schema.String.annotate({ "description": "The end-to-end ID of the FedNow transaction, assigned by the sending bank, and is not guaranteed to be unique across payments.", "readOnly": true })), "wire_message": Schema.optionalKey(Schema.String.annotate({ "description": "A message to be sent with a wire transfer. It can have up to 140 characters. This message will be validated against 4 lines, each with a max length of 35 characters according to the Fedwire standard." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" }))), "sepa_reference": Schema.optionalKey(Schema.String.annotate({ "description": "A reference message to be sent with a SEPA transaction. We recommend you set a unique value to help you and your customers track payments end to end. It must be from 6 to 140 characters. The allowed characters are `a-z`, `A-Z`, `0-9`, spaces, ampersand (`&`), hyphen (`-`), full stop (`.`), and solidus (`/`). If not populated, the default value is \"Payment via Bridge {unique_token}\"." }).check(Schema.isMinLength(6).annotate({ "expected": "a value with a length of at least 6" })).check(Schema.isMaxLength(140).annotate({ "expected": "a value with a length of at most 140" }))), "swift_reference": Schema.optionalKey(Schema.String.annotate({ "description": "A payment reference message or remittance information to be included in a SWIFT transaction. It can have at most 4 lines (separated by \"\\n\"), each line with a max length of 35 chars. The allowed characters are `a-z`, `A-Z`, `0-9`, special characters (`/` `-` `?` `:` `(` `)` `.` `,` `'` `+`), and space" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(140).annotate({ "expected": "a value with a length of at most 140" }))), "spei_reference": Schema.optionalKey(Schema.String.annotate({ "description": "A payment reference message or remittance information to be included in a SPEI transaction. The allowed characters are alphanumeric `a-z`, `A-Z`, `0-9`, and space" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(40).annotate({ "expected": "a value with a length of at most 40" }))), "reference": Schema.optionalKey(Schema.Union([Schema.String.annotate({ "title": "Faster Payments" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(18).annotate({ "expected": "a value with a length of at most 18" })), Schema.String.annotate({ "title": "Pix" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(100).annotate({ "expected": "a value with a length of at most 100" }))], { mode: "oneOf" }).annotate({ "description": "A payment reference message for newer payment rails (e.g. Pix, Faster Payments, and FedNow).\n" })), "charge_bearer": Schema.optionalKey(Schema.Literals(["our", "sha", "ben"]).annotate({ "description": "Which party bears the charges for the SWIFT transaction. Defaults to `sha` when not specified. Accepted on both request and response." })), "ach_reference": Schema.optionalKey(Schema.String.annotate({ "description": "A reference message to be sent with an ACH transaction. It can be at most 10 characters, A-Z, a-z, 0-9, and spaces." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(10).annotate({ "expected": "a value with a length of at most 10" }))), "uetr": Schema.optionalKey(Schema.String.annotate({ "description": "Deprecated: use tracking_number instead. The unique end-to-end transaction reference, for tracing purposes.", "readOnly": true })), "blockchain_memo": Schema.optionalKey(Schema.String.annotate({ "description": "The memo to include when sending funds on chain. Only allowed for blockchains that support memos such as Stellar" })), "deposit_id": Schema.optionalKey(Schema.String.annotate({ "description": "A UUID that uniquely identifies a deposit" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "tracking_number": Schema.optionalKey(Schema.String.annotate({ "description": "The primary tracking identifier for this fiat transaction. Format varies by payment rail (e.g., UETR for SEPA/FPS, clave de rastreo for SPEI, end-to-end ID for PIX).", "readOnly": true })), "transaction_id": Schema.optionalKey(Schema.String.annotate({ "description": "Deprecated: use tracking_number instead. The unique transaction identifier for this payment.", "readOnly": true })), "sending_institution_name": Schema.optionalKey(Schema.String.annotate({ "description": "The name of the institution sending the funds", "readOnly": true })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "The destination that Bridge will use to settle funds." }) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "identifier": "CreateBatchSettlementSchedule" }) +export type DeveloperFees = { readonly "default_liquidation_address_fee_percent": string } & { readonly [x: string]: Schema.Json } +export const DeveloperFees = Schema.StructWithRest(Schema.Struct({ "default_liquidation_address_fee_percent": Schema.String.annotate({ "description": "The default fee percent that will be applied to all your Liquidation Addresses. The value is a base 100 percentage, i.e. 10.2% is \"10.2\" in the API.", "examples": ["0.5"], "format": "float" }) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "identifier": "DeveloperFees" }) +export type FeeExternalAccount = { readonly "id": string, readonly "created_at": string, readonly "updated_at": string, readonly "account_owner_name": string, readonly "currency": "usd", readonly "account_type": "us", readonly "active": boolean, readonly "customer_id"?: string, readonly "bank_name"?: string, readonly "account_owner_type"?: "individual" | "business", readonly "first_name"?: string, readonly "last_name"?: string, readonly "business_name"?: string, readonly "address"?: { readonly "street_line_1": string, readonly "street_line_2"?: string, readonly "city": string, readonly "state"?: string, readonly "postal_code"?: string, readonly "country": string } & { readonly [x: string]: Schema.Json }, readonly "account_owner_country"?: string, readonly "deactivation_reason"?: "plaid_item_error" | "deactivated_due_to_bounceback" | "deleted_by_developer" | "requested_by_developer" | "invalid_account_number" | "invalid_bank_validation" | "rejected_by_bank_provider", readonly "deactivation_details"?: string, readonly "account": { readonly "account_number"?: string, readonly "routing_number": string, readonly "last_4": string, readonly "checking_or_savings"?: "checking" | "savings" } & { readonly [x: string]: Schema.Json }, readonly "beneficiary_address_valid"?: boolean, readonly "last_4"?: string, readonly "account_number"?: string, readonly "routing_number"?: string } & { readonly [x: string]: Schema.Json } +export const FeeExternalAccount = Schema.StructWithRest(Schema.Struct({ "id": Schema.String.annotate({ "description": "A UUID that uniquely identifies a resource", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" })), "created_at": Schema.String.annotate({ "description": "Time of creation of the External Account", "readOnly": true, "format": "date-time" }), "updated_at": Schema.String.annotate({ "description": "Time of last update of the External Account", "readOnly": true, "format": "date-time" }), "account_owner_name": Schema.String.annotate({ "description": "Owner of the account Bank Account (e.g. \"John Doe\"). For ach, wire, and iban accounts, this field must be at least 3 characters, at most 35 characters, and follow the regex pattern for the given account type:\n- ach: `^(?!\\s*$)[\\x20-\\x7E]*$`\n- wire: ```^[ \\w!\"#$%&'()+,\\-./:;<=>?@\\\\_`~]*$```\n- iban: `^(?![:\\- ]*$)[a-zA-Z0-9\\/\\-?:().,'+ _]+$`\n" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" })), "currency": Schema.Literal("usd").annotate({ "description": "Currency associated with the bank account. Must be `usd` for US accounts." }), "account_type": Schema.Literal("us").annotate({ "description": "Type of the bank account." }), "active": Schema.Boolean.annotate({ "description": "Whether or not this External Account is active", "readOnly": true }), "customer_id": Schema.optionalKey(Schema.String.annotate({ "description": "The id of the Bridge customer that this External Account belongs to", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "bank_name": Schema.optionalKey(Schema.String.annotate({ "description": "Bank name of the account (e.g. \"Chase\")" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" }))), "account_owner_type": Schema.optionalKey(Schema.Literals(["individual", "business"]).annotate({ "description": "The type of the account ownership. Required when the `account_type` is `iban`. For `individual` ownership, `first_name` and `last_name` are required. For `business` ownership, `business_name` is required." })), "first_name": Schema.optionalKey(Schema.String.annotate({ "description": "First name of the individual account holder. Required when the `account_owner_type` is `individual`" })), "last_name": Schema.optionalKey(Schema.String.annotate({ "description": "Last name of the individual account holder. Required when the `account_owner_type` is `individual`" })), "business_name": Schema.optionalKey(Schema.String.annotate({ "description": "Business name of the business account holder. Required when the `account_owner_type` is `business`" })), "address": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "street_line_1": Schema.String.check(Schema.isMinLength(4).annotate({ "expected": "a value with a length of at least 4" })).check(Schema.isMaxLength(35).annotate({ "expected": "a value with a length of at most 35" })), "street_line_2": Schema.optionalKey(Schema.String.check(Schema.isMaxLength(35).annotate({ "expected": "a value with a length of at most 35" }))), "city": Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "state": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-2 subdivision code. Must be supplied for US addresses." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "postal_code": Schema.optionalKey(Schema.String.annotate({ "description": "Must be supplied for countries that use postal codes." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "country": Schema.String.annotate({ "description": "Three-letter alpha-3 country code as defined in the ISO 3166-1 spec." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Address of the beneficiary of this account. Please ensure the address is valid (Google Maps is good for this). US addresses used to receive wires must include a street number." })), "account_owner_country": Schema.optionalKey(Schema.String.annotate({ "description": "Three-letter alpha-3 country of residence of the account owner (ISO 3166-1).", "readOnly": true }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))), "deactivation_reason": Schema.optionalKey(Schema.Literals(["plaid_item_error", "deactivated_due_to_bounceback", "deleted_by_developer", "requested_by_developer", "invalid_account_number", "invalid_bank_validation", "rejected_by_bank_provider"]).annotate({ "description": "Reason for deactivation when this External Account is inactive", "readOnly": true })), "deactivation_details": Schema.optionalKey(Schema.String.annotate({ "description": "Additional details about the deactivation when this External Account is inactive", "readOnly": true })), "account": Schema.StructWithRest(Schema.Struct({ "account_number": Schema.optionalKey(Schema.String.annotate({ "description": "The bank account number", "writeOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "routing_number": Schema.String.annotate({ "description": "The bank routing number" }).check(Schema.isMinLength(9).annotate({ "expected": "a value with a length of at least 9" })).check(Schema.isMaxLength(9).annotate({ "expected": "a value with a length of at most 9" })), "last_4": Schema.String.annotate({ "description": "Last 4 digits of the bank account number", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "checking_or_savings": Schema.optionalKey(Schema.Literals(["checking", "savings"]).annotate({ "description": "Determines whether the US account is treated as checking or savings. All US accounts will be treated as checking by default." })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "title": "us" }), "beneficiary_address_valid": Schema.optionalKey(Schema.Boolean.annotate({ "description": "Whether the beneficiary address is valid. A valid beneficiary address is required for all US External Accounts", "readOnly": true })), "last_4": Schema.optionalKey(Schema.String.annotate({ "description": "Last 4 digits of the bank account number. This field is getting deprecated in favor of the `account.last_4` field", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "account_number": Schema.optionalKey(Schema.String.annotate({ "description": "Account number of your bank account. This field is getting deprecated in favor of the `account.account_number` field for US accounts.", "writeOnly": true }).check(Schema.isMinLength(12).annotate({ "expected": "a value with a length of at least 12" }))), "routing_number": Schema.optionalKey(Schema.String.annotate({ "description": "Routing number of your bank account. This field is getting deprecated in favor of the `account.routing_number` field for US accounts.", "writeOnly": true }).check(Schema.isMinLength(9).annotate({ "expected": "a value with a length of at least 9" }))) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "title": "ACH/Wire", "description": "Properties shared by all external account types", "identifier": "FeeExternalAccount" }) +export type CreateFeeExternalAccountInput = { readonly "id"?: string, readonly "customer_id"?: string, readonly "bank_name"?: string, readonly "account_owner_name": string, readonly "created_at"?: string, readonly "updated_at"?: string, readonly "active"?: boolean, readonly "account_owner_type"?: "individual" | "business", readonly "first_name"?: string, readonly "last_name"?: string, readonly "business_name"?: string, readonly "address"?: { readonly "street_line_1": string, readonly "street_line_2"?: string, readonly "city": string, readonly "state"?: string, readonly "postal_code"?: string, readonly "country": string } & { readonly [x: string]: Schema.Json }, readonly "account_owner_country"?: string, readonly "deactivation_reason"?: "plaid_item_error" | "deactivated_due_to_bounceback" | "deleted_by_developer" | "requested_by_developer" | "invalid_account_number" | "invalid_bank_validation" | "rejected_by_bank_provider", readonly "deactivation_details"?: string, readonly "account_type": "us", readonly "currency": "usd", readonly "account": { readonly "account_number": string, readonly "routing_number": string, readonly "last_4"?: string, readonly "checking_or_savings"?: "checking" | "savings" } & { readonly [x: string]: Schema.Json }, readonly "beneficiary_address_valid"?: boolean, readonly "last_4"?: string, readonly "account_number"?: string, readonly "routing_number"?: string } & { readonly [x: string]: Schema.Json } +export const CreateFeeExternalAccountInput = Schema.StructWithRest(Schema.Struct({ "id": Schema.optionalKey(Schema.String.annotate({ "description": "A UUID that uniquely identifies a resource", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "customer_id": Schema.optionalKey(Schema.String.annotate({ "description": "The id of the Bridge customer that this External Account belongs to", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "bank_name": Schema.optionalKey(Schema.String.annotate({ "description": "Bank name of the account (e.g. \"Chase\")" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" }))), "account_owner_name": Schema.String.annotate({ "description": "Owner of the account Bank Account (e.g. \"John Doe\"). For ach, wire, and iban accounts, this field must be at least 3 characters, at most 35 characters, and follow the regex pattern for the given account type:\n- ach: `^(?!\\s*$)[\\x20-\\x7E]*$`\n- wire: ```^[ \\w!\"#$%&'()+,\\-./:;<=>?@\\\\_`~]*$```\n- iban: `^(?![:\\- ]*$)[a-zA-Z0-9\\/\\-?:().,'+ _]+$`\n" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" })), "created_at": Schema.optionalKey(Schema.String.annotate({ "description": "Time of creation of the External Account", "readOnly": true, "format": "date-time" })), "updated_at": Schema.optionalKey(Schema.String.annotate({ "description": "Time of last update of the External Account", "readOnly": true, "format": "date-time" })), "active": Schema.optionalKey(Schema.Boolean.annotate({ "description": "Whether or not this External Account is active", "readOnly": true })), "account_owner_type": Schema.optionalKey(Schema.Literals(["individual", "business"]).annotate({ "description": "The type of the account ownership. Required when the `account_type` is `iban`. For `individual` ownership, `first_name` and `last_name` are required. For `business` ownership, `business_name` is required." })), "first_name": Schema.optionalKey(Schema.String.annotate({ "description": "First name of the individual account holder. Required when the `account_owner_type` is `individual`" })), "last_name": Schema.optionalKey(Schema.String.annotate({ "description": "Last name of the individual account holder. Required when the `account_owner_type` is `individual`" })), "business_name": Schema.optionalKey(Schema.String.annotate({ "description": "Business name of the business account holder. Required when the `account_owner_type` is `business`" })), "address": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "street_line_1": Schema.String.check(Schema.isMinLength(4).annotate({ "expected": "a value with a length of at least 4" })).check(Schema.isMaxLength(35).annotate({ "expected": "a value with a length of at most 35" })), "street_line_2": Schema.optionalKey(Schema.String.check(Schema.isMaxLength(35).annotate({ "expected": "a value with a length of at most 35" }))), "city": Schema.String.check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "state": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-2 subdivision code. Must be supplied for US addresses." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "postal_code": Schema.optionalKey(Schema.String.annotate({ "description": "Must be supplied for countries that use postal codes." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "country": Schema.String.annotate({ "description": "Three-letter alpha-3 country code as defined in the ISO 3166-1 spec." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Address of the beneficiary of this account. Please ensure the address is valid (Google Maps is good for this). US addresses used to receive wires must include a street number." })), "account_owner_country": Schema.optionalKey(Schema.String.annotate({ "description": "Three-letter alpha-3 country of residence of the account owner (ISO 3166-1).", "readOnly": true }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))), "deactivation_reason": Schema.optionalKey(Schema.Literals(["plaid_item_error", "deactivated_due_to_bounceback", "deleted_by_developer", "requested_by_developer", "invalid_account_number", "invalid_bank_validation", "rejected_by_bank_provider"]).annotate({ "description": "Reason for deactivation when this External Account is inactive", "readOnly": true })), "deactivation_details": Schema.optionalKey(Schema.String.annotate({ "description": "Additional details about the deactivation when this External Account is inactive", "readOnly": true })), "account_type": Schema.Literal("us").annotate({ "description": "Type of the bank account." }), "currency": Schema.Literal("usd").annotate({ "description": "Currency associated with the bank account. Must be `usd` for US accounts." }), "account": Schema.StructWithRest(Schema.Struct({ "account_number": Schema.String.annotate({ "description": "The bank account number", "writeOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "routing_number": Schema.String.annotate({ "description": "The bank routing number" }).check(Schema.isMinLength(9).annotate({ "expected": "a value with a length of at least 9" })).check(Schema.isMaxLength(9).annotate({ "expected": "a value with a length of at most 9" })), "last_4": Schema.optionalKey(Schema.String.annotate({ "description": "Last 4 digits of the bank account number", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "checking_or_savings": Schema.optionalKey(Schema.Literals(["checking", "savings"]).annotate({ "description": "Determines whether the US account is treated as checking or savings. All US accounts will be treated as checking by default." })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "title": "us" }), "beneficiary_address_valid": Schema.optionalKey(Schema.Boolean.annotate({ "description": "Whether the beneficiary address is valid. A valid beneficiary address is required for all US External Accounts", "readOnly": true })), "last_4": Schema.optionalKey(Schema.String.annotate({ "description": "Last 4 digits of the bank account number. This field is getting deprecated in favor of the `account.last_4` field", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "account_number": Schema.optionalKey(Schema.String.annotate({ "description": "Account number of your bank account. This field is getting deprecated in favor of the `account.account_number` field for US accounts.", "writeOnly": true }).check(Schema.isMinLength(12).annotate({ "expected": "a value with a length of at least 12" }))), "routing_number": Schema.optionalKey(Schema.String.annotate({ "description": "Routing number of your bank account. This field is getting deprecated in favor of the `account.routing_number` field for US accounts.", "writeOnly": true }).check(Schema.isMinLength(9).annotate({ "expected": "a value with a length of at least 9" }))) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Properties shared by all external account types", "title": "ACH/Wire", "identifier": "CreateFeeExternalAccountInput" }) +export type CardProgramSummary = { readonly "period"?: "year" | "month" | "week" | "day" | "lifetime", readonly "period_starting"?: string, readonly "cards_provisioned_count"?: number, readonly "card_transactions_count"?: number, readonly "provisioned_cards_by_country"?: { readonly [x: string]: number }, readonly "transaction_volume"?: string, readonly "transacting_card_accounts_count"?: number, readonly "card_transactions_count_by_country"?: { readonly [x: string]: number }, readonly "transaction_volume_by_country"?: { readonly [x: string]: string }, readonly "transacting_cards_by_country"?: { readonly [x: string]: number } } +export const CardProgramSummary = Schema.Struct({ "period": Schema.optionalKey(Schema.Literals(["year", "month", "week", "day", "lifetime"]).annotate({ "description": "The period type of the card program summary" })), "period_starting": Schema.optionalKey(Schema.String.annotate({ "description": "The starting date of the period, in ISO8601 format", "examples": ["2025-01-01"] })), "cards_provisioned_count": Schema.optionalKey(Schema.Number.annotate({ "description": "The number of cards provisioned during the period", "examples": [1123] }).check(Schema.isInt().annotate({ "expected": "an integer" }))), "card_transactions_count": Schema.optionalKey(Schema.Number.annotate({ "description": "The number of card transactions during the period, excluding refunds.", "examples": [31415] }).check(Schema.isInt().annotate({ "expected": "an integer" }))), "provisioned_cards_by_country": Schema.optionalKey(Schema.Record(Schema.String, Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))).annotate({ "description": "The number of cards provisioned during the period, by issuing country. The key is the ISO-3166-1 alpha-3 country code, and the value is the number of cards provisioned for that issuing country.", "examples": [{ "USA": 123, "MEX": 45 }] })), "transaction_volume": Schema.optionalKey(Schema.String.annotate({ "description": "The total transaction volume during the period, in USD", "examples": ["-100.0"] })), "transacting_card_accounts_count": Schema.optionalKey(Schema.Number.annotate({ "description": "The number of card accounts that transacted during the period", "examples": [2047] }).check(Schema.isInt().annotate({ "expected": "an integer" }))), "card_transactions_count_by_country": Schema.optionalKey(Schema.Record(Schema.String, Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))).annotate({ "description": "The number of card transactions during the period, by merchant country. The key is the ISO-3166-1 alpha-3 country code, and the value is the number of card transactions for that merchant country.", "examples": [{ "USA": 74, "MEX": 55 }] })), "transaction_volume_by_country": Schema.optionalKey(Schema.Record(Schema.String, Schema.String).annotate({ "description": "The transaction volume during the period, by merchant country. The key is the ISO-3166-1 alpha-3 country code, and the value is the transaction volume for that merchant country.", "examples": [{ "USA": "7.04", "MEX": "5.0" }] })), "transacting_cards_by_country": Schema.optionalKey(Schema.Record(Schema.String, Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))).annotate({ "description": "The number of cards that transacted during the period, by issuing country. The key is the ISO-3166-1 alpha-3 country code, and the value is the number of cards transacted for that issuing country.", "examples": [{ "USA": 123, "MEX": 45 }] })) }).annotate({ "description": "The summary of a card program for a given period", "identifier": "CardProgramSummary" }) +export type CardDesigns = { readonly "card_designs"?: ReadonlyArray<{ readonly "shortname"?: string, readonly "type"?: "virtual" | "physical" }>, readonly "default_card_design_shortname"?: string } +export const CardDesigns = Schema.Struct({ "card_designs": Schema.optionalKey(Schema.Array(Schema.Struct({ "shortname": Schema.optionalKey(Schema.String.annotate({ "description": "The shortname of the card design. You can pass this into the `card_design_shortname` parameter when creating a card account." })), "type": Schema.optionalKey(Schema.Literals(["virtual", "physical"]).annotate({ "description": "The type of card that the design applies to" })) })).annotate({ "description": "A listing of the designs that you can use to issue a card with." })), "default_card_design_shortname": Schema.optionalKey(Schema.String.annotate({ "description": "The shortname of the default card design" })) }).annotate({ "description": "A listing of the designs that you can use to issue a card with.", "identifier": "CardDesigns" }) +export type CreateApiKeyInput = { readonly "scopes": ReadonlyArray<"api_key:create" | "api_key:self:read" | "audit_log:read" | "batch_settlement:create" | "batch_settlement:read" | "card:create" | "card:delete" | "card:read" | "card:update" | "crypto_return_policy:create" | "crypto_return_policy:delete" | "crypto_return_policy:read" | "crypto_return_policy:update" | "customer:create" | "customer:delete" | "customer:read" | "customer:update" | "customer_creation_request:create" | "customer_creation_request:read" | "developer_fee:create" | "developer_fee:read" | "developer_fee:update" | "developer_trade_configuration:read" | "developer_trade_configuration:update" | "exchange_rate:read" | "external_account:create" | "external_account:delete" | "external_account:read" | "external_account:update" | "funds_request:read" | "inquiry:read" | "inquiry:resume" | "liquidation_address:create" | "liquidation_address:drain:read" | "liquidation_address:drain:update" | "liquidation_address:read" | "liquidation_address:update" | "prefunded_account:create" | "prefunded_account:history:read" | "prefunded_account:read" | "rewards:read" | "rfi:read" | "sandbox:developer:create" | "sandbox:simulate" | "spender_contract:approval:create" | "spender_contract:approval:read" | "spender_contract:create" | "spender_contract:read" | "tos_link:create" | "tos_link:read" | "transfer:create" | "transfer:create:privy_custodial_wallet" | "transfer:delete" | "transfer:read" | "transfer:update" | "travel_rule_data:create" | "virtual_account:create" | "virtual_account:delete" | "virtual_account:history:read" | "virtual_account:read" | "virtual_account:transaction:read" | "virtual_account:update" | "wallet:create" | "wallet:create:privy_custodial_wallet" | "wallet:customer:read" | "wallet:delete" | "wallet:developer:read" | "wallet:update" | "webhook:create" | "webhook:delete" | "webhook:read" | "webhook:update">, readonly "name"?: string } & { readonly [x: string]: Schema.Json } +export const CreateApiKeyInput = Schema.StructWithRest(Schema.Struct({ "scopes": Schema.Array(Schema.Literals(["api_key:create", "api_key:self:read", "audit_log:read", "batch_settlement:create", "batch_settlement:read", "card:create", "card:delete", "card:read", "card:update", "crypto_return_policy:create", "crypto_return_policy:delete", "crypto_return_policy:read", "crypto_return_policy:update", "customer:create", "customer:delete", "customer:read", "customer:update", "customer_creation_request:create", "customer_creation_request:read", "developer_fee:create", "developer_fee:read", "developer_fee:update", "developer_trade_configuration:read", "developer_trade_configuration:update", "exchange_rate:read", "external_account:create", "external_account:delete", "external_account:read", "external_account:update", "funds_request:read", "inquiry:read", "inquiry:resume", "liquidation_address:create", "liquidation_address:drain:read", "liquidation_address:drain:update", "liquidation_address:read", "liquidation_address:update", "prefunded_account:create", "prefunded_account:history:read", "prefunded_account:read", "rewards:read", "rfi:read", "sandbox:developer:create", "sandbox:simulate", "spender_contract:approval:create", "spender_contract:approval:read", "spender_contract:create", "spender_contract:read", "tos_link:create", "tos_link:read", "transfer:create", "transfer:create:privy_custodial_wallet", "transfer:delete", "transfer:read", "transfer:update", "travel_rule_data:create", "virtual_account:create", "virtual_account:delete", "virtual_account:history:read", "virtual_account:read", "virtual_account:transaction:read", "virtual_account:update", "wallet:create", "wallet:create:privy_custodial_wallet", "wallet:customer:read", "wallet:delete", "wallet:developer:read", "wallet:update", "webhook:create", "webhook:delete", "webhook:read", "webhook:update"]).annotate({ "description": "A scope that may be granted to a scoped API key. Unrestricted keys are created via the Dashboard and implicitly hold the standard scopes; they cannot be requested here." })).annotate({ "description": "Scopes to grant the new key. Must be a non-empty array. Each scope must be one you yourself hold (scope subsetting)." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "name": Schema.optionalKey(Schema.String.annotate({ "description": "A human-readable label for this key, up to 100 characters. Useful for identifying the key's purpose later." }).check(Schema.isMaxLength(100).annotate({ "expected": "a value with a length of at most 100" }))) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "identifier": "CreateApiKeyInput" }) +export type ApiKeyWithSecret = { readonly "id": string, readonly "type": "Public" | "Private", readonly "owner_type": "Developer", readonly "owner_id": string, readonly "prefix": "sk-live" | "sk-test", readonly "last_4": string, readonly "state": "Active" | "Deleted", readonly "created_at": string, readonly "updated_at": string, readonly "scopes": ReadonlyArray, readonly "name"?: string, readonly "value": string } & { readonly [x: string]: Schema.Json } +export const ApiKeyWithSecret = Schema.StructWithRest(Schema.Struct({ "id": Schema.String.annotate({ "description": "The unique identifier for this API key.", "format": "uuid" }), "type": Schema.Literals(["Public", "Private"]).annotate({ "description": "Whether the key was created programmatically (Private) or via the Dashboard (Public)." }), "owner_type": Schema.Literal("Developer").annotate({ "description": "The type of entity that owns the key. Always `Developer`." }), "owner_id": Schema.String.annotate({ "description": "The developer ID that owns the key.", "format": "uuid" }), "prefix": Schema.Literals(["sk-live", "sk-test"]).annotate({ "description": "The environment prefix of the key. `sk-live` in production, `sk-test` in sandbox." }), "last_4": Schema.String.annotate({ "description": "The last four characters of the key, shown alongside the prefix for disambiguation in audit logs." }), "state": Schema.Literals(["Active", "Deleted"]).annotate({ "description": "Lifecycle state of the key." }), "created_at": Schema.String.annotate({ "format": "date-time" }), "updated_at": Schema.String.annotate({ "format": "date-time" }), "scopes": Schema.Array(Schema.String).annotate({ "description": "The scopes authorized on this key. A single-element list containing `bridge:api_unrestricted`\ndenotes an unrestricted key (all standard scopes). Any other list denotes a scoped key.\n" }), "name": Schema.optionalKey(Schema.String.annotate({ "description": "The human-readable label for this key, if one was provided at creation." }).check(Schema.isMaxLength(100).annotate({ "expected": "a value with a length of at most 100" }))), "value": Schema.String.annotate({ "description": "The plaintext secret for this API key. Store it securely — it cannot be retrieved again.", "examples": ["sk-live-0123456789abcdef0123456789ab9f2c"] }) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Returned only on key creation. `value` is the plaintext secret and is shown exactly once.", "identifier": "ApiKeyWithSecret" }) +export type ApiKey = { readonly "id": string, readonly "type": "Public" | "Private", readonly "owner_type": "Developer", readonly "owner_id": string, readonly "prefix": "sk-live" | "sk-test", readonly "last_4": string, readonly "state": "Active" | "Deleted", readonly "created_at": string, readonly "updated_at": string, readonly "scopes": ReadonlyArray, readonly "name"?: string } & { readonly [x: string]: Schema.Json } +export const ApiKey = Schema.StructWithRest(Schema.Struct({ "id": Schema.String.annotate({ "description": "The unique identifier for this API key.", "format": "uuid" }), "type": Schema.Literals(["Public", "Private"]).annotate({ "description": "Whether the key was created programmatically (Private) or via the Dashboard (Public)." }), "owner_type": Schema.Literal("Developer").annotate({ "description": "The type of entity that owns the key. Always `Developer`." }), "owner_id": Schema.String.annotate({ "description": "The developer ID that owns the key.", "format": "uuid" }), "prefix": Schema.Literals(["sk-live", "sk-test"]).annotate({ "description": "The environment prefix of the key. `sk-live` in production, `sk-test` in sandbox." }), "last_4": Schema.String.annotate({ "description": "The last four characters of the key, shown alongside the prefix for disambiguation in audit logs." }), "state": Schema.Literals(["Active", "Deleted"]).annotate({ "description": "Lifecycle state of the key." }), "created_at": Schema.String.annotate({ "format": "date-time" }), "updated_at": Schema.String.annotate({ "format": "date-time" }), "scopes": Schema.Array(Schema.String).annotate({ "description": "The scopes authorized on this key. A single-element list containing `bridge:api_unrestricted`\ndenotes an unrestricted key (all standard scopes). Any other list denotes a scoped key.\n" }), "name": Schema.optionalKey(Schema.String.annotate({ "description": "The human-readable label for this key, if one was provided at creation." }).check(Schema.isMaxLength(100).annotate({ "expected": "a value with a length of at most 100" }))) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "identifier": "ApiKey" }) +export type IndividualKycLinkResponse = { readonly "id"?: string, readonly "type"?: "individual" | "business", readonly "customer_id"?: string, readonly "full_name"?: string, readonly "email"?: string, readonly "kyc_link"?: string, readonly "kyc_status"?: "not_started" | "incomplete" | "awaiting_questionnaire" | "awaiting_ubo" | "under_review" | "approved" | "rejected" | "paused" | "offboarded" | "deposits_restricted", readonly "rejection_reasons"?: ReadonlyArray<{ readonly "developer_reason"?: string, readonly "reason"?: string, readonly "created_at"?: string | null } & { readonly [x: string]: Schema.Json }>, readonly "tos_link"?: string, readonly "tos_status"?: "pending" | "approved", readonly "created_at"?: string } & { readonly [x: string]: Schema.Json } +export const IndividualKycLinkResponse = Schema.StructWithRest(Schema.Struct({ "id": Schema.optionalKey(Schema.String.annotate({ "description": "ID of the KYC link" })), "type": Schema.optionalKey(Schema.Literals(["individual", "business"]).annotate({ "description": "Type of the KYC link" })), "customer_id": Schema.optionalKey(Schema.String.annotate({ "description": "ID of the customer." })), "full_name": Schema.optionalKey(Schema.String.annotate({ "description": "Full name of the customer, for a business, this would be the business entity's legal name" })), "email": Schema.optionalKey(Schema.String.annotate({ "description": "Email of the customer" })), "kyc_link": Schema.optionalKey(Schema.String.annotate({ "description": "Link to the KYC flow" })), "kyc_status": Schema.optionalKey(Schema.Literals(["not_started", "incomplete", "awaiting_questionnaire", "awaiting_ubo", "under_review", "approved", "rejected", "paused", "offboarded", "deposits_restricted"]).annotate({ "description": "Status of the KYC flow." })), "rejection_reasons": Schema.optionalKey(Schema.Array(Schema.StructWithRest(Schema.Struct({ "developer_reason": Schema.optionalKey(Schema.String.annotate({ "description": "Developer information for why a customer was rejected. Not to be shared with the customer." })), "reason": Schema.optionalKey(Schema.String.annotate({ "description": "Reason for why a customer was rejected. To be shared with the customer." })), "created_at": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Time of creation of the rejection reason" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Reason why the kyc_status was rejected" })).annotate({ "description": "Reasons why a customer KYC was rejected", "readOnly": true }).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" }))), "tos_link": Schema.optionalKey(Schema.String.annotate({ "description": "Link to the TOS flow" })), "tos_status": Schema.optionalKey(Schema.Literals(["pending", "approved"]).annotate({ "description": "Status of the TOS flow" })), "created_at": Schema.optionalKey(Schema.String.annotate({ "description": "Time of creation of the KYC link", "format": "date-time" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "identifier": "IndividualKycLinkResponse" }) +export type CreateKycLinks = { readonly "full_name"?: string, readonly "email": string, readonly "type": "individual" | "business", readonly "endorsements"?: ReadonlyArray<"base" | "cards" | "cop" | "faster_payments" | "pix" | "pix_onramp" | "pix_offramp" | "sepa" | "spei">, readonly "redirect_uri"?: string, readonly "transliterated_first_name"?: string, readonly "transliterated_middle_name"?: string, readonly "transliterated_last_name"?: string, readonly "transliterated_business_legal_name"?: string } & { readonly [x: string]: Schema.Json } +export const CreateKycLinks = Schema.StructWithRest(Schema.Struct({ "full_name": Schema.optionalKey(Schema.String.annotate({ "description": "Full name of the customer, for a business, this would be the business entity's legal name" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "email": Schema.String.annotate({ "description": "Email of the customer" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "type": Schema.Literals(["individual", "business"]).annotate({ "description": "Type of the customer (individual vs. business)" }), "endorsements": Schema.optionalKey(Schema.Array(Schema.Literals(["base", "cards", "cop", "faster_payments", "pix", "pix_onramp", "pix_offramp", "sepa", "spei"]).annotate({ "description": "The type of endorsement. Note: `pix_onramp` (BRL deposits via PIX) and `pix_offramp` (BRL withdrawals via PIX) can be requested individually for granular access. Requesting `pix` grants both directional endorsements. `pix_onramp` is not supported for non-BR individuals; if requested (or requested via `pix`) it will remain in an `endorsement_not_available_in_customers_region` state and no action is required.\n" })).annotate({ "description": "List of endorsements to request for the generated KYC link.\nFor example, `sepa` endorsement could be requested to allow an `individual` customer to submit `proof-of-address` documents in the KYC flow." }).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" }))), "redirect_uri": Schema.optionalKey(Schema.String.annotate({ "description": "The location where the customer should be redirected after completing the KYC flow. Must be in the form of http:// or https://." })), "transliterated_first_name": Schema.optionalKey(Schema.String.annotate({ "description": "Required when the `full_name` of an individual includes any non Latin-1 characters. Acceptable characters - Latin-1 Unicode Character Range: À-ÖØ-ßà-öø-ÿ; Standard Unicode Character Range: -~" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" }))), "transliterated_middle_name": Schema.optionalKey(Schema.String.annotate({ "description": "Required when the `full_name` of an individual includes any non Latin-1 characters and the individual has a middle name. Acceptable characters - Latin-1 Unicode Character Range: À-ÖØ-ßà-öø-ÿ; Standard Unicode Character Range: -~" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" }))), "transliterated_last_name": Schema.optionalKey(Schema.String.annotate({ "description": "Required when the `full_name` of an individual includes any non Latin-1 characters. Acceptable characters - Latin-1 Unicode Character Range: À-ÖØ-ßà-öø-ÿ; Standard Unicode Character Range: -~" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(256).annotate({ "expected": "a value with a length of at most 256" }))), "transliterated_business_legal_name": Schema.optionalKey(Schema.String.annotate({ "description": "Required if the `full_name` of a business includes any non Latin-1 characters. Acceptable characters - Latin-1 Unicode Character Range: À-ÖØ-ßà-öø-ÿ; Standard Unicode Character Range: -~" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(1024).annotate({ "expected": "a value with a length of at most 1024" }))) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "identifier": "CreateKycLinks" }) +export type Rfi = { readonly "id": string, readonly "state": "on_developer" | "on_bridge" | "closed", readonly "developer_id": string, readonly "customer_id"?: string, readonly "referent_id"?: string | null, readonly "referent_type"?: "transfer" | "drain" | "deposit" | "card_account", readonly "context"?: { readonly "amount_display"?: string, readonly "currency_display"?: string, readonly "transaction_date"?: string, readonly "customer_name"?: string, readonly "customer_email"?: string, readonly "sender_name"?: string, readonly "beneficiary_name"?: string, readonly "counterparty_name"?: string, readonly "creditor_iban"?: string, readonly "debtor_iban"?: string, readonly "custom_body"?: string }, readonly "bridge_action_taken"?: "customer_paused" | "transaction_paused", readonly "expected_action_on_expiry"?: "pause_customer", readonly "deadline": string, readonly "requested_items": ReadonlyArray<{ readonly "content": string }>, readonly "dashboard_url": string, readonly "state_changed_at"?: string | null, readonly "created_at": string, readonly "closed_at"?: string | null } & { readonly [x: string]: Schema.Json } +export const Rfi = Schema.StructWithRest(Schema.Struct({ "id": Schema.String.annotate({ "description": "A UUID that uniquely identifies a resource", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" })), "state": Schema.Literals(["on_developer", "on_bridge", "closed"]).annotate({ "description": "The current state of the RFI" }), "developer_id": Schema.String.annotate({ "description": "A UUID that uniquely identifies a resource", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" })), "customer_id": Schema.optionalKey(Schema.String.annotate({ "description": "The customer this RFI is associated with, if any", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "referent_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "The id of the record (transfer, drain, deposit, or card account) this RFI relates to, if any. Resolve it against the endpoint named by `referent_type`" })), "referent_type": Schema.optionalKey(Schema.Literals(["transfer", "drain", "deposit", "card_account"]).annotate({ "description": "The type of record that `referent_id` refers to" })), "context": Schema.optionalKey(Schema.Struct({ "amount_display": Schema.optionalKey(Schema.String.annotate({ "description": "The transaction amount, pre-formatted for display" })), "currency_display": Schema.optionalKey(Schema.String.annotate({ "description": "The transaction currency, pre-formatted for display" })), "transaction_date": Schema.optionalKey(Schema.String.annotate({ "description": "The transaction date, pre-formatted for display" })), "customer_name": Schema.optionalKey(Schema.String.annotate({ "description": "The customer's name" })), "customer_email": Schema.optionalKey(Schema.String.annotate({ "description": "The customer's email" })), "sender_name": Schema.optionalKey(Schema.String.annotate({ "description": "The sender's name, if this RFI concerns an incoming payment" })), "beneficiary_name": Schema.optionalKey(Schema.String.annotate({ "description": "The beneficiary's name, if this RFI concerns an outgoing payment" })), "counterparty_name": Schema.optionalKey(Schema.String.annotate({ "description": "The counterparty's name" })), "creditor_iban": Schema.optionalKey(Schema.String.annotate({ "description": "The creditor IBAN, for RFIs concerning an IBAN-based payment" })), "debtor_iban": Schema.optionalKey(Schema.String.annotate({ "description": "The debtor IBAN, for RFIs concerning an IBAN-based payment" })), "custom_body": Schema.optionalKey(Schema.String.annotate({ "description": "Ops-authored free text describing the request, present only for freeform RFIs" })) }).annotate({ "description": "Transaction and counterparty facts this RFI is about, keyed by field name. The set of keys present varies by RFI template - fields without a value for this RFI are omitted rather than set to null. May contain personally-identifiable information (customer name/email, IBANs, counterparty names). The properties below are the most common keys; other template-specific string keys may also be present." })), "bridge_action_taken": Schema.optionalKey(Schema.Literals(["customer_paused", "transaction_paused"]).annotate({ "description": "An action Bridge has already taken as a result of this RFI, if any" })), "expected_action_on_expiry": Schema.optionalKey(Schema.Literal("pause_customer").annotate({ "description": "The action Bridge expects to take if this RFI expires without a response, if any" })), "deadline": Schema.String.annotate({ "description": "The time by which a response to this RFI is expected", "format": "date-time" }), "requested_items": Schema.Array(Schema.Struct({ "content": Schema.String.annotate({ "description": "The question or request being made, in developer-facing prose" }) })).annotate({ "description": "The items Bridge is asking the developer to provide for this RFI" }), "dashboard_url": Schema.String.annotate({ "description": "A link to view and respond to this RFI in the Bridge dashboard" }), "state_changed_at": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "The time the RFI's state last changed", "format": "date-time" })), "created_at": Schema.String.annotate({ "description": "Time of creation of the RFI", "readOnly": true, "format": "date-time" }), "closed_at": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "The time the RFI was closed, if it has been", "format": "date-time" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "identifier": "Rfi" }) +export type FundsRequest = { readonly "id": string, readonly "deposit_id"?: string, readonly "customer_id"?: string, readonly "amount"?: string, readonly "currency"?: "usdb" | "usdc" | "usdt" | "usdl_linea" | "usd" | "pyusd", readonly "payment_rail"?: string, readonly "fraud"?: boolean, readonly "notice_date"?: string, readonly "imad"?: string, readonly "trace_number"?: string, readonly "bank_transaction_id"?: string, readonly "created_at"?: string, readonly "deposit_created_at"?: string } & { readonly [x: string]: Schema.Json } +export const FundsRequest = Schema.StructWithRest(Schema.Struct({ "id": Schema.String.annotate({ "description": "A UUID that uniquely identifies a resource", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" })), "deposit_id": Schema.optionalKey(Schema.String.annotate({ "description": "A UUID that uniquely identifies a resource" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" })).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1", "description": "The id that uniquely identifies the Bridge deposit associated with the funds request", "readOnly": true }))), "customer_id": Schema.optionalKey(Schema.String.annotate({ "description": "A UUID that uniquely identifies a resource" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" })).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1", "description": "The id of the Bridge customer that this static memo event belongs to", "readOnly": true }))), "amount": Schema.optionalKey(Schema.String.annotate({ "description": "Amount of the deposit, represented as a decimal string. Examples include \"100.25\", \"0.1\", \"1.234567\" etc. It is denominated in the source currency of the deposit." })), "currency": Schema.optionalKey(Schema.Literals(["usdb", "usdc", "usdt", "usdl_linea", "usd", "pyusd"])), "payment_rail": Schema.optionalKey(Schema.String.annotate({ "description": "The source payment rail of the deposit" })), "fraud": Schema.optionalKey(Schema.Boolean.annotate({ "description": "Whether the funds request was fraudulent or not" })), "notice_date": Schema.optionalKey(Schema.String.annotate({ "description": "Date that Bridge was notified about the funds request from our banking partner, in the format YYYY-MM-DD" })), "imad": Schema.optionalKey(Schema.String.annotate({ "description": "(Wire only) The IMAD of a wire deposit, if available" })), "trace_number": Schema.optionalKey(Schema.String.annotate({ "description": "(ACH only) The trace number of an ACH deposit, if available" })), "bank_transaction_id": Schema.optionalKey(Schema.String.annotate({ "description": "(Non-wire and Non-ACH only) In cases where an identifier tied to a public financial system is not available, we may instead provide a unique identifier that identifies the transaction for the relevant bank or financial institution" })), "created_at": Schema.optionalKey(Schema.String.annotate({ "description": "Time of creation of the funds request", "readOnly": true, "format": "date-time" })), "deposit_created_at": Schema.optionalKey(Schema.String.annotate({ "description": "Time of creation of the associated deposit", "readOnly": true, "format": "date-time" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "identifier": "FundsRequest" }) +export type Webhook = { readonly "id": string, readonly "url": string, readonly "status": "active" | "disabled" | "deleted", readonly "public_key": string, readonly "event_categories"?: ReadonlyArray<"customer" | "kyc_link" | "liquidation_address.drain" | "static_memo.activity" | "transfer" | "virtual_account.activity" | "bridge_wallet.activity" | "card_account" | "card_transaction" | "card_withdrawal" | "posted_card_account_transaction" | "external_account" | "rfi"> } & { readonly [x: string]: Schema.Json } +export const Webhook = Schema.StructWithRest(Schema.Struct({ "id": Schema.String.annotate({ "description": "An identifier that uniquely identifies the webhook endpoint" }).check(Schema.isPattern(new RegExp("^wep_[a-f0-9]+$")).annotate({ "expected": "a string matching the RegExp ^wep_[a-f0-9]+$" })), "url": Schema.String.annotate({ "description": "The URL that the webhook will send events to" }), "status": Schema.Literals(["active", "disabled", "deleted"]).annotate({ "description": "The status of the webhook. Only active webhooks will receive events automatically." }), "public_key": Schema.String.annotate({ "description": "The public key (in PEM format) that should be used to verify the authenticity of webhook events" }), "event_categories": Schema.optionalKey(Schema.Array(Schema.Literals(["customer", "kyc_link", "liquidation_address.drain", "static_memo.activity", "transfer", "virtual_account.activity", "bridge_wallet.activity", "card_account", "card_transaction", "card_withdrawal", "posted_card_account_transaction", "external_account", "rfi"]).annotate({ "description": "The category of the webhook event" })).annotate({ "description": "The list of event categories that the webhook endpoint will receive" }).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" }))) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "identifier": "Webhook" }) +export type CreateWebhook = { readonly "url": string, readonly "event_epoch": "webhook_creation" | "beginning_of_time", readonly "event_categories"?: ReadonlyArray<"customer" | "kyc_link" | "liquidation_address.drain" | "static_memo.activity" | "transfer" | "virtual_account.activity" | "bridge_wallet.activity" | "card_account" | "card_transaction" | "card_withdrawal" | "posted_card_account_transaction" | "external_account" | "rfi"> } & { readonly [x: string]: Schema.Json } +export const CreateWebhook = Schema.StructWithRest(Schema.Struct({ "url": Schema.String.annotate({ "description": "The URL that the webhook will send events to. It must use the HTTPS scheme and have a valid X.509 certificate. The URL doesn't need to be live, but the host must be reachable." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "event_epoch": Schema.Literals(["webhook_creation", "beginning_of_time"]).annotate({ "description": "Specifies the starting point from which this webhook will receive events. This should usually be set to \"webhook_creation\", unless there is a reason why this webhook needs to process events from before its creation. When this value is set to \"webhook_creation\", the webhook will receive a small number of events preceding its creation for convenience." }), "event_categories": Schema.optionalKey(Schema.Array(Schema.Literals(["customer", "kyc_link", "liquidation_address.drain", "static_memo.activity", "transfer", "virtual_account.activity", "bridge_wallet.activity", "card_account", "card_transaction", "card_withdrawal", "posted_card_account_transaction", "external_account", "rfi"]).annotate({ "description": "The category of the webhook event" })).annotate({ "description": "The list of event categories that the webhook endpoint will receive" }).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" }))) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "identifier": "CreateWebhook" }) +export type PutWebhookPayload = { readonly "url"?: string, readonly "status"?: "active" | "disabled", readonly "event_categories"?: ReadonlyArray<"customer" | "kyc_link" | "liquidation_address.drain" | "static_memo.activity" | "transfer" | "virtual_account.activity" | "bridge_wallet.activity" | "card_account" | "card_transaction" | "card_withdrawal" | "posted_card_account_transaction" | "external_account" | "rfi"> } & { readonly [x: string]: Schema.Json } +export const PutWebhookPayload = Schema.StructWithRest(Schema.Struct({ "url": Schema.optionalKey(Schema.String.annotate({ "description": "The new HTTPS URL that Bridge will send events to." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "status": Schema.optionalKey(Schema.Literals(["active", "disabled"]).annotate({ "description": "The new status of the webhook endpoint. If set to \"active\", the webhook will be enabled and will send requests to the new URL. If set to \"disabled\", the webhook will be disabled and will not send requests to the URL." })), "event_categories": Schema.optionalKey(Schema.Array(Schema.Literals(["customer", "kyc_link", "liquidation_address.drain", "static_memo.activity", "transfer", "virtual_account.activity", "bridge_wallet.activity", "card_account", "card_transaction", "card_withdrawal", "posted_card_account_transaction", "external_account", "rfi"]).annotate({ "description": "The category of the webhook event" })).annotate({ "description": "The list of event categories that the webhook endpoint will receive. Note that if modified, the webhook endpoint will receive events for new categories only from the current point onwards." }).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" }))) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "identifier": "PutWebhookPayload" }) +export type WebhookEvent = { readonly "api_version": string, readonly "event_id": string, readonly "event_developer_id": string, readonly "event_sequence"?: number, readonly "event_category": "customer" | "kyc_link" | "liquidation_address.drain" | "static_memo.activity" | "transfer" | "virtual_account.activity" | "bridge_wallet.activity" | "card_account" | "card_transaction" | "card_withdrawal" | "posted_card_account_transaction" | "external_account" | "rfi", readonly "event_type": "created" | "updated" | "updated.status_transitioned" | "deleted" | "canceled", readonly "event_object_id": string, readonly "event_object_status"?: "not_started" | "incomplete" | "active" | "rejected" | "under_review" | "manual_review" | "awaiting_ubo" | "approved" | "awaiting_funds" | "funds_received" | "payment_submitted" | "payment_processed" | "in_review" | "canceled" | "error" | "returned" | "refund_in_flight" | "refund_failed" | "refunded" | "undeliverable", readonly "event_object": { readonly [x: string]: Schema.Json }, readonly "event_object_changes": { readonly [x: string]: Schema.Json }, readonly "event_created_at": string } & { readonly [x: string]: Schema.Json } +export const WebhookEvent = Schema.StructWithRest(Schema.Struct({ "api_version": Schema.String.annotate({ "readOnly": true }), "event_id": Schema.String.annotate({ "description": "A UUID that uniquely identifies a resource", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" })), "event_developer_id": Schema.String.annotate({ "description": "The developer ID of the developer", "readOnly": true }), "event_sequence": Schema.optionalKey(Schema.Number.annotate({ "readOnly": true }).check(Schema.isInt().annotate({ "expected": "an integer" }))), "event_category": Schema.Literals(["customer", "kyc_link", "liquidation_address.drain", "static_memo.activity", "transfer", "virtual_account.activity", "bridge_wallet.activity", "card_account", "card_transaction", "card_withdrawal", "posted_card_account_transaction", "external_account", "rfi"]).annotate({ "description": "The category of the webhook event" }), "event_type": Schema.Literals(["created", "updated", "updated.status_transitioned", "deleted", "canceled"]).annotate({ "description": "The values here will be prefixed with the event_category. For example, a customer created event will be `customer.created`" }), "event_object_id": Schema.String.annotate({ "description": "A UUID that uniquely identifies a resource", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" })), "event_object_status": Schema.optionalKey(Schema.Literals(["not_started", "incomplete", "active", "rejected", "under_review", "manual_review", "awaiting_ubo", "approved", "awaiting_funds", "funds_received", "payment_submitted", "payment_processed", "in_review", "canceled", "error", "returned", "refund_in_flight", "refund_failed", "refunded", "undeliverable"]).annotate({ "readOnly": true })), "event_object": Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" })).annotate({ "description": "The object that was affected by the event", "readOnly": true }), "event_object_changes": Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" })).annotate({ "description": "The changes that were made to the object", "readOnly": true }), "event_created_at": Schema.String.annotate({ "readOnly": true, "format": "date-time" }) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "identifier": "WebhookEvent" }) +export type WebhookEventDeliveryLog = { readonly "status": number, readonly "event_id": string, readonly "response_body": string, readonly "created_at": string } & { readonly [x: string]: Schema.Json } +export const WebhookEventDeliveryLog = Schema.StructWithRest(Schema.Struct({ "status": Schema.Number.annotate({ "description": "The status code of the delivery" }).check(Schema.isInt().annotate({ "expected": "an integer" })), "event_id": Schema.String.annotate({ "description": "The id of the event for the delivery" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" })), "response_body": Schema.String.annotate({ "description": "The response body of the delivery" }), "created_at": Schema.String.annotate({ "description": "The time of the delivery", "format": "date-time" }) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "identifier": "WebhookEventDeliveryLog" }) +export type SendWebhookPayload = { readonly "event_id"?: string } & { readonly [x: string]: Schema.Json } +export const SendWebhookPayload = Schema.StructWithRest(Schema.Struct({ "event_id": Schema.optionalKey(Schema.String.annotate({ "description": "The ID of the event that will be delivered to your endpoint" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "identifier": "SendWebhookPayload" }) +export type TravelRuleData = { readonly "originator"?: { readonly "is_self"?: boolean, readonly "name"?: string, readonly "address"?: { readonly "street_line_1"?: string, readonly "street_line_2"?: string, readonly "city"?: string, readonly "state"?: string, readonly "postal_code"?: string, readonly "country"?: string }, readonly "wallet_type"?: "hosted" | "external" | "self_custodied", readonly "wallet_attested_ownership_at"?: string, readonly "identifying_information"?: ReadonlyArray<{ readonly "type": "drivers_license" | "matriculate_id" | "military_id" | "national_id" | "passport" | "permanent_residency_id" | "state_or_provincial_id" | "visa" | "abn" | "acn" | "ahv" | "ak" | "aom" | "arbn" | "avs" | "bc" | "bce" | "bin" | "bir" | "bp" | "brn" | "bsn" | "bvn" | "cc" | "cdi" | "cedula_juridica" | "cf" | "cif" | "cin" | "cipc" | "cn" | "cnp" | "cnpj" | "cpf" | "cpr" | "crc" | "crib" | "crn" | "cro" | "cui" | "cuil" | "curp" | "cuit" | "cvr" | "edrpou" | "ein" | "embg" | "emirates_id" | "en" | "fin" | "fn" | "gstin" | "gui" | "hetu" | "hkid" | "hn" | "ic" | "ico" | "id" | "id_broj" | "idno" | "idnp" | "idnr" | "if" | "iin" | "ik" | "inn" | "ird" | "itin" | "itr" | "iva" | "jmbg" | "kbo" | "kvk" | "matricule" | "mf" | "mn" | "ms" | "mst" | "nic" | "nicn" | "nie" | "nif" | "nin" | "nino" | "nip" | "nipc" | "nipt" | "nit" | "npwp" | "nric" | "nrn" | "nrt" | "ntn" | "nuit" | "nzbn" | "oib" | "orgnr" | "other" | "pan" | "partita_iva" | "pesel" | "pib" | "pin" | "pk" | "ppsn" | "qid" | "rc" | "regon" | "rfc" | "ricn" | "rif" | "rn" | "rnc" | "rnokpp" | "rp" | "rrn" | "rtn" | "ruc" | "rut" | "si" | "sin" | "siren" | "siret" | "spi" | "ssm" | "ssn" | "steuer_id" | "strn" | "tckn" | "tfn" | "tin" | "tpin" | "trn" | "ucn" | "uen" | "uic" | "uid" | "usc" | "ust_idnr" | "utr" | "vat" | "vkn" | "voen" | "y_tunnus", readonly "issuing_country": string, readonly "number"?: string, readonly "description"?: string, readonly "expiration"?: string, readonly "image_front"?: string, readonly "image_back"?: string }>, readonly "birth_date"?: string, readonly "place_of_birth"?: { readonly "country"?: string, readonly "city"?: string }, readonly "legal_entity_identifier"?: string }, readonly "beneficiary"?: { readonly "is_self"?: boolean, readonly "name"?: string, readonly "address"?: { readonly "street_line_1"?: string, readonly "street_line_2"?: string, readonly "city"?: string, readonly "state"?: string, readonly "postal_code"?: string, readonly "country"?: string }, readonly "wallet_type"?: "hosted" | "external" | "self_custodied", readonly "wallet_attested_ownership_at"?: string, readonly "legal_entity_identifier"?: string } } +export const TravelRuleData = Schema.Struct({ "originator": Schema.optionalKey(Schema.Struct({ "is_self": Schema.optionalKey(Schema.Boolean.annotate({ "description": "Set to `true` when this party is the same person or business as the Bridge customer on the resource. When `true`, Bridge uses the customer's name and address on file instead of relying on `name` and `address` in this payload." })), "name": Schema.optionalKey(Schema.String.annotate({ "description": "Legal name of the originator or beneficiary. Usually omitted when `is_self` is `true`." })), "address": Schema.optionalKey(Schema.Struct({ "street_line_1": Schema.optionalKey(Schema.String), "street_line_2": Schema.optionalKey(Schema.String), "city": Schema.optionalKey(Schema.String), "state": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-2 subdivision code." })), "postal_code": Schema.optionalKey(Schema.String), "country": Schema.optionalKey(Schema.String.annotate({ "description": "Three-letter alpha-3 country code as defined in the ISO 3166-1 spec." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))) }).annotate({ "description": "Address for travel rule submissions. All fields are optional to support partial address data (e.g. country-only)." })), "wallet_type": Schema.optionalKey(Schema.Literals(["hosted", "external", "self_custodied"]).annotate({ "description": "Indicates the custody model for the wallet. Use `self_custodied` for customer-owned wallets (customer controls private keys), `hosted` for wallets managed by a developer or regulated entity on behalf of the customer, or `external` for wallets belonging to external exchanges or smart contracts." })), "wallet_attested_ownership_at": Schema.optionalKey(Schema.String.annotate({ "description": "Required when `wallet_type` is `self-custodied` or `hosted`. Must be a timestamp in the past indicating when wallet ownership was attested.", "format": "date-time" })), "identifying_information": Schema.optionalKey(Schema.Array(Schema.Struct({ "type": Schema.Literals(["drivers_license", "matriculate_id", "military_id", "national_id", "passport", "permanent_residency_id", "state_or_provincial_id", "visa", "abn", "acn", "ahv", "ak", "aom", "arbn", "avs", "bc", "bce", "bin", "bir", "bp", "brn", "bsn", "bvn", "cc", "cdi", "cedula_juridica", "cf", "cif", "cin", "cipc", "cn", "cnp", "cnpj", "cpf", "cpr", "crc", "crib", "crn", "cro", "cui", "cuil", "curp", "cuit", "cvr", "edrpou", "ein", "embg", "emirates_id", "en", "fin", "fn", "gstin", "gui", "hetu", "hkid", "hn", "ic", "ico", "id", "id_broj", "idno", "idnp", "idnr", "if", "iin", "ik", "inn", "ird", "itin", "itr", "iva", "jmbg", "kbo", "kvk", "matricule", "mf", "mn", "ms", "mst", "nic", "nicn", "nie", "nif", "nin", "nino", "nip", "nipc", "nipt", "nit", "npwp", "nric", "nrn", "nrt", "ntn", "nuit", "nzbn", "oib", "orgnr", "other", "pan", "partita_iva", "pesel", "pib", "pin", "pk", "ppsn", "qid", "rc", "regon", "rfc", "ricn", "rif", "rn", "rnc", "rnokpp", "rp", "rrn", "rtn", "ruc", "rut", "si", "sin", "siren", "siret", "spi", "ssm", "ssn", "steuer_id", "strn", "tckn", "tfn", "tin", "tpin", "trn", "ucn", "uen", "uic", "uid", "usc", "ust_idnr", "utr", "vat", "vkn", "voen", "y_tunnus"]).annotate({ "description": "Tax identification number type or government-issued ID document type (see enum). Country-specific tax and national ID lists: [Individuals](https://apidocs.bridge.xyz/docs/individual-tax-identification-numbers-by-country), [Businesses](https://apidocs.bridge.xyz/docs/business-tax-identification-numbers-by-country).\n\n**EEA / BBSA (policy in `eea_requirements.rb`):** In-scope individuals and UBOs need **both** a valid national-ID-type entry and a valid TIN per [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements). In-scope businesses need business registration **and** business tax ID types per country tables there. **TIN issuing country** must match residence (individuals) or incorporation (businesses). **Foreign tax** outside the incorporation country: set `has_foreign_tax_registration` on the business customer and add TIN objects per jurisdiction ([foreign tax / tax residency](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#tax-residency-status-foreign-tax-registry)).\n" }), "issuing_country": Schema.String.annotate({ "description": "The ISO 3166-1 (three-character) country code that issued the provided document." }), "number": Schema.optionalKey(Schema.String.annotate({ "description": "The unique identifier of the document. Required if this document is being used as a tax identification number (e.g., you are providing a passport or national_id with no other identification)." })), "description": Schema.optionalKey(Schema.String.annotate({ "description": "A description describing the provided document. This field is required when `other` is selected." })), "expiration": Schema.optionalKey(Schema.String.annotate({ "description": "The expiration date of the given document in yyyy-mm-dd format." })), "image_front": Schema.optionalKey(Schema.String.annotate({ "description": "This field is optionally accepted for tax_id types, but required for government_id types. Base64 encoded image* of the front side of the provided document, following the data-uri scheme i.e. data:image/[type];base64,[base_64_encoded_file_contents], with a minimum size of 200px x 200px \\n\\n*Maximum File Size: 15MB\\n\\n*Valid file types: .pdf, .jpeg, .jpg, .png, .heic, .tif\n\n_Note: When combined with an `image_back`, the combined size of both images must not exceed 24MB._\n" })), "image_back": Schema.optionalKey(Schema.String.annotate({ "description": "Base64 encoded image* of the back side of the provided document, following the data-uri scheme i.e. data:image/[type];base64,[base_64_encoded_file_contents], with a minimum size of 200px x 200px \\n\\n*Maximum File Size: 15MB\\n\\n*Valid file types: .pdf, .jpeg, .jpg, .png, .heic, .tif\n\n_Note: When combined with an `image_front`, the combined size of both images must not exceed 24MB._\n" })) })).annotate({ "title": "Identification Information", "writeOnly": true, "description": "List of identification objects for the originator. Do **not** include `image_front` or `image_back` fields in this context; those are not accepted in Travel Rule submissions.\n" })), "birth_date": Schema.optionalKey(Schema.String.annotate({ "description": "Date of birth in format yyyy-mm-dd." }).check(Schema.isMinLength(10).annotate({ "expected": "a value with a length of at least 10" })).check(Schema.isMaxLength(10).annotate({ "expected": "a value with a length of at most 10" }))), "place_of_birth": Schema.optionalKey(Schema.Struct({ "country": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-1 alpha-3 country code for the place of birth." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))), "city": Schema.optionalKey(Schema.String.annotate({ "description": "City of birth (recommended for EEA)." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))) }).annotate({ "description": "Country (and optionally city) of birth. **EEA / BBSA in-scope customers:** supply when onboarding individuals or associated persons under the [EEA updated requirements](https://apidocs.bridge.xyz/platform/customers/customers/eea-updated-requirements#country-of-birth-and-city-of-birth). This is a sparse address — no street address. At least `country` should be present when the object is sent; `city` is recommended and will be required by EU law in 2027.\n" })), "legal_entity_identifier": Schema.optionalKey(Schema.String.annotate({ "description": "The Legal Entity Identifier (LEI) or equivalent (e.g. VAT number) of the originator. Provide this when the originator is a legal entity rather than an individual." })) }).annotate({ "description": "Travel Rule details for originator crypto movement." })), "beneficiary": Schema.optionalKey(Schema.Struct({ "is_self": Schema.optionalKey(Schema.Boolean.annotate({ "description": "Set to `true` when this party is the same person or business as the Bridge customer on the resource. When `true`, Bridge uses the customer's name and address on file instead of relying on `name` and `address` in this payload." })), "name": Schema.optionalKey(Schema.String.annotate({ "description": "Legal name of the originator or beneficiary. Usually omitted when `is_self` is `true`." })), "address": Schema.optionalKey(Schema.Struct({ "street_line_1": Schema.optionalKey(Schema.String), "street_line_2": Schema.optionalKey(Schema.String), "city": Schema.optionalKey(Schema.String), "state": Schema.optionalKey(Schema.String.annotate({ "description": "ISO 3166-2 subdivision code." })), "postal_code": Schema.optionalKey(Schema.String), "country": Schema.optionalKey(Schema.String.annotate({ "description": "Three-letter alpha-3 country code as defined in the ISO 3166-1 spec." }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" }))) }).annotate({ "description": "Address for travel rule submissions. All fields are optional to support partial address data (e.g. country-only)." })), "wallet_type": Schema.optionalKey(Schema.Literals(["hosted", "external", "self_custodied"]).annotate({ "description": "Indicates the custody model for the wallet. Use `self_custodied` for customer-owned wallets (customer controls private keys), `hosted` for wallets managed by a developer or regulated entity on behalf of the customer, or `external` for wallets belonging to external exchanges or smart contracts." })), "wallet_attested_ownership_at": Schema.optionalKey(Schema.String.annotate({ "description": "Required when `wallet_type` is `self-custodied` or `hosted`. Must be a timestamp in the past indicating when wallet ownership was attested.", "format": "date-time" })), "legal_entity_identifier": Schema.optionalKey(Schema.String.annotate({ "description": "The Legal Entity Identifier (LEI) or equivalent (e.g. VAT number) of the beneficiary. Provide this when the beneficiary is a legal entity rather than an individual." })) }).annotate({ "description": "Travel Rule details for beneficiary crypto movement." })) }).annotate({ "description": "Travel Rule data for a crypto movement. Send this on create or update when the same counterparty should apply to every future use of a reusable resource, or send the same payload with `POST /travel_rule_data/{id}` when it belongs to one specific movement.", "identifier": "TravelRuleData" }) +export type Country = { readonly "name": string, readonly "alpha3": string, readonly "postal_code_format"?: string, readonly "subdivisions": ReadonlyArray<{ readonly "name": string, readonly "code": string } & { readonly [x: string]: Schema.Json }> } & { readonly [x: string]: Schema.Json } +export const Country = Schema.StructWithRest(Schema.Struct({ "name": Schema.String.annotate({ "description": "The name of the country" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "alpha3": Schema.String.annotate({ "description": "The three-letter alpha-3 country code as defined in the ISO 3166-1 spec, used in Bridge APIs" }).check(Schema.isMinLength(3).annotate({ "expected": "a value with a length of at least 3" })).check(Schema.isMaxLength(3).annotate({ "expected": "a value with a length of at most 3" })), "postal_code_format": Schema.optionalKey(Schema.String.annotate({ "description": "A [Ruby-formatted regular expression](https://ruby-doc.org/3.4.2/Regexp.html) that matches valid postal codes for the country, or null if the country does not use postal codes." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" }))), "subdivisions": Schema.Array(Schema.StructWithRest(Schema.Struct({ "name": Schema.String.annotate({ "description": "The name of the subdivision" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })), "code": Schema.String.annotate({ "description": "The subdivision code, which can be used in place of the name when interacting with Bridge via API" }).check(Schema.isMinLength(2).annotate({ "expected": "a value with a length of at least 2" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))])).annotate({ "description": "A list of subdivisions for the country" }).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "identifier": "Country" }) +export type CryptoReturnPolicy = { readonly "id"?: string, readonly "developer_id"?: string, readonly "refund_destination_address"?: string, readonly "refund_destination_blockchain_memo"?: string, readonly "refund_destination_chain"?: string, readonly "refund_destination_currency"?: string, readonly "strategy"?: string } +export const CryptoReturnPolicy = Schema.Struct({ "id": Schema.optionalKey(Schema.String), "developer_id": Schema.optionalKey(Schema.String), "refund_destination_address": Schema.optionalKey(Schema.String), "refund_destination_blockchain_memo": Schema.optionalKey(Schema.String), "refund_destination_chain": Schema.optionalKey(Schema.String), "refund_destination_currency": Schema.optionalKey(Schema.String), "strategy": Schema.optionalKey(Schema.String) }).annotate({ "identifier": "CryptoReturnPolicy" }) +export type PostCryptoReturnPoliciesInput = { readonly "refund_destination_address"?: string, readonly "refund_destination_blockchain_memo"?: string, readonly "refund_destination_chain"?: string, readonly "refund_destination_currency"?: string, readonly "strategy"?: string } +export const PostCryptoReturnPoliciesInput = Schema.Struct({ "refund_destination_address": Schema.optionalKey(Schema.String.annotate({ "description": "The address to which the refund will be sent. Required if the strategy is `static_address`, but must be unset if the strategy is `refund_to_sender`." })), "refund_destination_blockchain_memo": Schema.optionalKey(Schema.String.annotate({ "description": "The memo to include with the refund transaction. Must be unset if the strategy is `refund_to_sender`." })), "refund_destination_chain": Schema.optionalKey(Schema.String.annotate({ "description": "The blockchain on which the refund will be sent. Required if the strategy is `static_address`, but must be unset if the strategy is `refund_to_sender`." })), "refund_destination_currency": Schema.optionalKey(Schema.String.annotate({ "description": "The currency to which the refund will be sent. Required if the strategy is `static_address`, but must be unset if the strategy is `refund_to_sender`." })), "strategy": Schema.optionalKey(Schema.String.annotate({ "description": "The strategy to use for the refund. Can be `refund_to_sender` or `static_address`. We only support multiple policies for `static_address`; different strategies cannot have multiple policies. If multiple `static_address` policies exist, the policy that matches both the currency and chain will be used first. If no such policy is found, the policy that matches only the currency will be used instead." })) }).annotate({ "identifier": "PostCryptoReturnPoliciesInput" }) +export type CardAccount = { readonly "id": string, readonly "client_reference_id"?: string, readonly "customer_id": string, readonly "cardholder_name"?: { readonly "first_name": string, readonly "middle_name"?: string, readonly "last_name": string } & { readonly [x: string]: Schema.Json }, readonly "card_image_url"?: string, readonly "status": "active" | "pending" | "inactive" | "frozen", readonly "status_reason"?: string, readonly "card_details"?: { readonly "last_4": string, readonly "expiry": string, readonly "bin": string, readonly "pin_status"?: "not_set" | "ok" } & { readonly [x: string]: Schema.Json }, readonly "balances": { readonly "available": { readonly "amount": string, readonly "currency": "usdc" } & { readonly [x: string]: Schema.Json }, readonly "hold": { readonly "amount": string, readonly "currency": "usdc" } & { readonly [x: string]: Schema.Json } } & { readonly [x: string]: Schema.Json }, readonly "freezes": ReadonlyArray<{ readonly "initiator": "bridge", readonly "card_account_id": string, readonly "reason": "lost_or_stolen" | "suspicious_activity" | "planned_inactivity" | "suspected_fraud" | "other", readonly "reason_detail"?: string, readonly "starting_at"?: string, readonly "ending_at"?: string, readonly "created_at": string, readonly "status": Schema.Json } & { readonly [x: string]: Schema.Json }>, readonly "stripe_card_id"?: string | null, readonly "crypto_account"?: { readonly "type": "standard" | "bridge_wallet" | "noncustodial_ata", readonly "address": string } & { readonly [x: string]: Schema.Json }, readonly "funding_instructions"?: { readonly "currency": "usdc", readonly "chain": "arbitrum" | "avalanche_c_chain" | "base" | "ethereum" | "optimism" | "polygon" | "solana" | "stellar", readonly "address": string, readonly "memo"?: string } & { readonly [x: string]: Schema.Json }, readonly "additional_funding_instructions"?: ReadonlyArray<{ readonly "currency": "usdc", readonly "chain": "arbitrum" | "avalanche_c_chain" | "base" | "ethereum" | "optimism" | "polygon" | "solana" | "stellar", readonly "address": string, readonly "memo"?: string } & { readonly [x: string]: Schema.Json }> } & { readonly [x: string]: Schema.Json } +export const CardAccount = Schema.StructWithRest(Schema.Struct({ "id": Schema.String.annotate({ "description": "ID of the card account" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" })), "client_reference_id": Schema.optionalKey(Schema.String.annotate({ "description": "The client-provided reference ID" })), "customer_id": Schema.String.annotate({ "description": "ID of the customer" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" })), "cardholder_name": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "first_name": Schema.String, "middle_name": Schema.optionalKey(Schema.String), "last_name": Schema.String }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "The name of the cardholder associated to the card. By default, this will be the name of the associated customer. To override the cardholder name, you can contact Bridge support." })), "card_image_url": Schema.optionalKey(Schema.String.annotate({ "description": "An expiring URL used to render the card image, with a validity period of 5 minutes. _Note:_ This field will be deprecated in favor of the more secure and scalable card details API. Please see the integration guide on [safely revealing card details](https://apidocs.bridge.xyz/docs/safely-reveal-card-details-to-customers) for more information." })), "status": Schema.Literals(["active", "pending", "inactive", "frozen"]).annotate({ "description": "Status of the card account" }), "status_reason": Schema.optionalKey(Schema.String.annotate({ "description": "An optional detailed explanation for the card account status" })), "card_details": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "last_4": Schema.String.annotate({ "description": "The last four digits of the card number", "examples": ["1264"] }), "expiry": Schema.String.annotate({ "description": "The expiration date of the card, in MM/YY format", "examples": ["10/24"] }), "bin": Schema.String.annotate({ "description": "The BIN of the card, including the first 8 digits", "examples": ["44325280"] }), "pin_status": Schema.optionalKey(Schema.Literals(["not_set", "ok"]).annotate({ "description": "The current status of the card PIN" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Details of the issued card. This object contains enough payment card details to identify the issued card, but only provides the last four digits of the card number to maintain security." })), "balances": Schema.StructWithRest(Schema.Struct({ "available": Schema.StructWithRest(Schema.Struct({ "amount": Schema.String, "currency": Schema.Literal("usdc") }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "The available balance of the card account" }), "hold": Schema.StructWithRest(Schema.Struct({ "amount": Schema.String, "currency": Schema.Literal("usdc") }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "The balance tha is placed on hold for pending authorizations" }) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Balances of the card account" }), "freezes": Schema.Array(Schema.StructWithRest(Schema.Struct({ "initiator": Schema.Literal("bridge").annotate({ "description": "The party that initiated the freeze. Card account responses also include freezes initiated by Bridge." }), "card_account_id": Schema.String.annotate({ "description": "Card account ID" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" })), "reason": Schema.Literals(["lost_or_stolen", "suspicious_activity", "planned_inactivity", "suspected_fraud", "other"]).annotate({ "description": "The reason of the freeze" }), "reason_detail": Schema.optionalKey(Schema.String.annotate({ "description": "A more detailed reason for the freeze" })), "starting_at": Schema.optionalKey(Schema.String.annotate({ "description": "The start time of the freeze, in ISO8601 format" })), "ending_at": Schema.optionalKey(Schema.String.annotate({ "description": "The end time of the freeze, in ISO8601 format" })), "created_at": Schema.String.annotate({ "description": "The creation time of the freeze, in ISO8601 format", "readOnly": true }), "status": Schema.Json.annotate({ "expected": "JSON value" }) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Card freeze" })).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" })), "stripe_card_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "The [Stripe Issuing card ID](https://docs.stripe.com/api/issuing/cards/object?issuing_card_object-id), if the card account is backed by Stripe Issuing" })), "crypto_account": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "type": Schema.Literals(["standard", "bridge_wallet", "noncustodial_ata"]).annotate({ "description": "The type of the crypto account" }), "address": Schema.String.annotate({ "description": "The public address of the crypto account" }) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "The crypto account for a self-custodial card account. This field is not supported for a Bridge-custodial card funding setup (note that if you are on cards trial, you are automatically on a custodial funding setup)." })), "funding_instructions": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "currency": Schema.Literal("usdc").annotate({ "description": "The crypto currency used by the card account" }), "chain": Schema.Literals(["arbitrum", "avalanche_c_chain", "base", "ethereum", "optimism", "polygon", "solana", "stellar"]).annotate({ "description": "The chain used by the card account" }), "address": Schema.String.annotate({ "description": "The deposit address provided by Bridge to fund the card account" }), "memo": Schema.optionalKey(Schema.String.annotate({ "description": "If present, this is the message that the customer MUST include in their on-chain funding transfers. It is only applicable to memo-based blockchains such as Stellar and Tron" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Funding instructions applicable only to the top-up card funding strategy, which is configured at the developer level" })), "additional_funding_instructions": Schema.optionalKey(Schema.Array(Schema.StructWithRest(Schema.Struct({ "currency": Schema.Literal("usdc").annotate({ "description": "The crypto currency used by the card account" }), "chain": Schema.Literals(["arbitrum", "avalanche_c_chain", "base", "ethereum", "optimism", "polygon", "solana", "stellar"]).annotate({ "description": "The chain used by the card account" }), "address": Schema.String.annotate({ "description": "The deposit address provided by Bridge to fund the card account" }), "memo": Schema.optionalKey(Schema.String.annotate({ "description": "If present, this is the message that the customer MUST include in their on-chain funding transfers. It is only applicable to memo-based blockchains such as Stellar and Tron" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Funding instructions applicable only to the top-up card funding strategy, which is configured at the developer level" })).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" }))) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "identifier": "CardAccount" }) +export type PostCardAccountsInput = { readonly "client_reference_id"?: string, readonly "currency": "usdc", readonly "chain": "arbitrum" | "avalanche_c_chain" | "base" | "ethereum" | "optimism" | "polygon" | "solana" | "stellar", readonly "crypto_account"?: { readonly "type": "standard" | "bridge_wallet" | "noncustodial_ata", readonly "address": string } & { readonly [x: string]: Schema.Json }, readonly "card_design_shortname"?: string } & { readonly [x: string]: Schema.Json } +export const PostCardAccountsInput = Schema.StructWithRest(Schema.Struct({ "client_reference_id": Schema.optionalKey(Schema.String.annotate({ "description": "An optional client-provided reference ID that uniquely identifies the card account in the client's system" })), "currency": Schema.Literal("usdc").annotate({ "description": "Crypto currency used by the card account being created" }), "chain": Schema.Literals(["arbitrum", "avalanche_c_chain", "base", "ethereum", "optimism", "polygon", "solana", "stellar"]).annotate({ "description": "Chain used by the card account being created" }), "crypto_account": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "type": Schema.Literals(["standard", "bridge_wallet", "noncustodial_ata"]).annotate({ "description": "The type of the crypto account" }), "address": Schema.String.annotate({ "description": "The public address of the crypto account" }) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "The crypto account for a self-custodial card account. This field is not supported for a Bridge-custodial card funding setup (note that if you are on cards trial, you are automatically on a custodial funding setup)." })), "card_design_shortname": Schema.optionalKey(Schema.String.annotate({ "description": "The shortname of the card design to use for the card account. If not specified, the default card design will be used." })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "identifier": "PostCardAccountsInput" }) +export type PostCardFreezeInput = { readonly "initiator": "developer" | "customer", readonly "reason": "lost_or_stolen" | "suspicious_activity" | "planned_inactivity" | "suspected_fraud" | "other", readonly "reason_detail"?: string, readonly "starting_at"?: string, readonly "ending_at"?: string } & { readonly [x: string]: Schema.Json } +export const PostCardFreezeInput = Schema.StructWithRest(Schema.Struct({ "initiator": Schema.Literals(["developer", "customer"]).annotate({ "description": "The party that initiated the freeze. A freeze can be initiated by either the customer or developer. Only one freeze per initiator can be active at a time. If a new freeze is initiated by the same party, it overwrites any existing freeze" }), "reason": Schema.Literals(["lost_or_stolen", "suspicious_activity", "planned_inactivity", "suspected_fraud", "other"]).annotate({ "description": "The reason of the freeze" }), "reason_detail": Schema.optionalKey(Schema.String.annotate({ "description": "A more detailed reason for the freeze" })), "starting_at": Schema.optionalKey(Schema.String.annotate({ "description": "An optional starting time in ISO8601 format. It defaults to the current date-time if unspecified" })), "ending_at": Schema.optionalKey(Schema.String.annotate({ "description": "An optional ending time in ISO8601 format. If this ending time is not specified, the card account will stay frozen indefinitely until it gets unfrozen by another request" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "identifier": "PostCardFreezeInput" }) +export type PostCardUnfreezeInput = { readonly "initiator": "developer" | "customer" } & { readonly [x: string]: Schema.Json } +export const PostCardUnfreezeInput = Schema.StructWithRest(Schema.Struct({ "initiator": Schema.Literals(["developer", "customer"]).annotate({ "description": "The party that initiated the freeze. A freeze can be initiated by either the customer or developer. Only one freeze per initiator can be active at a time. If a new freeze is initiated by the same party, it overwrites any existing freeze" }) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "identifier": "PostCardUnfreezeInput" }) +export type CardUnfreezeResponse = { readonly "card_account_id": string, readonly "initiator": "developer" | "customer" | "bridge", readonly "reason": "lost_or_stolen" | "suspicious_activity" | "planned_inactivity" | "suspected_fraud" | "other", readonly "created_at": string, readonly "status": "freeze_removed", readonly "reason_detail"?: string, readonly "starting_at"?: string, readonly "ending_at"?: string } & { readonly [x: string]: Schema.Json } +export const CardUnfreezeResponse = Schema.StructWithRest(Schema.Struct({ "card_account_id": Schema.String.annotate({ "description": "Card account ID" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" })), "initiator": Schema.Literals(["developer", "customer", "bridge"]).annotate({ "description": "The initiator of the removed freeze" }), "reason": Schema.Literals(["lost_or_stolen", "suspicious_activity", "planned_inactivity", "suspected_fraud", "other"]).annotate({ "description": "The reason of the removed freeze" }), "created_at": Schema.String.annotate({ "description": "The creation time of the removed freeze, in ISO8601 format", "readOnly": true }), "status": Schema.Literal("freeze_removed").annotate({ "description": "The processing status of the unfreeze request", "readOnly": true }), "reason_detail": Schema.optionalKey(Schema.String.annotate({ "description": "The reason detail of the removed freeze" })), "starting_at": Schema.optionalKey(Schema.String.annotate({ "description": "The start time of the removed freeze, in ISO8601 format" })), "ending_at": Schema.optionalKey(Schema.String.annotate({ "description": "The end time of the removed freeze, in ISO8601 format" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Card freeze", "identifier": "CardUnfreezeResponse" }) +export type PostCardPushProvisioningInput = { readonly "wallet_provider"?: "apple_pay" | "google_pay", readonly "apple_pay"?: { readonly "encoding"?: "base64" | "hex", readonly "leaf_cert": string, readonly "subordinate_cert": string, readonly "nonce": string, readonly "nonce_signature": string } & { readonly [x: string]: Schema.Json }, readonly "google_pay"?: { readonly "client_wallet_account_id": string, readonly "client_device_id": string } & { readonly [x: string]: Schema.Json }, readonly "initiator": Schema.Json } & { readonly [x: string]: Schema.Json } +export const PostCardPushProvisioningInput = Schema.StructWithRest(Schema.Struct({ "wallet_provider": Schema.optionalKey(Schema.Literals(["apple_pay", "google_pay"]).annotate({ "description": "The mobile wallet provider" })), "apple_pay": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "encoding": Schema.optionalKey(Schema.Literals(["base64", "hex"]).annotate({ "description": "Specifies the encoding of each field in the Apple Pay provisioning request. Defaults to `hex` if unspecified." })), "leaf_cert": Schema.String.annotate({ "description": "The leaf certificate returned by the wallet provider that was signed using the subordinate cert. The binary data of this certificate should be hex (case-insensitive) or base64 encoded, as specified by the encoding field" }), "subordinate_cert": Schema.String.annotate({ "description": "The subordinate certificate returned by the wallet provider that was signed using the wallet provider's Certificate Authority (CA) certificate. The binary data of this certificate should be hex (case-insensitive) or base64 encoded, as specified by the encoding field" }), "nonce": Schema.String.annotate({ "description": "The nonce value returned by Apple Pay. It should be hex (case-insensitive) or base64 encoded, as specified by the encoding field" }), "nonce_signature": Schema.String.annotate({ "description": "The nonce signature value returned by Apple Pay. It should be hex (case-insensitive) or base64 encoded, as specified by the encoding field" }) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Apple Pay specific provisioning request data. Required for `apple_pay` wallet provider." })), "google_pay": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "client_wallet_account_id": Schema.String.annotate({ "description": "Value returned by Google Pay for use with Visa" }), "client_device_id": Schema.String.annotate({ "description": "Value returned by Google Pay for use with Visa" }) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Google Pay specific push provisioning request data. Required for `google_pay` wallet provider." })), "initiator": Schema.Json.annotate({ "expected": "JSON value" }) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "identifier": "PostCardPushProvisioningInput" }) +export type CardPushProvisioningResponse = { readonly "wallet_provider"?: "apple_pay" | "google_pay", readonly "apple_pay"?: { readonly "activation_data"?: string, readonly "encrypted_pass_data"?: string, readonly "ephemeral_public_key"?: string } & { readonly [x: string]: Schema.Json }, readonly "google_pay"?: { readonly "opaque_payment_card"?: string } & { readonly [x: string]: Schema.Json }, readonly "card_account_id": Schema.Json, readonly "initiator": Schema.Json, readonly "reason": Schema.Json, readonly "created_at": Schema.Json, readonly "status": Schema.Json } & { readonly [x: string]: Schema.Json } +export const CardPushProvisioningResponse = Schema.StructWithRest(Schema.Struct({ "wallet_provider": Schema.optionalKey(Schema.Literals(["apple_pay", "google_pay"]).annotate({ "description": "The mobile wallet provider" })), "apple_pay": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "activation_data": Schema.optionalKey(Schema.String.annotate({ "description": "The request's activation data. This field is always Base64-encoded" })), "encrypted_pass_data": Schema.optionalKey(Schema.String.annotate({ "description": "An encrypted JSON file containing the sensitive information needed to add a card to a wallet. This field is always Base64-encoded" })), "ephemeral_public_key": Schema.optionalKey(Schema.String.annotate({ "description": "A generated key that is combined with a private key. This field is always Base64-encoded" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "The detailed provisioning request data that need to be sent directly to the `apple_pay` wallet provider" })), "google_pay": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "opaque_payment_card": Schema.optionalKey(Schema.String.annotate({ "description": "A Base64-encoded or Base64url-encoded opaque string" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "The detailed provisioning request data that need to be sent directly to the `google_pay` wallet provider" })), "card_account_id": Schema.Json.annotate({ "expected": "JSON value" }), "initiator": Schema.Json.annotate({ "expected": "JSON value" }), "reason": Schema.Json.annotate({ "expected": "JSON value" }), "created_at": Schema.Json.annotate({ "expected": "JSON value" }), "status": Schema.Json.annotate({ "expected": "JSON value" }) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "The mobile wallet push provisioning response", "identifier": "CardPushProvisioningResponse" }) +export type CardAuthorization = { readonly "id": string, readonly "amount": string, readonly "billing_amount"?: string, readonly "currency": "usd", readonly "merchant_category_code": string, readonly "description": string, readonly "authorized_at": string, readonly "details": { readonly "vendor_auth_id"?: string } & { readonly [x: string]: Schema.Json }, readonly "local_transaction_details"?: { readonly "amount": string, readonly "currency": string, readonly "exchange_rate": string } & { readonly [x: string]: Schema.Json }, readonly "verification_data"?: { readonly "address_check"?: "match" | "not_provided" | "mismatch", readonly "address_postal_code_check"?: "match" | "not_provided" | "mismatch", readonly "cvv_check"?: "match" | "not_provided" | "mismatch", readonly "pin_check"?: "verified" | "failed" | "locked" | "not_set" | "blocked" | "no_pin_passed" | "unknown", readonly "three_d_secure_check"?: "attempt_acknowledged" | "authenticated" | "failed" | "required" }, readonly "stripe_issuing_authorization_id"?: string | null, readonly "stripe_authorization_code"?: string | null } & { readonly [x: string]: Schema.Json } +export const CardAuthorization = Schema.StructWithRest(Schema.Struct({ "id": Schema.String.annotate({ "description": "ID of the pending authorization" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" })), "amount": Schema.String.annotate({ "description": "The amount represented as a decimal string" }), "billing_amount": Schema.optionalKey(Schema.String.annotate({ "description": "The billing amount, represented as a decimal string. The billing amount is the amount of the transaction excluding any additional hold. This amount should be present on all purchases, but will only differ from the amount field for some merchant categories in which an upcharge is involved (e.g. gas stations, hotels)." })), "currency": Schema.Literal("usd").annotate({ "description": "The currency of the transaction" }), "merchant_category_code": Schema.String.annotate({ "description": "A merchant category code for card transactions (e.g., '5712')" }), "description": Schema.String.annotate({ "description": "A description of the card transaction, including the merchant's name and location information" }), "authorized_at": Schema.String.annotate({ "description": "Timestamp when the card transaction was authorized, in ISO8601 format" }), "details": Schema.StructWithRest(Schema.Struct({ "vendor_auth_id": Schema.optionalKey(Schema.String.annotate({ "description": "ID in the vendor system used to identify this authorized card transaction" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]), "local_transaction_details": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "amount": Schema.String.annotate({ "description": "The amount in local currency, represented as a decimal string" }), "currency": Schema.String.annotate({ "description": "The transaction's local currency" }), "exchange_rate": Schema.String.annotate({ "description": "The exchange rate applied to convert the local currency amount into USD for the transaction" }) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Details of a transaction processed in a local currency other than USD, with currency conversion applied" })), "verification_data": Schema.optionalKey(Schema.Struct({ "address_check": Schema.optionalKey(Schema.Literals(["match", "not_provided", "mismatch"]).annotate({ "description": "Whether the cardholder provided an address and if it matched the cardholder’s address on file." })), "address_postal_code_check": Schema.optionalKey(Schema.Literals(["match", "not_provided", "mismatch"]).annotate({ "description": "Whether the cardholder provided a postal code and if it matched the cardholder’s postal code on file." })), "cvv_check": Schema.optionalKey(Schema.Literals(["match", "not_provided", "mismatch"]).annotate({ "description": "Whether the cardholder provided a CVV and if it matched the CVV on record." })), "pin_check": Schema.optionalKey(Schema.Literals(["verified", "failed", "locked", "not_set", "blocked", "no_pin_passed", "unknown"]).annotate({ "description": "Whether the cardholder provided a PIN and if it matched the PIN on record." })), "three_d_secure_check": Schema.optionalKey(Schema.Literals(["attempt_acknowledged", "authenticated", "failed", "required"]).annotate({ "description": "The results of the 3DS authentication attempt for this authorization, if applicable." })) }).annotate({ "description": "Information on verifications that were performed on information that the cardholder provided to the merchant." })), "stripe_issuing_authorization_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "The [Stripe Issuing authorization ID](https://docs.stripe.com/api/issuing/authorizations/object#issuing_authorization_object-id), if the authorization is backed by Stripe Issuing" })), "stripe_authorization_code": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "The network-assigned [authorization code](https://docs.corp.stripe.com/api/issuing/authorizations/object#issuing_authorization_object-request_history-authorization_code) for this request, if the authorization is backed by Stripe Issuing" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "A pending card authorization", "identifier": "CardAuthorization" }) +export type CardTransaction = { readonly "id": string, readonly "card_account_id"?: string, readonly "customer_id"?: string, readonly "category": "adjustment" | "fee" | "purchase" | "refund" | "crypto_funding" | "crypto_return" | "crypto_withdrawal", readonly "amount": string, readonly "billing_amount"?: string, readonly "currency": "usd" | "usdc", readonly "merchant_category_code"?: string, readonly "merchant_name"?: string, readonly "merchant_location"?: string, readonly "description": string, readonly "local_transaction_details"?: { readonly "amount": string, readonly "currency": string, readonly "exchange_rate": string } & { readonly [x: string]: Schema.Json }, readonly "posted_at": string, readonly "authorized_at"?: string, readonly "status"?: "pending" | "posted", readonly "crypto_transaction_details"?: { readonly "from_address"?: string, readonly "to_address"?: string, readonly "tx_hash"?: string, readonly "chain"?: "arbitrum" | "avalanche_c_chain" | "base" | "ethereum" | "optimism" | "polygon" | "solana" | "stellar" | "tron", readonly "memo"?: string } & { readonly [x: string]: Schema.Json }, readonly "related_transaction_ids"?: ReadonlyArray, readonly "stripe_issuing_transaction_id"?: string | null } & { readonly [x: string]: Schema.Json } +export const CardTransaction = Schema.StructWithRest(Schema.Struct({ "id": Schema.String.annotate({ "description": "ID of the transaction" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" })), "card_account_id": Schema.optionalKey(Schema.String.annotate({ "description": "ID of the card account associated to this transaction" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "customer_id": Schema.optionalKey(Schema.String.annotate({ "description": "ID of the customer of the card account associated to this transaction" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "category": Schema.Literals(["adjustment", "fee", "purchase", "refund", "crypto_funding", "crypto_return", "crypto_withdrawal"]).annotate({ "description": "The category of the transaction" }), "amount": Schema.String.annotate({ "description": "The amount represented as a decimal string" }), "billing_amount": Schema.optionalKey(Schema.String.annotate({ "description": "The billing amount, represented as a decimal string. The billing amount is the amount of the transaction excluding any additional hold. This amount should be present on all purchases, but will only differ from the amount field for some merchant categories in which an upcharge is involved (e.g. gas stations, hotels)." })), "currency": Schema.Literals(["usd", "usdc"]).annotate({ "description": "The currency of the transaction" }), "merchant_category_code": Schema.optionalKey(Schema.String.annotate({ "description": "The merchant category code, if applicable (e.g., '5712'). Always returned for transactions with category `purchase` or `refund`" })), "merchant_name": Schema.optionalKey(Schema.String.annotate({ "description": "The merchant name, if applicable. Always returned for transactions with category `purchase` or `refund`" })), "merchant_location": Schema.optionalKey(Schema.String.annotate({ "description": "The merchant location, if applicable. Always returned for transactions with category `purchase` or `refund`" })), "description": Schema.String.annotate({ "description": "The transaction description. It includes the merchant's name and location information for card transactions" }), "local_transaction_details": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "amount": Schema.String.annotate({ "description": "The amount in local currency, represented as a decimal string" }), "currency": Schema.String.annotate({ "description": "The transaction's local currency" }), "exchange_rate": Schema.String.annotate({ "description": "The exchange rate applied to convert the local currency amount into USD for the transaction" }) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Details of a transaction processed in a local currency other than USD, with currency conversion applied" })), "posted_at": Schema.String.annotate({ "description": "Timestamp when the transaction was posted, in ISO8601 format" }), "authorized_at": Schema.optionalKey(Schema.String.annotate({ "description": "Timestamp when the transaction was authorized, in ISO8601 format. Applicable only to transactions with category `purchase` or `refund` and always returned when applicable" })), "status": Schema.optionalKey(Schema.Literals(["pending", "posted"]).annotate({ "description": "The status of the transaction" })), "crypto_transaction_details": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "from_address": Schema.optionalKey(Schema.String.annotate({ "description": "The source blockchain address of the crypto transaction. Present for crypto funding transactions" })), "to_address": Schema.optionalKey(Schema.String.annotate({ "description": "The destination blockchain address of the crypto transaction" })), "tx_hash": Schema.optionalKey(Schema.String.annotate({ "description": "The blockchain transaction hash" })), "chain": Schema.optionalKey(Schema.Literals(["arbitrum", "avalanche_c_chain", "base", "ethereum", "optimism", "polygon", "solana", "stellar", "tron"]).annotate({ "description": "The blockchain network on which the transaction occurred" })), "memo": Schema.optionalKey(Schema.String.annotate({ "description": "An optional memo associated with the crypto transaction, if applicable" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Details of the underlying crypto transaction for crypto funding, withdrawal, or return transactions" })), "related_transaction_ids": Schema.optionalKey(Schema.Array(Schema.String).annotate({ "description": "IDs of related card transactions" })), "stripe_issuing_transaction_id": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "The [Stripe Issuing transaction ID](https://docs.stripe.com/api/issuing/transactions/object?issuing_transaction_object-id), if the transaction is backed by Stripe Issuing" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "A posted transaction", "identifier": "CardTransaction" }) +export type CardSpendingLimit = { readonly "period": "daily" | "trial_lifetime", readonly "timezone"?: string, readonly "next_reset_at"?: string, readonly "total_amount": string, readonly "remaining_amount": string, readonly "currency"?: "usd" } & { readonly [x: string]: Schema.Json } +export const CardSpendingLimit = Schema.StructWithRest(Schema.Struct({ "period": Schema.Literals(["daily", "trial_lifetime"]).annotate({ "description": "The period of the spending limit" }), "timezone": Schema.optionalKey(Schema.String.annotate({ "description": "The timezone of the spending limit, only applicable to spending limits that have a `next_reset_at`" })), "next_reset_at": Schema.optionalKey(Schema.String.annotate({ "description": "The next reset time of the spending limit, in ISO8601 format" })), "total_amount": Schema.String.annotate({ "description": "The total amount of the spending limit" }), "remaining_amount": Schema.String.annotate({ "description": "The remaining amount of the spending limit" }), "currency": Schema.optionalKey(Schema.Literal("usd").annotate({ "description": "The currency of the spending limit" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "A spending limit for a card account", "identifier": "CardSpendingLimit" }) +export type PostCardAccountDepositAddressInput = { readonly "chain": "arbitrum" | "avalanche_c_chain" | "base" | "ethereum" | "optimism" | "polygon" | "solana" | "stellar" } & { readonly [x: string]: Schema.Json } +export const PostCardAccountDepositAddressInput = Schema.StructWithRest(Schema.Struct({ "chain": Schema.Union([Schema.Literal("arbitrum").annotate({ "description": "The chain to provision the new deposit address on." }), Schema.Literal("avalanche_c_chain").annotate({ "description": "The chain to provision the new deposit address on." }), Schema.Literal("base").annotate({ "description": "The chain to provision the new deposit address on." }), Schema.Literal("ethereum").annotate({ "description": "The chain to provision the new deposit address on." }), Schema.Literal("optimism").annotate({ "description": "The chain to provision the new deposit address on." }), Schema.Literal("polygon").annotate({ "description": "The chain to provision the new deposit address on." }), Schema.Literal("solana").annotate({ "description": "The chain to provision the new deposit address on." }), Schema.Literal("stellar").annotate({ "description": "The chain to provision the new deposit address on." })]) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "The details of the new deposit address to be provisioned.", "identifier": "PostCardAccountDepositAddressInput" }) +export type CardAccountFundingInstructions = { readonly "currency": "usdc", readonly "chain": "arbitrum" | "avalanche_c_chain" | "base" | "ethereum" | "optimism" | "polygon" | "solana" | "stellar", readonly "address": string, readonly "memo"?: string } & { readonly [x: string]: Schema.Json } +export const CardAccountFundingInstructions = Schema.StructWithRest(Schema.Struct({ "currency": Schema.Literal("usdc").annotate({ "description": "The crypto currency used by the card account" }), "chain": Schema.Literals(["arbitrum", "avalanche_c_chain", "base", "ethereum", "optimism", "polygon", "solana", "stellar"]).annotate({ "description": "The chain used by the card account" }), "address": Schema.String.annotate({ "description": "The deposit address provided by Bridge to fund the card account" }), "memo": Schema.optionalKey(Schema.String.annotate({ "description": "If present, this is the message that the customer MUST include in their on-chain funding transfers. It is only applicable to memo-based blockchains such as Stellar and Tron" })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Funding instructions applicable only to the top-up card funding strategy, which is configured at the developer level", "identifier": "CardAccountFundingInstructions" }) +export type CardWithdrawal = { readonly "id": string, readonly "card_account_id": string, readonly "customer_id": string, readonly "amount": string, readonly "type"?: "top_up_balance_withdrawal" | "fee", readonly "currency": "usdc", readonly "destination": { readonly "chain": string, readonly "address": string, readonly "memo"?: string, readonly "tx_hash"?: string, readonly "gas_fee"?: { readonly "amount": string, readonly "currency": string } & { readonly [x: string]: Schema.Json } } & { readonly [x: string]: Schema.Json }, readonly "client_note"?: string, readonly "created_at": string, readonly "updated_at": string } & { readonly [x: string]: Schema.Json } +export const CardWithdrawal = Schema.StructWithRest(Schema.Struct({ "id": Schema.String.annotate({ "description": "ID of the withdrawal", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" })), "card_account_id": Schema.String.annotate({ "description": "ID of the card account associated with the withdrawal", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" })), "customer_id": Schema.String.annotate({ "description": "ID of the customer who owns the card account", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" })), "amount": Schema.String.annotate({ "description": "The amount represented as a decimal string" }), "type": Schema.optionalKey(Schema.Literals(["top_up_balance_withdrawal", "fee"]).annotate({ "description": "The type of the withdrawal. Defaults to `top_up_balance_withdrawal`." })), "currency": Schema.Literal("usdc").annotate({ "description": "The currency of the withdrawal, which is the crypto currency on the card account", "readOnly": true }), "destination": Schema.StructWithRest(Schema.Struct({ "chain": Schema.String.annotate({ "description": "The chain of the wallet the withdrawn crypto funds should be transferred to" }), "address": Schema.String.annotate({ "description": "The address of the wallet the withdrawn crypto funds should be transferred to" }), "memo": Schema.optionalKey(Schema.String.annotate({ "description": "The memo to attach to the withdrawal transaction. Will be transmitted for blockchains that support memos only." })), "tx_hash": Schema.optionalKey(Schema.String.annotate({ "description": "The crypto transaction hash for the withdrawal once it's confirmed on the chain", "readOnly": true })), "gas_fee": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "amount": Schema.String.annotate({ "description": "The amount of the gas fee represented as a decimal string", "readOnly": true }), "currency": Schema.String.annotate({ "description": "The currency of the gas fee.", "readOnly": true }) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "The gas fee for the withdrawal transaction. Note that this is the representation of the native gas fee of the onchain transaction, which may be different from the fiat-converted gas fee charged on the invoice." })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]), "client_note": Schema.optionalKey(Schema.String.annotate({ "description": "An optional client-provided note for the withdrawal" })), "created_at": Schema.String.annotate({ "description": "Timestamp when the withdrawal was created, in ISO8601 format", "readOnly": true }), "updated_at": Schema.String.annotate({ "description": "Timestamp when the withdrawal was last updated, in ISO8601 format", "readOnly": true }) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "A card funds withdrawal", "identifier": "CardWithdrawal" }) +export type DeveloperFeeConfig = { readonly "id": string, readonly "name": string, readonly "schema": "v1", readonly "default_fee_percentage": string, readonly "source_asset_fee": { readonly [x: string]: string }, readonly "description"?: string | null, readonly "created_at": string, readonly "updated_at": string } & { readonly [x: string]: Schema.Json } +export const DeveloperFeeConfig = Schema.StructWithRest(Schema.Struct({ "id": Schema.String.annotate({ "description": "A UUID that uniquely identifies a resource", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" })), "name": Schema.String.annotate({ "description": "A friendly name for this fee config." }), "schema": Schema.Literal("v1").annotate({ "description": "The schema version for this fee config. Currently only `v1` is supported." }), "default_fee_percentage": Schema.String.annotate({ "description": "The default developer fee percent applied by this config. The value is a base 100 percentage, i.e. 10.2% is 10.2 in the API.", "examples": ["0.1"], "format": "number" }), "source_asset_fee": Schema.Record(Schema.String, Schema.String).annotate({ "description": "Per-source-currency fee overrides applied instead of `default_fee_percentage`. Keys are `CryptoCurrency` values, values are base 100 percentages, e.g. `{\"usdc\": \"0.05\"}` charges a 0.05% fee on USDC deposits.", "examples": [{ "usdc": "0.05", "usdt": "0.2" }] }), "description": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "An optional longer description of this fee config." })), "created_at": Schema.String.annotate({ "description": "Time of creation of the Developer Fee Config", "readOnly": true, "format": "date-time" }), "updated_at": Schema.String.annotate({ "description": "Time of most recent update of the Developer Fee Config", "readOnly": true, "format": "date-time" }) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "identifier": "DeveloperFeeConfig" }) +export type CreateDeveloperFeeConfig = { readonly "name": string, readonly "schema": "v1", readonly "default_fee_percentage": string, readonly "source_asset_fee"?: { readonly [x: string]: string }, readonly "description"?: string } & { readonly [x: string]: Schema.Json } +export const CreateDeveloperFeeConfig = Schema.StructWithRest(Schema.Struct({ "name": Schema.String.annotate({ "description": "A friendly name for this fee config." }), "schema": Schema.Literal("v1").annotate({ "description": "The schema version for this fee config. Currently only `v1` is supported." }), "default_fee_percentage": Schema.String.annotate({ "description": "The default developer fee percent applied by this config. The value is a base 100 percentage, i.e. 10.2% is 10.2 in the API.", "examples": ["0.1"], "format": "number" }), "source_asset_fee": Schema.optionalKey(Schema.Record(Schema.String, Schema.String).annotate({ "description": "Per-source-currency fee overrides applied instead of `default_fee_percentage`. Keys are `CryptoCurrency` values, values are base 100 percentages, e.g. `{\"usdc\": \"0.05\"}` charges a 0.05% fee on USDC deposits.", "examples": [{ "usdc": "0.05", "usdt": "0.2" }] })), "description": Schema.optionalKey(Schema.String.annotate({ "description": "An optional longer description of this fee config." })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "identifier": "CreateDeveloperFeeConfig" }) +export type UpdateDeveloperFeeConfig = { readonly "name": string, readonly "schema": "v1", readonly "default_fee_percentage": string, readonly "source_asset_fee"?: { readonly [x: string]: string }, readonly "description"?: string } & { readonly [x: string]: Schema.Json } +export const UpdateDeveloperFeeConfig = Schema.StructWithRest(Schema.Struct({ "name": Schema.String.annotate({ "description": "A friendly name for this fee config." }), "schema": Schema.Literal("v1").annotate({ "description": "The schema version for this fee config. Currently only `v1` is supported." }), "default_fee_percentage": Schema.String.annotate({ "description": "The default developer fee percent applied by this config. The value is a base 100 percentage, i.e. 10.2% is 10.2 in the API.", "examples": ["0.1"], "format": "number" }), "source_asset_fee": Schema.optionalKey(Schema.Record(Schema.String, Schema.String).annotate({ "description": "Per-source-currency fee overrides applied instead of `default_fee_percentage`. Keys are `CryptoCurrency` values, values are base 100 percentages, e.g. `{\"usdc\": \"0.05\"}` charges a 0.05% fee on USDC deposits.", "examples": [{ "usdc": "0.05", "usdt": "0.2" }] })), "description": Schema.optionalKey(Schema.String.annotate({ "description": "An optional longer description of this fee config." })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "identifier": "UpdateDeveloperFeeConfig" }) +export type DeveloperRewardSummary = { readonly "developer_id"?: string, readonly "currency"?: string, readonly "balance"?: string, readonly "rewards"?: string, readonly "updated_at"?: string } +export const DeveloperRewardSummary = Schema.Struct({ "developer_id": Schema.optionalKey(Schema.String.annotate({ "description": "The developer ID of the developer" })), "currency": Schema.optionalKey(Schema.String.annotate({ "description": "The stablecoin symbol for the reward summary" })), "balance": Schema.optionalKey(Schema.String.annotate({ "description": "The balance of the developer in the given stablecoin" })), "rewards": Schema.optionalKey(Schema.String.annotate({ "description": "The rewards of the developer in the given stablecoin" })), "updated_at": Schema.optionalKey(Schema.String.annotate({ "description": "The timestamp of the last update to the reward summary, in ISO8601 format" })) }).annotate({ "title": "Reward Summary for a given stablecoin", "identifier": "DeveloperRewardSummary" }) +export type DeveloperRewardHistory = { readonly "currency"?: string, readonly "developer_id"?: string, readonly "reserves_currency"?: string, readonly "data"?: ReadonlyArray<{ readonly "date"?: string, readonly "distributed"?: boolean, readonly "total"?: { readonly "aum"?: string, readonly "developer_rewards"?: string, readonly "net_rewards"?: string, readonly "bridge_fee_bps"?: string, readonly "bridge_fee"?: string, readonly "annualized_yield_bps"?: string }, readonly "providers"?: ReadonlyArray<{ readonly "provider"?: string, readonly "aum"?: string, readonly "developer_rewards"?: string, readonly "annualized_yield_bps"?: string }> }>, readonly "pagination"?: { readonly "has_more"?: boolean, readonly "next_cursor"?: string | null } } +export const DeveloperRewardHistory = Schema.Struct({ "currency": Schema.optionalKey(Schema.String.annotate({ "description": "The stablecoin symbol" })), "developer_id": Schema.optionalKey(Schema.String.annotate({ "description": "The developer ID" })), "reserves_currency": Schema.optionalKey(Schema.String.annotate({ "description": "The denomination currency for all monetary amounts" })), "data": Schema.optionalKey(Schema.Array(Schema.Struct({ "date": Schema.optionalKey(Schema.String.annotate({ "description": "The reward calculation date (YYYY-MM-DD)" })), "distributed": Schema.optionalKey(Schema.Boolean.annotate({ "description": "Whether rewards for this date have been distributed" })), "total": Schema.optionalKey(Schema.Struct({ "aum": Schema.optionalKey(Schema.String.annotate({ "description": "Developer AUM across all providers" })), "developer_rewards": Schema.optionalKey(Schema.String.annotate({ "description": "Gross rewards (net of premint yield)" })), "net_rewards": Schema.optionalKey(Schema.String.annotate({ "description": "Net rewards after fees" })), "bridge_fee_bps": Schema.optionalKey(Schema.String.annotate({ "description": "Effective fee rate for that day" })), "bridge_fee": Schema.optionalKey(Schema.String.annotate({ "description": "Fee amount for that day" })), "annualized_yield_bps": Schema.optionalKey(Schema.String.annotate({ "description": "Blended annualized yield across providers" })) })), "providers": Schema.optionalKey(Schema.Array(Schema.Struct({ "provider": Schema.optionalKey(Schema.String.annotate({ "description": "Provider identifier" })), "aum": Schema.optionalKey(Schema.String.annotate({ "description": "Developer AUM held at this provider" })), "developer_rewards": Schema.optionalKey(Schema.String.annotate({ "description": "Gross rewards from this provider" })), "annualized_yield_bps": Schema.optionalKey(Schema.String.annotate({ "description": "Annualized yield rate for this provider" })) }))) }))), "pagination": Schema.optionalKey(Schema.Struct({ "has_more": Schema.optionalKey(Schema.Boolean.annotate({ "description": "Whether more pages are available" })), "next_cursor": Schema.optionalKey(Schema.Union([Schema.String, Schema.Null]).annotate({ "description": "Cursor for the next page" })) })) }).annotate({ "title": "Developer Daily Reward History", "identifier": "DeveloperRewardHistory" }) +export type CustomerRewardSummary = { readonly "developer_id"?: string, readonly "customer_id"?: string, readonly "currency"?: string, readonly "balance"?: string, readonly "rewards"?: string, readonly "updated_at"?: string } +export const CustomerRewardSummary = Schema.Struct({ "developer_id": Schema.optionalKey(Schema.String.annotate({ "description": "The developer ID of the customer" })), "customer_id": Schema.optionalKey(Schema.String.annotate({ "description": "The customer ID of the customer" })), "currency": Schema.optionalKey(Schema.String.annotate({ "description": "The stablecoin symbol for the reward summary" })), "balance": Schema.optionalKey(Schema.String.annotate({ "description": "The balance of the customer in the given stablecoin" })), "rewards": Schema.optionalKey(Schema.String.annotate({ "description": "The rewards of the customer in the given stablecoin" })), "updated_at": Schema.optionalKey(Schema.String.annotate({ "description": "The timestamp of the last update to the reward summary, in ISO8601 format" })) }).annotate({ "title": "Customer Reward Summary for a given stablecoin", "identifier": "CustomerRewardSummary" }) +export type CustomerRewardHistory = { readonly "customer_id"?: string, readonly "rewards"?: ReadonlyArray<{ readonly "balance"?: string, readonly "amount"?: string, readonly "currency"?: string, readonly "date"?: string }> } +export const CustomerRewardHistory = Schema.Struct({ "customer_id": Schema.optionalKey(Schema.String.annotate({ "description": "The customer ID of the customer" })), "rewards": Schema.optionalKey(Schema.Array(Schema.Struct({ "balance": Schema.optionalKey(Schema.String.annotate({ "description": "The balance of the customer in the given stablecoin" })), "amount": Schema.optionalKey(Schema.String.annotate({ "description": "The amount of the reward" })), "currency": Schema.optionalKey(Schema.String.annotate({ "description": "The stablecoin symbol for the reward summary" })), "date": Schema.optionalKey(Schema.String.annotate({ "description": "The date of the calculated reward" })) })).annotate({ "description": "The rewards of the customer in the given stablecoin" })) }).annotate({ "title": "Customer Reward History for a given stablecoin", "identifier": "CustomerRewardHistory" }) +export type SimulateKycApprovalResponse = { readonly "success": boolean, readonly "customer_id": string, readonly "kyc_status": "not_started" | "incomplete" | "awaiting_questionnaire" | "awaiting_ubo" | "under_review" | "approved" | "rejected" | "paused" | "offboarded" | "deposits_restricted", readonly "message": string } +export const SimulateKycApprovalResponse = Schema.Struct({ "success": Schema.Boolean.annotate({ "description": "Whether the simulation succeeded" }), "customer_id": Schema.String.annotate({ "description": "The ID of the customer whose KYC was simulated" }), "kyc_status": Schema.Literals(["not_started", "incomplete", "awaiting_questionnaire", "awaiting_ubo", "under_review", "approved", "rejected", "paused", "offboarded", "deposits_restricted"]).annotate({ "description": "Status of the KYC flow." }), "message": Schema.String.annotate({ "description": "Human-readable description of what was processed" }) }).annotate({ "description": "Response from the simulate KYC approval endpoint", "identifier": "SimulateKycApprovalResponse" }) +// schemas +export type GetWalletsParams = { readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string } +export const GetWalletsParams = Schema.Struct({ "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String) }) +export type GetWalletsQuery = { readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string } +export const GetWalletsQuery = Schema.Struct({ "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String) }) +export type GetWallets200 = BridgeWalletsList +export const GetWallets200 = BridgeWalletsList +export type GetWallets400 = Error +export const GetWallets400 = Error +export type GetWallets401 = Error +export const GetWallets401 = Error +export type GetWallets404 = Error +export const GetWallets404 = Error +export type GetWallets500 = Error +export const GetWallets500 = Error +export type GetWalletsTotalBalances200 = ReadonlyArray +export const GetWalletsTotalBalances200 = Schema.Array(BridgeWalletTotalBalance) +export type GetWalletsTotalBalances400 = Error +export const GetWalletsTotalBalances400 = Error +export type GetWalletsTotalBalances401 = Error +export const GetWalletsTotalBalances401 = Error +export type GetWalletsTotalBalances404 = Error +export const GetWalletsTotalBalances404 = Error +export type GetWalletsTotalBalances500 = Error +export const GetWalletsTotalBalances500 = Error +export type GetWalletsByBridgeWalletIDPathParams = { readonly "bridgeWalletID": Id } +export const GetWalletsByBridgeWalletIDPathParams = Schema.Struct({ "bridgeWalletID": Id }) +export type GetWalletsByBridgeWalletID200 = BridgeWalletWithBalances +export const GetWalletsByBridgeWalletID200 = BridgeWalletWithBalances +export type GetWalletsByBridgeWalletID400 = Error +export const GetWalletsByBridgeWalletID400 = Error +export type GetWalletsByBridgeWalletID401 = Error +export const GetWalletsByBridgeWalletID401 = Error +export type GetWalletsByBridgeWalletID404 = Error +export const GetWalletsByBridgeWalletID404 = Error +export type GetWalletsByBridgeWalletID500 = Error +export const GetWalletsByBridgeWalletID500 = Error +export type GetWalletsByBridgeWalletIDHistoryParams = { readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string, readonly "starting_time"?: string, readonly "ending_time"?: string } +export const GetWalletsByBridgeWalletIDHistoryParams = Schema.Struct({ "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String), "starting_time": Schema.optionalKey(Schema.String), "ending_time": Schema.optionalKey(Schema.String) }) +export type GetWalletsByBridgeWalletIDHistoryPathParams = { readonly "bridgeWalletID": Id } +export const GetWalletsByBridgeWalletIDHistoryPathParams = Schema.Struct({ "bridgeWalletID": Id }) +export type GetWalletsByBridgeWalletIDHistoryQuery = { readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string, readonly "starting_time"?: string, readonly "ending_time"?: string } +export const GetWalletsByBridgeWalletIDHistoryQuery = Schema.Struct({ "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String), "starting_time": Schema.optionalKey(Schema.String), "ending_time": Schema.optionalKey(Schema.String) }) +export type GetWalletsByBridgeWalletIDHistory200 = { readonly "count": number, readonly "data": ReadonlyArray } +export const GetWalletsByBridgeWalletIDHistory200 = Schema.Struct({ "count": Schema.Number.annotate({ "description": "The number of events returned" }).check(Schema.isInt().annotate({ "expected": "an integer" })), "data": Schema.Array(BridgeWalletEventResponse).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" })) }).annotate({ "title": "Bridge Wallet History" }) +export type GetWalletsByBridgeWalletIDHistory400 = Error +export const GetWalletsByBridgeWalletIDHistory400 = Error +export type GetWalletsByBridgeWalletIDHistory401 = Error +export const GetWalletsByBridgeWalletIDHistory401 = Error +export type GetWalletsByBridgeWalletIDHistory404 = Error +export const GetWalletsByBridgeWalletIDHistory404 = Error +export type GetWalletsByBridgeWalletIDHistory500 = Error +export const GetWalletsByBridgeWalletIDHistory500 = Error +export type GetCustomersParams = { readonly "starting_after"?: string, readonly "ending_before"?: string, readonly "limit"?: number, readonly "email"?: string } +export const GetCustomersParams = Schema.Struct({ "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String), "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "email": Schema.optionalKey(Schema.String) }) +export type GetCustomersQuery = { readonly "starting_after"?: string, readonly "ending_before"?: string, readonly "limit"?: number, readonly "email"?: string } +export const GetCustomersQuery = Schema.Struct({ "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String), "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "email": Schema.optionalKey(Schema.String) }) +export type GetCustomers200 = { readonly "count"?: number, readonly "data": ReadonlyArray } +export const GetCustomers200 = Schema.Struct({ "count": Schema.optionalKey(Schema.Number.annotate({ "description": "total number of items in data" }).check(Schema.isInt().annotate({ "expected": "an integer" }))), "data": Schema.Array(Customer).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" })) }).annotate({ "title": "Customers" }) +export type GetCustomers401 = Error +export const GetCustomers401 = Error +export type GetCustomers500 = Error +export const GetCustomers500 = Error +export type PostCustomersParams = { readonly "Idempotency-Key": string } +export const PostCustomersParams = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostCustomersHeaders = { readonly "Idempotency-Key": string } +export const PostCustomersHeaders = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostCustomersRequestJson = CreateIndividualCustomerPayload | CreateBusinessCustomerPayload +export const PostCustomersRequestJson = Schema.Union([CreateIndividualCustomerPayload, CreateBusinessCustomerPayload], { mode: "oneOf" }) +export type PostCustomers201 = Customer +export const PostCustomers201 = Customer +export type PostCustomers400 = Error +export const PostCustomers400 = Error +export type PostCustomers401 = Error +export const PostCustomers401 = Error +export type PostCustomers500 = Error +export const PostCustomers500 = Error +export type GetCustomersByCustomerIDPathParams = { readonly "customerID": Id } +export const GetCustomersByCustomerIDPathParams = Schema.Struct({ "customerID": Id }) +export type GetCustomersByCustomerID200 = Customer +export const GetCustomersByCustomerID200 = Customer +export type GetCustomersByCustomerID401 = Error +export const GetCustomersByCustomerID401 = Error +export type GetCustomersByCustomerID404 = Error +export const GetCustomersByCustomerID404 = Error +export type GetCustomersByCustomerID500 = Error +export const GetCustomersByCustomerID500 = Error +export type PutCustomersByCustomerIDPathParams = { readonly "customerID": Id } +export const PutCustomersByCustomerIDPathParams = Schema.Struct({ "customerID": Id }) +export type PutCustomersByCustomerIDRequestJson = UpdateIndividualCustomerPayload | UpdateBusinessCustomerPayload +export const PutCustomersByCustomerIDRequestJson = Schema.Union([UpdateIndividualCustomerPayload, UpdateBusinessCustomerPayload], { mode: "oneOf" }) +export type PutCustomersByCustomerID200 = Customer +export const PutCustomersByCustomerID200 = Customer +export type PutCustomersByCustomerID401 = Error +export const PutCustomersByCustomerID401 = Error +export type PutCustomersByCustomerID404 = Error +export const PutCustomersByCustomerID404 = Error +export type PutCustomersByCustomerID500 = Error +export const PutCustomersByCustomerID500 = Error +export type DeleteCustomersByCustomerIDPathParams = { readonly "customerID": Id } +export const DeleteCustomersByCustomerIDPathParams = Schema.Struct({ "customerID": Id }) +export type DeleteCustomersByCustomerID200 = Customer +export const DeleteCustomersByCustomerID200 = Customer +export type DeleteCustomersByCustomerID401 = Error +export const DeleteCustomersByCustomerID401 = Error +export type DeleteCustomersByCustomerID404 = Error +export const DeleteCustomersByCustomerID404 = Error +export type DeleteCustomersByCustomerID500 = Error +export const DeleteCustomersByCustomerID500 = Error +export type GetCustomersByCustomerIDExternalAccountsParams = { readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string } +export const GetCustomersByCustomerIDExternalAccountsParams = Schema.Struct({ "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String) }) +export type GetCustomersByCustomerIDExternalAccountsPathParams = { readonly "customerID": Id } +export const GetCustomersByCustomerIDExternalAccountsPathParams = Schema.Struct({ "customerID": Id }) +export type GetCustomersByCustomerIDExternalAccountsQuery = { readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string } +export const GetCustomersByCustomerIDExternalAccountsQuery = Schema.Struct({ "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String) }) +export type GetCustomersByCustomerIDExternalAccounts200 = { readonly "data": ReadonlyArray, readonly "count"?: number } +export const GetCustomersByCustomerIDExternalAccounts200 = Schema.Struct({ "data": Schema.Array(ExternalAccountResponse).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" })), "count": Schema.optionalKey(Schema.Number.annotate({ "description": "total number of items in data" }).check(Schema.isInt().annotate({ "expected": "an integer" }))) }).annotate({ "title": "ExternalAccount" }) +export type GetCustomersByCustomerIDExternalAccounts401 = Error +export const GetCustomersByCustomerIDExternalAccounts401 = Error +export type GetCustomersByCustomerIDExternalAccounts500 = Error +export const GetCustomersByCustomerIDExternalAccounts500 = Error +export type PostCustomersByCustomerIDExternalAccountsParams = { readonly "Idempotency-Key": string } +export const PostCustomersByCustomerIDExternalAccountsParams = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostCustomersByCustomerIDExternalAccountsPathParams = { readonly "customerID": Id } +export const PostCustomersByCustomerIDExternalAccountsPathParams = Schema.Struct({ "customerID": Id }) +export type PostCustomersByCustomerIDExternalAccountsHeaders = { readonly "Idempotency-Key": string } +export const PostCustomersByCustomerIDExternalAccountsHeaders = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostCustomersByCustomerIDExternalAccountsRequestJson = CreateExternalAccountInput +export const PostCustomersByCustomerIDExternalAccountsRequestJson = CreateExternalAccountInput +export type PostCustomersByCustomerIDExternalAccounts201 = ExternalAccountResponse +export const PostCustomersByCustomerIDExternalAccounts201 = ExternalAccountResponse +export type PostCustomersByCustomerIDExternalAccounts400 = Error +export const PostCustomersByCustomerIDExternalAccounts400 = Error +export type PostCustomersByCustomerIDExternalAccounts401 = Error +export const PostCustomersByCustomerIDExternalAccounts401 = Error +export type PostCustomersByCustomerIDExternalAccounts500 = Error +export const PostCustomersByCustomerIDExternalAccounts500 = Error +export type GetCustomersByCustomerIDExternalAccountsByExternalAccountIDPathParams = { readonly "customerID": Id, readonly "externalAccountID": Id } +export const GetCustomersByCustomerIDExternalAccountsByExternalAccountIDPathParams = Schema.Struct({ "customerID": Id, "externalAccountID": Id }) +export type GetCustomersByCustomerIDExternalAccountsByExternalAccountID200 = ExternalAccountResponse +export const GetCustomersByCustomerIDExternalAccountsByExternalAccountID200 = ExternalAccountResponse +export type GetCustomersByCustomerIDExternalAccountsByExternalAccountID401 = Error +export const GetCustomersByCustomerIDExternalAccountsByExternalAccountID401 = Error +export type GetCustomersByCustomerIDExternalAccountsByExternalAccountID404 = Error +export const GetCustomersByCustomerIDExternalAccountsByExternalAccountID404 = Error +export type GetCustomersByCustomerIDExternalAccountsByExternalAccountID500 = Error +export const GetCustomersByCustomerIDExternalAccountsByExternalAccountID500 = Error +export type PutCustomersByCustomerIDExternalAccountsByExternalAccountIDPathParams = { readonly "customerID": Id, readonly "externalAccountID": Id } +export const PutCustomersByCustomerIDExternalAccountsByExternalAccountIDPathParams = Schema.Struct({ "customerID": Id, "externalAccountID": Id }) +export type PutCustomersByCustomerIDExternalAccountsByExternalAccountIDRequestJson = UpdateExternalAccountInput +export const PutCustomersByCustomerIDExternalAccountsByExternalAccountIDRequestJson = UpdateExternalAccountInput +export type PutCustomersByCustomerIDExternalAccountsByExternalAccountID200 = ExternalAccountResponse +export const PutCustomersByCustomerIDExternalAccountsByExternalAccountID200 = ExternalAccountResponse +export type PutCustomersByCustomerIDExternalAccountsByExternalAccountID400 = Error +export const PutCustomersByCustomerIDExternalAccountsByExternalAccountID400 = Error +export type PutCustomersByCustomerIDExternalAccountsByExternalAccountID401 = Error +export const PutCustomersByCustomerIDExternalAccountsByExternalAccountID401 = Error +export type PutCustomersByCustomerIDExternalAccountsByExternalAccountID500 = Error +export const PutCustomersByCustomerIDExternalAccountsByExternalAccountID500 = Error +export type DeleteCustomersByCustomerIDExternalAccountsByExternalAccountIDPathParams = { readonly "customerID": Id, readonly "externalAccountID": Id } +export const DeleteCustomersByCustomerIDExternalAccountsByExternalAccountIDPathParams = Schema.Struct({ "customerID": Id, "externalAccountID": Id }) +export type DeleteCustomersByCustomerIDExternalAccountsByExternalAccountID200 = ExternalAccountResponse +export const DeleteCustomersByCustomerIDExternalAccountsByExternalAccountID200 = ExternalAccountResponse +export type DeleteCustomersByCustomerIDExternalAccountsByExternalAccountID401 = Error +export const DeleteCustomersByCustomerIDExternalAccountsByExternalAccountID401 = Error +export type DeleteCustomersByCustomerIDExternalAccountsByExternalAccountID404 = Error +export const DeleteCustomersByCustomerIDExternalAccountsByExternalAccountID404 = Error +export type DeleteCustomersByCustomerIDExternalAccountsByExternalAccountID500 = Error +export const DeleteCustomersByCustomerIDExternalAccountsByExternalAccountID500 = Error +export type GetCustomersByCustomerIDAssociatedPersonsPathParams = { readonly "customerID": Id } +export const GetCustomersByCustomerIDAssociatedPersonsPathParams = Schema.Struct({ "customerID": Id }) +export type GetCustomersByCustomerIDAssociatedPersons200 = { readonly "data": ReadonlyArray } +export const GetCustomersByCustomerIDAssociatedPersons200 = Schema.Struct({ "data": Schema.Array(AssociatedPersonResponse).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" })) }).annotate({ "title": "AssociatedPersonsList" }) +export type GetCustomersByCustomerIDAssociatedPersons401 = Error +export const GetCustomersByCustomerIDAssociatedPersons401 = Error +export type GetCustomersByCustomerIDAssociatedPersons404 = Error +export const GetCustomersByCustomerIDAssociatedPersons404 = Error +export type GetCustomersByCustomerIDAssociatedPersons500 = Error +export const GetCustomersByCustomerIDAssociatedPersons500 = Error +export type PostCustomersByCustomerIDAssociatedPersonsParams = { readonly "Idempotency-Key": string } +export const PostCustomersByCustomerIDAssociatedPersonsParams = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostCustomersByCustomerIDAssociatedPersonsPathParams = { readonly "customerID": Id } +export const PostCustomersByCustomerIDAssociatedPersonsPathParams = Schema.Struct({ "customerID": Id }) +export type PostCustomersByCustomerIDAssociatedPersonsHeaders = { readonly "Idempotency-Key": string } +export const PostCustomersByCustomerIDAssociatedPersonsHeaders = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostCustomersByCustomerIDAssociatedPersonsRequestJson = AssociatedPerson +export const PostCustomersByCustomerIDAssociatedPersonsRequestJson = AssociatedPerson +export type PostCustomersByCustomerIDAssociatedPersons201 = AssociatedPersonResponse +export const PostCustomersByCustomerIDAssociatedPersons201 = AssociatedPersonResponse +export type PostCustomersByCustomerIDAssociatedPersons400 = Error +export const PostCustomersByCustomerIDAssociatedPersons400 = Error +export type PostCustomersByCustomerIDAssociatedPersons401 = Error +export const PostCustomersByCustomerIDAssociatedPersons401 = Error +export type PostCustomersByCustomerIDAssociatedPersons404 = Error +export const PostCustomersByCustomerIDAssociatedPersons404 = Error +export type PostCustomersByCustomerIDAssociatedPersons500 = Error +export const PostCustomersByCustomerIDAssociatedPersons500 = Error +export type GetCustomersByCustomerIDAssociatedPersonsByAssociatedPersonIDPathParams = { readonly "customerID": Id, readonly "associatedPersonID": Id } +export const GetCustomersByCustomerIDAssociatedPersonsByAssociatedPersonIDPathParams = Schema.Struct({ "customerID": Id, "associatedPersonID": Id }) +export type GetCustomersByCustomerIDAssociatedPersonsByAssociatedPersonID200 = AssociatedPersonResponse +export const GetCustomersByCustomerIDAssociatedPersonsByAssociatedPersonID200 = AssociatedPersonResponse +export type GetCustomersByCustomerIDAssociatedPersonsByAssociatedPersonID401 = Error +export const GetCustomersByCustomerIDAssociatedPersonsByAssociatedPersonID401 = Error +export type GetCustomersByCustomerIDAssociatedPersonsByAssociatedPersonID404 = Error +export const GetCustomersByCustomerIDAssociatedPersonsByAssociatedPersonID404 = Error +export type GetCustomersByCustomerIDAssociatedPersonsByAssociatedPersonID500 = Error +export const GetCustomersByCustomerIDAssociatedPersonsByAssociatedPersonID500 = Error +export type PutCustomersByCustomerIDAssociatedPersonsByAssociatedPersonIDPathParams = { readonly "customerID": Id, readonly "associatedPersonID": Id } +export const PutCustomersByCustomerIDAssociatedPersonsByAssociatedPersonIDPathParams = Schema.Struct({ "customerID": Id, "associatedPersonID": Id }) +export type PutCustomersByCustomerIDAssociatedPersonsByAssociatedPersonIDRequestJson = AssociatedPerson +export const PutCustomersByCustomerIDAssociatedPersonsByAssociatedPersonIDRequestJson = AssociatedPerson +export type PutCustomersByCustomerIDAssociatedPersonsByAssociatedPersonID200 = AssociatedPersonResponse +export const PutCustomersByCustomerIDAssociatedPersonsByAssociatedPersonID200 = AssociatedPersonResponse +export type PutCustomersByCustomerIDAssociatedPersonsByAssociatedPersonID400 = Error +export const PutCustomersByCustomerIDAssociatedPersonsByAssociatedPersonID400 = Error +export type PutCustomersByCustomerIDAssociatedPersonsByAssociatedPersonID401 = Error +export const PutCustomersByCustomerIDAssociatedPersonsByAssociatedPersonID401 = Error +export type PutCustomersByCustomerIDAssociatedPersonsByAssociatedPersonID404 = Error +export const PutCustomersByCustomerIDAssociatedPersonsByAssociatedPersonID404 = Error +export type PutCustomersByCustomerIDAssociatedPersonsByAssociatedPersonID500 = Error +export const PutCustomersByCustomerIDAssociatedPersonsByAssociatedPersonID500 = Error +export type DeleteCustomersByCustomerIDAssociatedPersonsByAssociatedPersonIDPathParams = { readonly "customerID": Id, readonly "associatedPersonID": Id } +export const DeleteCustomersByCustomerIDAssociatedPersonsByAssociatedPersonIDPathParams = Schema.Struct({ "customerID": Id, "associatedPersonID": Id }) +export type DeleteCustomersByCustomerIDAssociatedPersonsByAssociatedPersonID200 = AssociatedPersonResponse +export const DeleteCustomersByCustomerIDAssociatedPersonsByAssociatedPersonID200 = AssociatedPersonResponse +export type DeleteCustomersByCustomerIDAssociatedPersonsByAssociatedPersonID401 = Error +export const DeleteCustomersByCustomerIDAssociatedPersonsByAssociatedPersonID401 = Error +export type DeleteCustomersByCustomerIDAssociatedPersonsByAssociatedPersonID404 = Error +export const DeleteCustomersByCustomerIDAssociatedPersonsByAssociatedPersonID404 = Error +export type DeleteCustomersByCustomerIDAssociatedPersonsByAssociatedPersonID500 = Error +export const DeleteCustomersByCustomerIDAssociatedPersonsByAssociatedPersonID500 = Error +export type GetCustomersByCustomerIDFiatPayoutConfigurationPathParams = { readonly "customerID": Id } +export const GetCustomersByCustomerIDFiatPayoutConfigurationPathParams = Schema.Struct({ "customerID": Id }) +export type GetCustomersByCustomerIDFiatPayoutConfiguration200 = FiatPayoutConfigurationResponse +export const GetCustomersByCustomerIDFiatPayoutConfiguration200 = FiatPayoutConfigurationResponse +export type GetCustomersByCustomerIDFiatPayoutConfiguration401 = Error +export const GetCustomersByCustomerIDFiatPayoutConfiguration401 = Error +export type GetCustomersByCustomerIDFiatPayoutConfiguration404 = Error +export const GetCustomersByCustomerIDFiatPayoutConfiguration404 = Error +export type GetCustomersByCustomerIDFiatPayoutConfiguration500 = Error +export const GetCustomersByCustomerIDFiatPayoutConfiguration500 = Error +export type PatchCustomersByCustomerIDFiatPayoutConfigurationPathParams = { readonly "customerID": Id } +export const PatchCustomersByCustomerIDFiatPayoutConfigurationPathParams = Schema.Struct({ "customerID": Id }) +export type PatchCustomersByCustomerIDFiatPayoutConfigurationRequestJson = PatchFiatPayoutConfigurationInput +export const PatchCustomersByCustomerIDFiatPayoutConfigurationRequestJson = PatchFiatPayoutConfigurationInput +export type PatchCustomersByCustomerIDFiatPayoutConfiguration200 = FiatPayoutConfigurationResponse +export const PatchCustomersByCustomerIDFiatPayoutConfiguration200 = FiatPayoutConfigurationResponse +export type PatchCustomersByCustomerIDFiatPayoutConfiguration400 = Error +export const PatchCustomersByCustomerIDFiatPayoutConfiguration400 = Error +export type PatchCustomersByCustomerIDFiatPayoutConfiguration401 = Error +export const PatchCustomersByCustomerIDFiatPayoutConfiguration401 = Error +export type PatchCustomersByCustomerIDFiatPayoutConfiguration403 = Error +export const PatchCustomersByCustomerIDFiatPayoutConfiguration403 = Error +export type PatchCustomersByCustomerIDFiatPayoutConfiguration404 = Error +export const PatchCustomersByCustomerIDFiatPayoutConfiguration404 = Error +export type PatchCustomersByCustomerIDFiatPayoutConfiguration500 = Error +export const PatchCustomersByCustomerIDFiatPayoutConfiguration500 = Error +export type PostCustomersByCustomerIDExternalAccountsByExternalAccountIDDeactivateParams = { readonly "Idempotency-Key": string } +export const PostCustomersByCustomerIDExternalAccountsByExternalAccountIDDeactivateParams = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostCustomersByCustomerIDExternalAccountsByExternalAccountIDDeactivatePathParams = { readonly "customerID": Id, readonly "externalAccountID": Id } +export const PostCustomersByCustomerIDExternalAccountsByExternalAccountIDDeactivatePathParams = Schema.Struct({ "customerID": Id, "externalAccountID": Id }) +export type PostCustomersByCustomerIDExternalAccountsByExternalAccountIDDeactivateHeaders = { readonly "Idempotency-Key": string } +export const PostCustomersByCustomerIDExternalAccountsByExternalAccountIDDeactivateHeaders = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostCustomersByCustomerIDExternalAccountsByExternalAccountIDDeactivate200 = ExternalAccountResponse +export const PostCustomersByCustomerIDExternalAccountsByExternalAccountIDDeactivate200 = ExternalAccountResponse +export type PostCustomersByCustomerIDExternalAccountsByExternalAccountIDDeactivate401 = Error +export const PostCustomersByCustomerIDExternalAccountsByExternalAccountIDDeactivate401 = Error +export type PostCustomersByCustomerIDExternalAccountsByExternalAccountIDDeactivate404 = Error +export const PostCustomersByCustomerIDExternalAccountsByExternalAccountIDDeactivate404 = Error +export type PostCustomersByCustomerIDExternalAccountsByExternalAccountIDDeactivate500 = Error +export const PostCustomersByCustomerIDExternalAccountsByExternalAccountIDDeactivate500 = Error +export type PostCustomersByCustomerIDExternalAccountsByExternalAccountIDVerifyPathParams = { readonly "customerID": Id, readonly "externalAccountID": Id } +export const PostCustomersByCustomerIDExternalAccountsByExternalAccountIDVerifyPathParams = Schema.Struct({ "customerID": Id, "externalAccountID": Id }) +export type PostCustomersByCustomerIDExternalAccountsByExternalAccountIDVerify200 = { readonly "account_type"?: "iban" | "gb" | "pix" | "clabe" | "bre_b" | "co_bank_transfer", readonly "account_verification"?: AccountVerification } +export const PostCustomersByCustomerIDExternalAccountsByExternalAccountIDVerify200 = Schema.Struct({ "account_type": Schema.optionalKey(Schema.Literals(["iban", "gb", "pix", "clabe", "bre_b", "co_bank_transfer"]).annotate({ "description": "The account type that was verified." })), "account_verification": Schema.optionalKey(AccountVerification) }) +export type PostCustomersByCustomerIDExternalAccountsByExternalAccountIDVerify400 = Error +export const PostCustomersByCustomerIDExternalAccountsByExternalAccountIDVerify400 = Error +export type PostCustomersByCustomerIDExternalAccountsByExternalAccountIDVerify401 = Error +export const PostCustomersByCustomerIDExternalAccountsByExternalAccountIDVerify401 = Error +export type PostCustomersByCustomerIDExternalAccountsByExternalAccountIDVerify404 = Error +export const PostCustomersByCustomerIDExternalAccountsByExternalAccountIDVerify404 = Error +export type PostCustomersByCustomerIDExternalAccountsByExternalAccountIDVerify409 = Error +export const PostCustomersByCustomerIDExternalAccountsByExternalAccountIDVerify409 = Error +export type PostCustomersByCustomerIDExternalAccountsByExternalAccountIDVerify500 = Error +export const PostCustomersByCustomerIDExternalAccountsByExternalAccountIDVerify500 = Error +export type PostCustomersByCustomerIDExternalAccountsByExternalAccountIDReactivateParams = { readonly "Idempotency-Key": string } +export const PostCustomersByCustomerIDExternalAccountsByExternalAccountIDReactivateParams = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostCustomersByCustomerIDExternalAccountsByExternalAccountIDReactivatePathParams = { readonly "customerID": Id, readonly "externalAccountID": Id } +export const PostCustomersByCustomerIDExternalAccountsByExternalAccountIDReactivatePathParams = Schema.Struct({ "customerID": Id, "externalAccountID": Id }) +export type PostCustomersByCustomerIDExternalAccountsByExternalAccountIDReactivateHeaders = { readonly "Idempotency-Key": string } +export const PostCustomersByCustomerIDExternalAccountsByExternalAccountIDReactivateHeaders = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostCustomersByCustomerIDExternalAccountsByExternalAccountIDReactivate200 = ExternalAccountResponse +export const PostCustomersByCustomerIDExternalAccountsByExternalAccountIDReactivate200 = ExternalAccountResponse +export type PostCustomersByCustomerIDExternalAccountsByExternalAccountIDReactivate400 = Error +export const PostCustomersByCustomerIDExternalAccountsByExternalAccountIDReactivate400 = Error +export type GetCustomersByCustomerIDTosAcceptanceLinkPathParams = { readonly "customerID": Id } +export const GetCustomersByCustomerIDTosAcceptanceLinkPathParams = Schema.Struct({ "customerID": Id }) +export type GetCustomersByCustomerIDTosAcceptanceLink200 = { readonly "url": string } +export const GetCustomersByCustomerIDTosAcceptanceLink200 = Schema.Struct({ "url": Schema.String.annotate({ "description": "A hosted URL for ToS acceptance" }) }) +export type GetCustomersByCustomerIDTosAcceptanceLink401 = Error +export const GetCustomersByCustomerIDTosAcceptanceLink401 = Error +export type GetCustomersByCustomerIDTosAcceptanceLink500 = Error +export const GetCustomersByCustomerIDTosAcceptanceLink500 = Error +export type GetCustomersByCustomerIDKycLinkParams = { readonly "endorsement"?: "sepa" | "spei" | "cards", readonly "redirect_uri"?: string } +export const GetCustomersByCustomerIDKycLinkParams = Schema.Struct({ "endorsement": Schema.optionalKey(Schema.Literals(["sepa", "spei", "cards"])), "redirect_uri": Schema.optionalKey(Schema.String.annotate({ "examples": ["http%3A%2F%2Fexample.com%2Fredirect"] })) }) +export type GetCustomersByCustomerIDKycLinkPathParams = { readonly "customerID": Id } +export const GetCustomersByCustomerIDKycLinkPathParams = Schema.Struct({ "customerID": Id }) +export type GetCustomersByCustomerIDKycLinkQuery = { readonly "endorsement"?: "sepa" | "spei" | "cards", readonly "redirect_uri"?: string } +export const GetCustomersByCustomerIDKycLinkQuery = Schema.Struct({ "endorsement": Schema.optionalKey(Schema.Literals(["sepa", "spei", "cards"])), "redirect_uri": Schema.optionalKey(Schema.String.annotate({ "examples": ["http%3A%2F%2Fexample.com%2Fredirect"] })) }) +export type GetCustomersByCustomerIDKycLink200 = { readonly "url": string } +export const GetCustomersByCustomerIDKycLink200 = Schema.Struct({ "url": Schema.String.annotate({ "description": "A hosted KYC link" }) }) +export type GetCustomersByCustomerIDKycLink401 = Error +export const GetCustomersByCustomerIDKycLink401 = Error +export type GetCustomersByCustomerIDKycLink500 = Error +export const GetCustomersByCustomerIDKycLink500 = Error +export type GetCustomersByCustomerIDTransfersParams = { readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string, readonly "tx_hash"?: string, readonly "updated_after_ms"?: number, readonly "updated_before_ms"?: number, readonly "state"?: "awaiting_funds" | "funds_received" | "payment_submitted" | "payment_processed" | "in_review" | "kyc_required" | "kyc_in_review" | "developer_kyb_required" | "canceled" | "error" | "returned" | "refund_in_flight" | "refund_failed" | "refunded" | "undeliverable" } +export const GetCustomersByCustomerIDTransfersParams = Schema.Struct({ "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String), "tx_hash": Schema.optionalKey(Schema.String), "updated_after_ms": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), "updated_before_ms": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), "state": Schema.optionalKey(Schema.Literals(["awaiting_funds", "funds_received", "payment_submitted", "payment_processed", "in_review", "kyc_required", "kyc_in_review", "developer_kyb_required", "canceled", "error", "returned", "refund_in_flight", "refund_failed", "refunded", "undeliverable"])) }) +export type GetCustomersByCustomerIDTransfersPathParams = { readonly "customerID": Id } +export const GetCustomersByCustomerIDTransfersPathParams = Schema.Struct({ "customerID": Id }) +export type GetCustomersByCustomerIDTransfersQuery = { readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string, readonly "tx_hash"?: string, readonly "updated_after_ms"?: number, readonly "updated_before_ms"?: number, readonly "state"?: "awaiting_funds" | "funds_received" | "payment_submitted" | "payment_processed" | "in_review" | "kyc_required" | "kyc_in_review" | "developer_kyb_required" | "canceled" | "error" | "returned" | "refund_in_flight" | "refund_failed" | "refunded" | "undeliverable" } +export const GetCustomersByCustomerIDTransfersQuery = Schema.Struct({ "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String), "tx_hash": Schema.optionalKey(Schema.String), "updated_after_ms": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), "updated_before_ms": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), "state": Schema.optionalKey(Schema.Literals(["awaiting_funds", "funds_received", "payment_submitted", "payment_processed", "in_review", "kyc_required", "kyc_in_review", "developer_kyb_required", "canceled", "error", "returned", "refund_in_flight", "refund_failed", "refunded", "undeliverable"])) }) +export type GetCustomersByCustomerIDTransfers200 = { readonly "count": number, readonly "data": ReadonlyArray } +export const GetCustomersByCustomerIDTransfers200 = Schema.Struct({ "count": Schema.Number.annotate({ "description": "The number of transfers returned" }).check(Schema.isInt().annotate({ "expected": "an integer" })), "data": Schema.Array(TransferResponse).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" })) }).annotate({ "title": "Transfers" }) +export type GetCustomersByCustomerIDTransfers401 = Error +export const GetCustomersByCustomerIDTransfers401 = Error +export type GetCustomersByCustomerIDTransfers500 = Error +export const GetCustomersByCustomerIDTransfers500 = Error +export type GetCustomersByCustomerIDTransfersStaticTemplatesParams = { readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string } +export const GetCustomersByCustomerIDTransfersStaticTemplatesParams = Schema.Struct({ "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String) }) +export type GetCustomersByCustomerIDTransfersStaticTemplatesPathParams = { readonly "customerID": Id } +export const GetCustomersByCustomerIDTransfersStaticTemplatesPathParams = Schema.Struct({ "customerID": Id }) +export type GetCustomersByCustomerIDTransfersStaticTemplatesQuery = { readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string } +export const GetCustomersByCustomerIDTransfersStaticTemplatesQuery = Schema.Struct({ "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String) }) +export type GetCustomersByCustomerIDTransfersStaticTemplates200 = { readonly "count": number, readonly "data": ReadonlyArray } +export const GetCustomersByCustomerIDTransfersStaticTemplates200 = Schema.Struct({ "count": Schema.Number.annotate({ "description": "The number of static templates returned" }).check(Schema.isInt().annotate({ "expected": "an integer" })), "data": Schema.Array(TransferResponse).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" })) }).annotate({ "title": "Static Templates" }) +export type GetCustomersByCustomerIDTransfersStaticTemplates401 = Error +export const GetCustomersByCustomerIDTransfersStaticTemplates401 = Error +export type GetCustomersByCustomerIDTransfersStaticTemplates404 = Error +export const GetCustomersByCustomerIDTransfersStaticTemplates404 = Error +export type GetCustomersByCustomerIDTransfersStaticTemplates500 = Error +export const GetCustomersByCustomerIDTransfersStaticTemplates500 = Error +export type PostCustomersTosLinksParams = { readonly "Idempotency-Key": string } +export const PostCustomersTosLinksParams = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostCustomersTosLinksHeaders = { readonly "Idempotency-Key": string } +export const PostCustomersTosLinksHeaders = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostCustomersTosLinks201 = { readonly "url": string } +export const PostCustomersTosLinks201 = Schema.Struct({ "url": Schema.String.annotate({ "description": "A Bridge hosted URL for users to complete terms of service signing." }) }) +export type PostCustomersTosLinks401 = Error +export const PostCustomersTosLinks401 = Error +export type PostCustomersTosLinks500 = Error +export const PostCustomersTosLinks500 = Error +export type PostCustomersByCustomerIDPlaidLinkRequestsParams = { readonly "Idempotency-Key": string } +export const PostCustomersByCustomerIDPlaidLinkRequestsParams = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostCustomersByCustomerIDPlaidLinkRequestsPathParams = { readonly "customerID": Id } +export const PostCustomersByCustomerIDPlaidLinkRequestsPathParams = Schema.Struct({ "customerID": Id }) +export type PostCustomersByCustomerIDPlaidLinkRequestsHeaders = { readonly "Idempotency-Key": string } +export const PostCustomersByCustomerIDPlaidLinkRequestsHeaders = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostCustomersByCustomerIDPlaidLinkRequests201 = PlaidLinkRequest +export const PostCustomersByCustomerIDPlaidLinkRequests201 = PlaidLinkRequest +export type PostCustomersByCustomerIDPlaidLinkRequests400 = Error +export const PostCustomersByCustomerIDPlaidLinkRequests400 = Error +export type PostCustomersByCustomerIDPlaidLinkRequests401 = Error +export const PostCustomersByCustomerIDPlaidLinkRequests401 = Error +export type PostCustomersByCustomerIDPlaidLinkRequests500 = Error +export const PostCustomersByCustomerIDPlaidLinkRequests500 = Error +export type PostPlaidExchangePublicTokenByLinkTokenPathParams = { readonly "link_token": string } +export const PostPlaidExchangePublicTokenByLinkTokenPathParams = Schema.Struct({ "link_token": Schema.String }) +export type PostPlaidExchangePublicTokenByLinkTokenRequestJson = PlaidExchangePublicToken +export const PostPlaidExchangePublicTokenByLinkTokenRequestJson = PlaidExchangePublicToken +export type PostPlaidExchangePublicTokenByLinkToken201 = { readonly "message"?: string } +export const PostPlaidExchangePublicTokenByLinkToken201 = Schema.Struct({ "message": Schema.optionalKey(Schema.String.annotate({ "description": "Message indicating the status of the request" })) }).annotate({ "title": "Plaid public token exchanged" }) +export type PostPlaidExchangePublicTokenByLinkToken400 = Error +export const PostPlaidExchangePublicTokenByLinkToken400 = Error +export type PostPlaidExchangePublicTokenByLinkToken401 = Error +export const PostPlaidExchangePublicTokenByLinkToken401 = Error +export type PostPlaidExchangePublicTokenByLinkToken500 = Error +export const PostPlaidExchangePublicTokenByLinkToken500 = Error +export type GetTransfersParams = { readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string, readonly "tx_hash"?: string, readonly "updated_after_ms"?: number, readonly "updated_before_ms"?: number, readonly "template_id"?: Id, readonly "state"?: "awaiting_funds" | "funds_received" | "payment_submitted" | "payment_processed" | "in_review" | "kyc_required" | "kyc_in_review" | "developer_kyb_required" | "canceled" | "error" | "returned" | "refund_in_flight" | "refund_failed" | "refunded" | "undeliverable" } +export const GetTransfersParams = Schema.Struct({ "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String), "tx_hash": Schema.optionalKey(Schema.String), "updated_after_ms": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), "updated_before_ms": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), "template_id": Schema.optionalKey(Id), "state": Schema.optionalKey(Schema.Literals(["awaiting_funds", "funds_received", "payment_submitted", "payment_processed", "in_review", "kyc_required", "kyc_in_review", "developer_kyb_required", "canceled", "error", "returned", "refund_in_flight", "refund_failed", "refunded", "undeliverable"])) }) +export type GetTransfersQuery = { readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string, readonly "tx_hash"?: string, readonly "updated_after_ms"?: number, readonly "updated_before_ms"?: number, readonly "template_id"?: Id, readonly "state"?: "awaiting_funds" | "funds_received" | "payment_submitted" | "payment_processed" | "in_review" | "kyc_required" | "kyc_in_review" | "developer_kyb_required" | "canceled" | "error" | "returned" | "refund_in_flight" | "refund_failed" | "refunded" | "undeliverable" } +export const GetTransfersQuery = Schema.Struct({ "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String), "tx_hash": Schema.optionalKey(Schema.String), "updated_after_ms": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), "updated_before_ms": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), "template_id": Schema.optionalKey(Id), "state": Schema.optionalKey(Schema.Literals(["awaiting_funds", "funds_received", "payment_submitted", "payment_processed", "in_review", "kyc_required", "kyc_in_review", "developer_kyb_required", "canceled", "error", "returned", "refund_in_flight", "refund_failed", "refunded", "undeliverable"])) }) +export type GetTransfers200 = { readonly "count": number, readonly "data": ReadonlyArray } +export const GetTransfers200 = Schema.Struct({ "count": Schema.Number.annotate({ "description": "The number of transfers returned" }).check(Schema.isInt().annotate({ "expected": "an integer" })), "data": Schema.Array(TransferResponse).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" })) }).annotate({ "title": "Transfers" }) +export type GetTransfers401 = Error +export const GetTransfers401 = Error +export type GetTransfers500 = Error +export const GetTransfers500 = Error +export type PostTransfersParams = { readonly "Idempotency-Key": string } +export const PostTransfersParams = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostTransfersHeaders = { readonly "Idempotency-Key": string } +export const PostTransfersHeaders = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostTransfersRequestJson = TransferRequest +export const PostTransfersRequestJson = TransferRequest +export type PostTransfers201 = TransferResponse | TransferRouteResponse +export const PostTransfers201 = Schema.Union([TransferResponse, TransferRouteResponse], { mode: "oneOf" }) +export type PostTransfers400 = Error +export const PostTransfers400 = Error +export type PostTransfers401 = Error +export const PostTransfers401 = Error +export type PostTransfers403 = Error +export const PostTransfers403 = Error +export type PostTransfers409 = Error +export const PostTransfers409 = Error +export type PostTransfers500 = Error +export const PostTransfers500 = Error +export type GetTransfersPendingParams = { readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string } +export const GetTransfersPendingParams = Schema.Struct({ "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String) }) +export type GetTransfersPendingQuery = { readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string } +export const GetTransfersPendingQuery = Schema.Struct({ "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String) }) +export type GetTransfersPending200 = { readonly "count": number, readonly "data": ReadonlyArray } +export const GetTransfersPending200 = Schema.Struct({ "count": Schema.Number.annotate({ "description": "The number of transfers returned" }).check(Schema.isInt().annotate({ "expected": "an integer" })), "data": Schema.Array(TransferResponse).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" })) }).annotate({ "title": "PendingTransfers" }) +export type GetTransfersPending400 = Error +export const GetTransfersPending400 = Error +export type GetTransfersPending401 = Error +export const GetTransfersPending401 = Error +export type GetTransfersPending500 = Error +export const GetTransfersPending500 = Error +export type GetTransfersByTransferIDPathParams = { readonly "transferID": Id } +export const GetTransfersByTransferIDPathParams = Schema.Struct({ "transferID": Id }) +export type GetTransfersByTransferID200 = TransferResponse +export const GetTransfersByTransferID200 = TransferResponse +export type GetTransfersByTransferID401 = Error +export const GetTransfersByTransferID401 = Error +export type GetTransfersByTransferID404 = Error +export const GetTransfersByTransferID404 = Error +export type GetTransfersByTransferID500 = Error +export const GetTransfersByTransferID500 = Error +export type PutTransfersByTransferIDPathParams = { readonly "transferID": Id } +export const PutTransfersByTransferIDPathParams = Schema.Struct({ "transferID": Id }) +export type PutTransfersByTransferIDRequestJson = TransferUpdateRequest +export const PutTransfersByTransferIDRequestJson = TransferUpdateRequest +export type PutTransfersByTransferID201 = TransferResponse +export const PutTransfersByTransferID201 = TransferResponse +export type PutTransfersByTransferID400 = Error +export const PutTransfersByTransferID400 = Error +export type PutTransfersByTransferID401 = Error +export const PutTransfersByTransferID401 = Error +export type PutTransfersByTransferID403 = Error +export const PutTransfersByTransferID403 = Error +export type PutTransfersByTransferID500 = Error +export const PutTransfersByTransferID500 = Error +export type DeleteTransfersByTransferIDPathParams = { readonly "transferID": Id } +export const DeleteTransfersByTransferIDPathParams = Schema.Struct({ "transferID": Id }) +export type DeleteTransfersByTransferID401 = Error +export const DeleteTransfersByTransferID401 = Error +export type DeleteTransfersByTransferID404 = Error +export const DeleteTransfersByTransferID404 = Error +export type DeleteTransfersByTransferID500 = Error +export const DeleteTransfersByTransferID500 = Error +export type PostTransfersByTransferIDExecuteParams = { readonly "Idempotency-Key": string } +export const PostTransfersByTransferIDExecuteParams = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostTransfersByTransferIDExecutePathParams = { readonly "transferID": Id } +export const PostTransfersByTransferIDExecutePathParams = Schema.Struct({ "transferID": Id }) +export type PostTransfersByTransferIDExecuteHeaders = { readonly "Idempotency-Key": string } +export const PostTransfersByTransferIDExecuteHeaders = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostTransfersByTransferIDExecute200 = TransferResponse +export const PostTransfersByTransferIDExecute200 = TransferResponse +export type PostTransfersByTransferIDExecute400 = Error +export const PostTransfersByTransferIDExecute400 = Error +export type PostTransfersByTransferIDExecute401 = Error +export const PostTransfersByTransferIDExecute401 = Error +export type PostTransfersByTransferIDExecute404 = Error +export const PostTransfersByTransferIDExecute404 = Error +export type PostTransfersByTransferIDExecute500 = Error +export const PostTransfersByTransferIDExecute500 = Error +export type GetTransfersStaticTemplatesParams = { readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string } +export const GetTransfersStaticTemplatesParams = Schema.Struct({ "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String) }) +export type GetTransfersStaticTemplatesQuery = { readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string } +export const GetTransfersStaticTemplatesQuery = Schema.Struct({ "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String) }) +export type GetTransfersStaticTemplates200 = { readonly "count": number, readonly "data": ReadonlyArray } +export const GetTransfersStaticTemplates200 = Schema.Struct({ "count": Schema.Number.annotate({ "description": "The number of static templates returned" }).check(Schema.isInt().annotate({ "expected": "an integer" })), "data": Schema.Array(TransferResponse).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" })) }).annotate({ "title": "Static Templates" }) +export type GetTransfersStaticTemplates401 = Error +export const GetTransfersStaticTemplates401 = Error +export type GetTransfersStaticTemplates500 = Error +export const GetTransfersStaticTemplates500 = Error +export type GetPrefundedAccounts200 = { readonly "data": ReadonlyArray } +export const GetPrefundedAccounts200 = Schema.Struct({ "data": Schema.Array(PrefundedAccount).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" })) }).annotate({ "title": "Prefunded Accounts" }) +export type GetPrefundedAccounts401 = Error +export const GetPrefundedAccounts401 = Error +export type GetPrefundedAccounts404 = Error +export const GetPrefundedAccounts404 = Error +export type GetPrefundedAccounts500 = Error +export const GetPrefundedAccounts500 = Error +export type GetPrefundedAccountsByPrefundedAccountIDPathParams = { readonly "prefundedAccountID": Id } +export const GetPrefundedAccountsByPrefundedAccountIDPathParams = Schema.Struct({ "prefundedAccountID": Id }) +export type GetPrefundedAccountsByPrefundedAccountID200 = PrefundedAccount +export const GetPrefundedAccountsByPrefundedAccountID200 = PrefundedAccount +export type GetPrefundedAccountsByPrefundedAccountID401 = Error +export const GetPrefundedAccountsByPrefundedAccountID401 = Error +export type GetPrefundedAccountsByPrefundedAccountID404 = Error +export const GetPrefundedAccountsByPrefundedAccountID404 = Error +export type GetPrefundedAccountsByPrefundedAccountID500 = Error +export const GetPrefundedAccountsByPrefundedAccountID500 = Error +export type GetPrefundedAccountsByPrefundedAccountIDHistoryParams = { readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string } +export const GetPrefundedAccountsByPrefundedAccountIDHistoryParams = Schema.Struct({ "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String) }) +export type GetPrefundedAccountsByPrefundedAccountIDHistoryPathParams = { readonly "prefundedAccountID": Id } +export const GetPrefundedAccountsByPrefundedAccountIDHistoryPathParams = Schema.Struct({ "prefundedAccountID": Id }) +export type GetPrefundedAccountsByPrefundedAccountIDHistoryQuery = { readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string } +export const GetPrefundedAccountsByPrefundedAccountIDHistoryQuery = Schema.Struct({ "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String) }) +export type GetPrefundedAccountsByPrefundedAccountIDHistory200 = PrefundedAccountHistory +export const GetPrefundedAccountsByPrefundedAccountIDHistory200 = PrefundedAccountHistory +export type GetPrefundedAccountsByPrefundedAccountIDHistory401 = Error +export const GetPrefundedAccountsByPrefundedAccountIDHistory401 = Error +export type GetPrefundedAccountsByPrefundedAccountIDHistory404 = Error +export const GetPrefundedAccountsByPrefundedAccountIDHistory404 = Error +export type GetPrefundedAccountsByPrefundedAccountIDHistory500 = Error +export const GetPrefundedAccountsByPrefundedAccountIDHistory500 = Error +export type GetCustomersByCustomerIDWalletsParams = { readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string } +export const GetCustomersByCustomerIDWalletsParams = Schema.Struct({ "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String) }) +export type GetCustomersByCustomerIDWalletsPathParams = { readonly "customerID": Id } +export const GetCustomersByCustomerIDWalletsPathParams = Schema.Struct({ "customerID": Id }) +export type GetCustomersByCustomerIDWalletsQuery = { readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string } +export const GetCustomersByCustomerIDWalletsQuery = Schema.Struct({ "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String) }) +export type GetCustomersByCustomerIDWallets200 = BridgeWalletsList +export const GetCustomersByCustomerIDWallets200 = BridgeWalletsList +export type GetCustomersByCustomerIDWallets400 = Error +export const GetCustomersByCustomerIDWallets400 = Error +export type GetCustomersByCustomerIDWallets401 = Error +export const GetCustomersByCustomerIDWallets401 = Error +export type GetCustomersByCustomerIDWallets404 = Error +export const GetCustomersByCustomerIDWallets404 = Error +export type GetCustomersByCustomerIDWallets500 = Error +export const GetCustomersByCustomerIDWallets500 = Error +export type PostCustomersByCustomerIDWalletsParams = { readonly "Idempotency-Key": string } +export const PostCustomersByCustomerIDWalletsParams = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostCustomersByCustomerIDWalletsPathParams = { readonly "customerID": Id } +export const PostCustomersByCustomerIDWalletsPathParams = Schema.Struct({ "customerID": Id }) +export type PostCustomersByCustomerIDWalletsHeaders = { readonly "Idempotency-Key": string } +export const PostCustomersByCustomerIDWalletsHeaders = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostCustomersByCustomerIDWalletsRequestJson = CreateBridgeWallet +export const PostCustomersByCustomerIDWalletsRequestJson = CreateBridgeWallet +export type PostCustomersByCustomerIDWallets201 = CreateBridgeWalletResponse +export const PostCustomersByCustomerIDWallets201 = CreateBridgeWalletResponse +export type PostCustomersByCustomerIDWallets400 = Error +export const PostCustomersByCustomerIDWallets400 = Error +export type PostCustomersByCustomerIDWallets401 = Error +export const PostCustomersByCustomerIDWallets401 = Error +export type PostCustomersByCustomerIDWallets404 = Error +export const PostCustomersByCustomerIDWallets404 = Error +export type PostCustomersByCustomerIDWallets500 = Error +export const PostCustomersByCustomerIDWallets500 = Error +export type GetCustomersByCustomerIDWalletsByBridgeWalletIDPathParams = { readonly "customerID": Id, readonly "bridgeWalletID": Id } +export const GetCustomersByCustomerIDWalletsByBridgeWalletIDPathParams = Schema.Struct({ "customerID": Id, "bridgeWalletID": Id }) +export type GetCustomersByCustomerIDWalletsByBridgeWalletID200 = BridgeWalletWithBalances +export const GetCustomersByCustomerIDWalletsByBridgeWalletID200 = BridgeWalletWithBalances +export type GetCustomersByCustomerIDWalletsByBridgeWalletID400 = Error +export const GetCustomersByCustomerIDWalletsByBridgeWalletID400 = Error +export type GetCustomersByCustomerIDWalletsByBridgeWalletID401 = Error +export const GetCustomersByCustomerIDWalletsByBridgeWalletID401 = Error +export type GetCustomersByCustomerIDWalletsByBridgeWalletID404 = Error +export const GetCustomersByCustomerIDWalletsByBridgeWalletID404 = Error +export type GetCustomersByCustomerIDWalletsByBridgeWalletID500 = Error +export const GetCustomersByCustomerIDWalletsByBridgeWalletID500 = Error +export type GetCustomersByCustomerIDLiquidationAddressesParams = { readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string } +export const GetCustomersByCustomerIDLiquidationAddressesParams = Schema.Struct({ "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String) }) +export type GetCustomersByCustomerIDLiquidationAddressesPathParams = { readonly "customerID": Id } +export const GetCustomersByCustomerIDLiquidationAddressesPathParams = Schema.Struct({ "customerID": Id }) +export type GetCustomersByCustomerIDLiquidationAddressesQuery = { readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string } +export const GetCustomersByCustomerIDLiquidationAddressesQuery = Schema.Struct({ "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String) }) +export type GetCustomersByCustomerIDLiquidationAddresses200 = { readonly "count": number, readonly "data": ReadonlyArray } +export const GetCustomersByCustomerIDLiquidationAddresses200 = Schema.Struct({ "count": Schema.Number.annotate({ "description": "total number of items in data" }).check(Schema.isInt().annotate({ "expected": "an integer" })), "data": Schema.Array(LiquidationAddress).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" })) }).annotate({ "title": "Liquidation Addresses" }) +export type GetCustomersByCustomerIDLiquidationAddresses400 = Error +export const GetCustomersByCustomerIDLiquidationAddresses400 = Error +export type GetCustomersByCustomerIDLiquidationAddresses401 = Error +export const GetCustomersByCustomerIDLiquidationAddresses401 = Error +export type GetCustomersByCustomerIDLiquidationAddresses500 = Error +export const GetCustomersByCustomerIDLiquidationAddresses500 = Error +export type PostCustomersByCustomerIDLiquidationAddressesParams = { readonly "Idempotency-Key": string } +export const PostCustomersByCustomerIDLiquidationAddressesParams = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostCustomersByCustomerIDLiquidationAddressesPathParams = { readonly "customerID": Id } +export const PostCustomersByCustomerIDLiquidationAddressesPathParams = Schema.Struct({ "customerID": Id }) +export type PostCustomersByCustomerIDLiquidationAddressesHeaders = { readonly "Idempotency-Key": string } +export const PostCustomersByCustomerIDLiquidationAddressesHeaders = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostCustomersByCustomerIDLiquidationAddressesRequestJson = CreateLiquidationAddress +export const PostCustomersByCustomerIDLiquidationAddressesRequestJson = CreateLiquidationAddress +export type PostCustomersByCustomerIDLiquidationAddresses201 = CreateLiquidationAddressResponse +export const PostCustomersByCustomerIDLiquidationAddresses201 = CreateLiquidationAddressResponse +export type PostCustomersByCustomerIDLiquidationAddresses400 = Error +export const PostCustomersByCustomerIDLiquidationAddresses400 = Error +export type PostCustomersByCustomerIDLiquidationAddresses401 = Error +export const PostCustomersByCustomerIDLiquidationAddresses401 = Error +export type PostCustomersByCustomerIDLiquidationAddresses500 = Error +export const PostCustomersByCustomerIDLiquidationAddresses500 = Error +export type GetLiquidationAddressesParams = { readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string } +export const GetLiquidationAddressesParams = Schema.Struct({ "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String) }) +export type GetLiquidationAddressesQuery = { readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string } +export const GetLiquidationAddressesQuery = Schema.Struct({ "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String) }) +export type GetLiquidationAddresses200 = { readonly "count": number, readonly "data": ReadonlyArray } +export const GetLiquidationAddresses200 = Schema.Struct({ "count": Schema.Number.annotate({ "description": "total number of items in data" }).check(Schema.isInt().annotate({ "expected": "an integer" })), "data": Schema.Array(LiquidationAddress).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" })) }).annotate({ "title": "Liquidation Addresses" }) +export type GetLiquidationAddresses400 = Error +export const GetLiquidationAddresses400 = Error +export type GetLiquidationAddresses401 = Error +export const GetLiquidationAddresses401 = Error +export type GetLiquidationAddresses500 = Error +export const GetLiquidationAddresses500 = Error +export type GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDPathParams = { readonly "customerID": Id, readonly "liquidationAddressID": Id } +export const GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDPathParams = Schema.Struct({ "customerID": Id, "liquidationAddressID": Id }) +export type GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressID200 = LiquidationAddress +export const GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressID200 = LiquidationAddress +export type GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressID400 = Error +export const GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressID400 = Error +export type GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressID401 = Error +export const GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressID401 = Error +export type GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressID404 = Error +export const GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressID404 = Error +export type GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressID500 = Error +export const GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressID500 = Error +export type PutCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDPathParams = { readonly "customerID": Id, readonly "liquidationAddressID": Id } +export const PutCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDPathParams = Schema.Struct({ "customerID": Id, "liquidationAddressID": Id }) +export type PutCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDRequestJson = UpdateLiquidationAddress +export const PutCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDRequestJson = UpdateLiquidationAddress +export type PutCustomersByCustomerIDLiquidationAddressesByLiquidationAddressID200 = LiquidationAddress +export const PutCustomersByCustomerIDLiquidationAddressesByLiquidationAddressID200 = LiquidationAddress +export type PutCustomersByCustomerIDLiquidationAddressesByLiquidationAddressID400 = Error +export const PutCustomersByCustomerIDLiquidationAddressesByLiquidationAddressID400 = Error +export type PutCustomersByCustomerIDLiquidationAddressesByLiquidationAddressID401 = Error +export const PutCustomersByCustomerIDLiquidationAddressesByLiquidationAddressID401 = Error +export type PutCustomersByCustomerIDLiquidationAddressesByLiquidationAddressID500 = Error +export const PutCustomersByCustomerIDLiquidationAddressesByLiquidationAddressID500 = Error +export type GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDDrainsParams = { readonly "tx_hash"?: string, readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string, readonly "updated_after_ms"?: number, readonly "updated_before_ms"?: number, readonly "drain_id"?: string } +export const GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDDrainsParams = Schema.Struct({ "tx_hash": Schema.optionalKey(Schema.String), "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String), "updated_after_ms": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), "updated_before_ms": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), "drain_id": Schema.optionalKey(Schema.String) }) +export type GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDDrainsPathParams = { readonly "customerID": Id, readonly "liquidationAddressID": Id } +export const GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDDrainsPathParams = Schema.Struct({ "customerID": Id, "liquidationAddressID": Id }) +export type GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDDrainsQuery = { readonly "tx_hash"?: string, readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string, readonly "updated_after_ms"?: number, readonly "updated_before_ms"?: number, readonly "drain_id"?: string } +export const GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDDrainsQuery = Schema.Struct({ "tx_hash": Schema.optionalKey(Schema.String), "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String), "updated_after_ms": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), "updated_before_ms": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), "drain_id": Schema.optionalKey(Schema.String) }) +export type GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDDrains200 = null | string | number | boolean | { readonly "data"?: Drain } & { readonly [x: string]: Schema.Json } | ReadonlyArray +export const GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDDrains200 = Schema.Union([Schema.Null, Schema.String, Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), Schema.Boolean, Schema.StructWithRest(Schema.Struct({ "data": Schema.optionalKey(Drain) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]), Schema.Array(Schema.Json.annotate({ "expected": "JSON value" }))]) +export type GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDDrains400 = Error +export const GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDDrains400 = Error +export type GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDDrains401 = Error +export const GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDDrains401 = Error +export type GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDDrains500 = Error +export const GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDDrains500 = Error +export type PostCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDDrainsByDrainIDExecuteParams = { readonly "Idempotency-Key": string } +export const PostCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDDrainsByDrainIDExecuteParams = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDDrainsByDrainIDExecutePathParams = { readonly "customerID": Id, readonly "liquidationAddressID": Id, readonly "drainID": Id } +export const PostCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDDrainsByDrainIDExecutePathParams = Schema.Struct({ "customerID": Id, "liquidationAddressID": Id, "drainID": Id }) +export type PostCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDDrainsByDrainIDExecuteHeaders = { readonly "Idempotency-Key": string } +export const PostCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDDrainsByDrainIDExecuteHeaders = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDDrainsByDrainIDExecute200 = Drain +export const PostCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDDrainsByDrainIDExecute200 = Drain +export type PostCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDDrainsByDrainIDExecute400 = Error +export const PostCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDDrainsByDrainIDExecute400 = Error +export type PostCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDDrainsByDrainIDExecute401 = Error +export const PostCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDDrainsByDrainIDExecute401 = Error +export type PostCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDDrainsByDrainIDExecute404 = Error +export const PostCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDDrainsByDrainIDExecute404 = Error +export type PostCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDDrainsByDrainIDExecute500 = Error +export const PostCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDDrainsByDrainIDExecute500 = Error +export type GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDBalancesPathParams = { readonly "customerID": Id, readonly "liquidationAddressID": Id } +export const GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDBalancesPathParams = Schema.Struct({ "customerID": Id, "liquidationAddressID": Id }) +export type GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDBalances200 = null | string | number | boolean | { readonly "data"?: Balance } & { readonly [x: string]: Schema.Json } | ReadonlyArray +export const GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDBalances200 = Schema.Union([Schema.Null, Schema.String, Schema.Number.check(Schema.isFinite().annotate({ "expected": "a finite number" })), Schema.Boolean, Schema.StructWithRest(Schema.Struct({ "data": Schema.optionalKey(Balance) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]), Schema.Array(Schema.Json.annotate({ "expected": "JSON value" }))]) +export type GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDBalances400 = Error +export const GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDBalances400 = Error +export type GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDBalances401 = Error +export const GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDBalances401 = Error +export type GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDBalances500 = Error +export const GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDBalances500 = Error +export type GetCustomersByCustomerIDVirtualAccountsParams = { readonly "status"?: VirtualAccountActivationStatus, readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string } +export const GetCustomersByCustomerIDVirtualAccountsParams = Schema.Struct({ "status": Schema.optionalKey(VirtualAccountActivationStatus), "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String) }) +export type GetCustomersByCustomerIDVirtualAccountsPathParams = { readonly "customerID": Id } +export const GetCustomersByCustomerIDVirtualAccountsPathParams = Schema.Struct({ "customerID": Id }) +export type GetCustomersByCustomerIDVirtualAccountsQuery = { readonly "status"?: VirtualAccountActivationStatus, readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string } +export const GetCustomersByCustomerIDVirtualAccountsQuery = Schema.Struct({ "status": Schema.optionalKey(VirtualAccountActivationStatus), "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String) }) +export type GetCustomersByCustomerIDVirtualAccounts200 = { readonly "count": number, readonly "data": ReadonlyArray } +export const GetCustomersByCustomerIDVirtualAccounts200 = Schema.Struct({ "count": Schema.Number.annotate({ "description": "total number of items in data" }).check(Schema.isInt().annotate({ "expected": "an integer" })), "data": Schema.Array(VirtualAccountResponse).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" })) }).annotate({ "title": "Virtual Accounts" }) +export type PostCustomersByCustomerIDVirtualAccountsParams = { readonly "Idempotency-Key": string } +export const PostCustomersByCustomerIDVirtualAccountsParams = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostCustomersByCustomerIDVirtualAccountsPathParams = { readonly "customerID": Id } +export const PostCustomersByCustomerIDVirtualAccountsPathParams = Schema.Struct({ "customerID": Id }) +export type PostCustomersByCustomerIDVirtualAccountsHeaders = { readonly "Idempotency-Key": string } +export const PostCustomersByCustomerIDVirtualAccountsHeaders = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostCustomersByCustomerIDVirtualAccountsRequestJson = CreateVirtualAccount +export const PostCustomersByCustomerIDVirtualAccountsRequestJson = CreateVirtualAccount +export type PostCustomersByCustomerIDVirtualAccounts200 = VirtualAccountResponse +export const PostCustomersByCustomerIDVirtualAccounts200 = VirtualAccountResponse +export type GetCustomersByCustomerIDVirtualAccountsByVirtualAccountIDPathParams = { readonly "customerID": Id, readonly "virtualAccountID": Id } +export const GetCustomersByCustomerIDVirtualAccountsByVirtualAccountIDPathParams = Schema.Struct({ "customerID": Id, "virtualAccountID": Id }) +export type GetCustomersByCustomerIDVirtualAccountsByVirtualAccountID200 = VirtualAccountResponse +export const GetCustomersByCustomerIDVirtualAccountsByVirtualAccountID200 = VirtualAccountResponse +export type PutCustomersByCustomerIDVirtualAccountsByVirtualAccountIDPathParams = { readonly "customerID": Id, readonly "virtualAccountID": Id } +export const PutCustomersByCustomerIDVirtualAccountsByVirtualAccountIDPathParams = Schema.Struct({ "customerID": Id, "virtualAccountID": Id }) +export type PutCustomersByCustomerIDVirtualAccountsByVirtualAccountIDRequestJson = UpdateVirtualAccount +export const PutCustomersByCustomerIDVirtualAccountsByVirtualAccountIDRequestJson = UpdateVirtualAccount +export type PutCustomersByCustomerIDVirtualAccountsByVirtualAccountID200 = VirtualAccountResponse +export const PutCustomersByCustomerIDVirtualAccountsByVirtualAccountID200 = VirtualAccountResponse +export type PostCustomersByCustomerIDVirtualAccountsByVirtualAccountIDDeactivateParams = { readonly "Idempotency-Key": string } +export const PostCustomersByCustomerIDVirtualAccountsByVirtualAccountIDDeactivateParams = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostCustomersByCustomerIDVirtualAccountsByVirtualAccountIDDeactivatePathParams = { readonly "customerID": Id, readonly "virtualAccountID": Id } +export const PostCustomersByCustomerIDVirtualAccountsByVirtualAccountIDDeactivatePathParams = Schema.Struct({ "customerID": Id, "virtualAccountID": Id }) +export type PostCustomersByCustomerIDVirtualAccountsByVirtualAccountIDDeactivateHeaders = { readonly "Idempotency-Key": string } +export const PostCustomersByCustomerIDVirtualAccountsByVirtualAccountIDDeactivateHeaders = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostCustomersByCustomerIDVirtualAccountsByVirtualAccountIDDeactivate200 = { readonly "id"?: string, readonly "status"?: "activated" | "deactivated", readonly "developer_fee_percent"?: string, readonly "fee_config"?: { readonly "source"?: { readonly [x: string]: { readonly "fee_percent"?: string, readonly "fee_amount"?: string, readonly "minimum_fee"?: string, readonly "maximum_fee"?: string } } }, readonly "customer_id"?: string, readonly "created_at"?: string, readonly "source_deposit_instructions"?: { readonly "bank_account_number": string, readonly "bank_routing_number": string, readonly "bank_beneficiary_name": string, readonly "bank_beneficiary_address": string, readonly "currency": "usd", readonly "payment_rail"?: "ach_push" | "bre_b" | "faster_payments" | "pix" | "sepa" | "spei" | "wire", readonly "payment_rails": ReadonlyArray<"ach_push" | "fednow" | "wire">, readonly "bank_name": string, readonly "bank_address": string } & { readonly [x: string]: Schema.Json } | { readonly "iban": string, readonly "bic": string, readonly "account_holder_name": string, readonly "bank_beneficiary_name"?: string, readonly "bank_beneficiary_address"?: string, readonly "currency": "eur", readonly "payment_rails": "sepa", readonly "bank_name": string, readonly "bank_address": string } & { readonly [x: string]: Schema.Json } | { readonly "clabe": string, readonly "account_holder_name": string, readonly "currency": "mxn", readonly "payment_rails": ReadonlyArray<"spei">, readonly "bank_name": string, readonly "bank_address": string } & { readonly [x: string]: Schema.Json } | { readonly "br_code": string, readonly "account_holder_name": string, readonly "currency": "brl", readonly "payment_rails": ReadonlyArray<"pix">, readonly "bank_name": string, readonly "bank_address": string } & { readonly [x: string]: Schema.Json } | { readonly "account_number": string, readonly "sort_code": string, readonly "account_holder_name": string, readonly "bank_beneficiary_name"?: string, readonly "bank_beneficiary_address"?: string, readonly "currency": "gbp", readonly "payment_rails": "faster_payments", readonly "bank_name": string, readonly "bank_address": string } & { readonly [x: string]: Schema.Json } | { readonly "bre_b_key": string, readonly "account_holder_name": string, readonly "deposit_message"?: string, readonly "currency": "cop", readonly "payment_rails": ReadonlyArray<"bre_b">, readonly "bank_name": string, readonly "bank_address": string } & { readonly [x: string]: Schema.Json }, readonly "destination"?: { readonly "currency": "usdb" | "usdc" | "usdt" | "usdl_linea" | "pyusd" | "eurc", readonly "payment_rail": "arbitrum" | "avalanche_c_chain" | "base" | "celo" | "ethereum" | "linea" | "optimism" | "polygon" | "solana" | "stellar" | "tempo" | "tron" | "xdc", readonly "address"?: string, readonly "blockchain_memo"?: string, readonly "bridge_wallet_id"?: string, readonly "prefunded_account_id"?: string } & { readonly [x: string]: Schema.Json } } & { readonly [x: string]: Schema.Json } +export const PostCustomersByCustomerIDVirtualAccountsByVirtualAccountIDDeactivate200 = Schema.StructWithRest(Schema.Struct({ "id": Schema.optionalKey(Schema.String.annotate({ "description": "A UUID that uniquely identifies a resource", "readOnly": true }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "status": Schema.optionalKey(Schema.Literals(["activated", "deactivated"]).annotate({ "description": "The activation status of the Virtual Account", "examples": ["deactivated"] })), "developer_fee_percent": Schema.optionalKey(Schema.String.annotate({ "description": "The developer fee percent that will be applied to this Virtual Account. The value is a base 100 percentage, i.e. 10.2% is 10.2 in the API.", "examples": ["0.1"], "format": "number" })), "fee_config": Schema.optionalKey(Schema.Struct({ "source": Schema.optionalKey(Schema.Record(Schema.String, Schema.Struct({ "fee_percent": Schema.optionalKey(Schema.String.annotate({ "description": "Percentage fee (0-100, exclusive). Applied to the amount remaining after any flat fee deduction.", "examples": ["1.5"], "format": "number" })), "fee_amount": Schema.optionalKey(Schema.String.annotate({ "description": "Flat fee amount deducted before percentage calculation", "examples": ["10.00"], "format": "number" })), "minimum_fee": Schema.optionalKey(Schema.String.annotate({ "description": "Minimum total fee floor", "examples": ["1.00"], "format": "number" })), "maximum_fee": Schema.optionalKey(Schema.String.annotate({ "description": "Maximum total fee cap", "examples": ["1000.00"], "format": "number" })) }).annotate({ "description": "Fee parameters for a specific payment rail or default configuration" })).annotate({ "description": "Source-side fee configuration keyed by payment rail or `default`", "examples": [{ "default": { "fee_percent": "0.5", "minimum_fee": "1.00" }, "wire": { "fee_amount": "10.00", "fee_percent": "1.0" } }] })) }).annotate({ "description": "Developer fee configuration. Available by request only. Contact Bridge to enable this feature for your developer account. Responses render source-side fees keyed by payment rail, using `default` for a catch-all configuration." })), "customer_id": Schema.optionalKey(Schema.String.annotate({ "description": "A UUID that uniquely identifies a resource" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "created_at": Schema.optionalKey(Schema.String.annotate({ "description": "Time of creation of the virtual account", "readOnly": true, "format": "date-time" })), "source_deposit_instructions": Schema.optionalKey(Schema.Union([Schema.StructWithRest(Schema.Struct({ "bank_account_number": Schema.String.annotate({ "description": "The account number of the bank that the customer should send the deposit to" }), "bank_routing_number": Schema.String.annotate({ "description": "The routing number of the bank that the customer should send the deposit to" }), "bank_beneficiary_name": Schema.String.annotate({ "description": "If available, the name of the beneficiary of the bank account that the customer should send the deposit to" }), "bank_beneficiary_address": Schema.String.annotate({ "description": "If available, the address of the beneficiary of the bank account that the customer should send the deposit to" }), "currency": Schema.Literal("usd"), "payment_rail": Schema.optionalKey(Schema.Literals(["ach_push", "bre_b", "faster_payments", "pix", "sepa", "spei", "wire"])), "payment_rails": Schema.Array(Schema.Literals(["ach_push", "fednow", "wire"])).annotate({ "description": "The payment rails supported by these deposit instructions" }), "bank_name": Schema.String.annotate({ "description": "The name of the bank that the customer should send the deposit to" }), "bank_address": Schema.String.annotate({ "description": "The address of the bank that the customer should send the deposit to" }) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "title": "Virtual Account US", "examples": [{ "currency": "usd", "payment_rails": ["ach_push", "fednow", "wire"], "bank_name": "Lead Bank", "bank_address": "1801 Main St., Kansas City, MO 64108", "bank_beneficiary_name": "Customer Name", "bank_beneficiary_address": "1234 Main St., Kansas City, MO 64108", "bank_account_number": "123456789", "bank_routing_number": "87654321" }], "readOnly": true }), Schema.StructWithRest(Schema.Struct({ "iban": Schema.String.annotate({ "description": "he IBAN of the account that the customer should send the deposit to" }), "bic": Schema.String.annotate({ "description": "The BIC of the bank that the customer should send the deposit to" }), "account_holder_name": Schema.String.annotate({ "description": "The name of the account owner that the deposit must be sent to." }), "bank_beneficiary_name": Schema.optionalKey(Schema.String.annotate({ "description": "The account beneficiary name — the customer for POBO accounts, otherwise the Bridge legal entity. Senders should match this name." })), "bank_beneficiary_address": Schema.optionalKey(Schema.String.annotate({ "description": "The account beneficiary address. Present for POBO accounts (the customer's registered address)." })), "currency": Schema.Literal("eur"), "payment_rails": Schema.Literal("sepa"), "bank_name": Schema.String.annotate({ "description": "The name of the bank that the customer should send the deposit to" }), "bank_address": Schema.String.annotate({ "description": "The address of the bank that the customer should send the deposit to" }) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "title": "Virtual IBAN", "readOnly": true }), Schema.StructWithRest(Schema.Struct({ "clabe": Schema.String.annotate({ "description": "The CLABE (account number) of the account that the customer should send the deposit to" }), "account_holder_name": Schema.String.annotate({ "description": "The name of the account owner that the deposit must be sent to." }), "currency": Schema.Literal("mxn"), "payment_rails": Schema.Array(Schema.Literal("spei")).annotate({ "description": "The payment rails supported by these deposit instructions" }), "bank_name": Schema.String.annotate({ "description": "The name of the bank that the customer should send the deposit to" }), "bank_address": Schema.String.annotate({ "description": "The address of the bank that the customer should send the deposit to" }) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "title": "Virtual Account MX", "readOnly": true }), Schema.StructWithRest(Schema.Struct({ "br_code": Schema.String.annotate({ "description": "The BR Code that the customer should send the deposit to" }), "account_holder_name": Schema.String.annotate({ "description": "The name of the account owner that the deposit must be sent to." }), "currency": Schema.Literal("brl"), "payment_rails": Schema.Array(Schema.Literal("pix")).annotate({ "description": "The payment rails supported by these deposit instructions" }), "bank_name": Schema.String.annotate({ "description": "The name of the bank that the customer should send the deposit to" }), "bank_address": Schema.String.annotate({ "description": "The address of the bank that the customer should send the deposit to" }) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "title": "Virtual Account BR", "readOnly": true }), Schema.StructWithRest(Schema.Struct({ "account_number": Schema.String.annotate({ "description": "The bank account number" }).check(Schema.isMinLength(8).annotate({ "expected": "a value with a length of at least 8" })).check(Schema.isMaxLength(8).annotate({ "expected": "a value with a length of at most 8" })), "sort_code": Schema.String.annotate({ "description": "The sort code, without hyphens" }).check(Schema.isMinLength(6).annotate({ "expected": "a value with a length of at least 6" })).check(Schema.isMaxLength(6).annotate({ "expected": "a value with a length of at most 6" })), "account_holder_name": Schema.String.annotate({ "description": "The name of the account owner that the deposit must be sent to." }), "bank_beneficiary_name": Schema.optionalKey(Schema.String.annotate({ "description": "The account beneficiary name — the customer for POBO accounts, otherwise the Bridge legal entity. Senders should match this name." })), "bank_beneficiary_address": Schema.optionalKey(Schema.String.annotate({ "description": "The account beneficiary address. Present for POBO accounts (the customer's registered address)." })), "currency": Schema.Literal("gbp"), "payment_rails": Schema.Literal("faster_payments"), "bank_name": Schema.String.annotate({ "description": "The name of the bank that the customer should send the deposit to" }), "bank_address": Schema.String.annotate({ "description": "The address of the bank that the customer should send the deposit to" }) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "title": "gb", "readOnly": true }), Schema.StructWithRest(Schema.Struct({ "bre_b_key": Schema.String.annotate({ "description": "The Bre-B key of the Colombian bank account for receiving COP deposits" }), "account_holder_name": Schema.String.annotate({ "description": "The name of the account owner that the deposit must be sent to." }), "deposit_message": Schema.optionalKey(Schema.String.annotate({ "description": "The reference message to include with the COP deposit" })), "currency": Schema.Literal("cop"), "payment_rails": Schema.Array(Schema.Literal("bre_b")).annotate({ "description": "The payment rails supported by these deposit instructions" }), "bank_name": Schema.String.annotate({ "description": "The name of the bank that the customer should send the deposit to" }), "bank_address": Schema.String.annotate({ "description": "The address of the bank that the customer should send the deposit to" }) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "title": "Virtual Account CO (Bre-B)", "readOnly": true })], { mode: "oneOf" }).annotate({ "title": "Source Deposit Instructions", "readOnly": true })), "destination": Schema.optionalKey(Schema.StructWithRest(Schema.Struct({ "currency": Schema.Literals(["usdb", "usdc", "usdt", "usdl_linea", "pyusd", "eurc"]), "payment_rail": Schema.Literals(["arbitrum", "avalanche_c_chain", "base", "celo", "ethereum", "linea", "optimism", "polygon", "solana", "stellar", "tempo", "tron", "xdc"]), "address": Schema.optionalKey(Schema.String.annotate({ "description": "The crypto wallet address that the customer wishes to ultimately receive funds at" })), "blockchain_memo": Schema.optionalKey(Schema.String.annotate({ "description": "The memo to include when sending funds on chain. Only allowed for blockchains that support memos such as Stellar" })), "bridge_wallet_id": Schema.optionalKey(Schema.String.annotate({ "description": "The Bridge Wallet to which Bridge will send the funds. The chain associated with the Bridge Wallet must match the payment rail." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))), "prefunded_account_id": Schema.optionalKey(Schema.String.annotate({ "description": "The id of the prefunded account to which the funds will be sent. Use 'prefunded' as the payment rail and 'usd' as the currency when specifying a prefunded account id." }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" }))) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "examples": [{ "currency": "usdc", "payment_rail": "polygon", "address": "0xdeadbeef" }] })) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]) +export type PostCustomersByCustomerIDVirtualAccountsByVirtualAccountIDReactivateParams = { readonly "Idempotency-Key": string } +export const PostCustomersByCustomerIDVirtualAccountsByVirtualAccountIDReactivateParams = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostCustomersByCustomerIDVirtualAccountsByVirtualAccountIDReactivatePathParams = { readonly "customerID": Id, readonly "virtualAccountID": Id } +export const PostCustomersByCustomerIDVirtualAccountsByVirtualAccountIDReactivatePathParams = Schema.Struct({ "customerID": Id, "virtualAccountID": Id }) +export type PostCustomersByCustomerIDVirtualAccountsByVirtualAccountIDReactivateHeaders = { readonly "Idempotency-Key": string } +export const PostCustomersByCustomerIDVirtualAccountsByVirtualAccountIDReactivateHeaders = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostCustomersByCustomerIDVirtualAccountsByVirtualAccountIDReactivate200 = VirtualAccountResponse +export const PostCustomersByCustomerIDVirtualAccountsByVirtualAccountIDReactivate200 = VirtualAccountResponse +export type GetCustomersByCustomerIDVirtualAccountsByVirtualAccountIDHistoryParams = { readonly "deposit_id"?: string, readonly "deposit_ids"?: ReadonlyArray, readonly "tx_hash"?: string, readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string, readonly "event_type"?: "funds_received" | "payment_submitted" | "payment_processed" | "in_review" | "refund" | "refund_in_flight" | "refund_failed" | "microdeposit" | "account_update" | "deactivation" | "activation" } +export const GetCustomersByCustomerIDVirtualAccountsByVirtualAccountIDHistoryParams = Schema.Struct({ "deposit_id": Schema.optionalKey(Schema.String), "deposit_ids": Schema.optionalKey(Schema.Array(Schema.String)), "tx_hash": Schema.optionalKey(Schema.String), "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String), "event_type": Schema.optionalKey(Schema.Literals(["funds_received", "payment_submitted", "payment_processed", "in_review", "refund", "refund_in_flight", "refund_failed", "microdeposit", "account_update", "deactivation", "activation"])) }) +export type GetCustomersByCustomerIDVirtualAccountsByVirtualAccountIDHistoryPathParams = { readonly "customerID": Id, readonly "virtualAccountID": Id } +export const GetCustomersByCustomerIDVirtualAccountsByVirtualAccountIDHistoryPathParams = Schema.Struct({ "customerID": Id, "virtualAccountID": Id }) +export type GetCustomersByCustomerIDVirtualAccountsByVirtualAccountIDHistoryQuery = { readonly "deposit_id"?: string, readonly "deposit_ids"?: ReadonlyArray, readonly "tx_hash"?: string, readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string, readonly "event_type"?: "funds_received" | "payment_submitted" | "payment_processed" | "in_review" | "refund" | "refund_in_flight" | "refund_failed" | "microdeposit" | "account_update" | "deactivation" | "activation" } +export const GetCustomersByCustomerIDVirtualAccountsByVirtualAccountIDHistoryQuery = Schema.Struct({ "deposit_id": Schema.optionalKey(Schema.String), "deposit_ids": Schema.optionalKey(Schema.Array(Schema.String)), "tx_hash": Schema.optionalKey(Schema.String), "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String), "event_type": Schema.optionalKey(Schema.Literals(["funds_received", "payment_submitted", "payment_processed", "in_review", "refund", "refund_in_flight", "refund_failed", "microdeposit", "account_update", "deactivation", "activation"])) }) +export type GetCustomersByCustomerIDVirtualAccountsByVirtualAccountIDHistory200 = { readonly "count": number, readonly "data": ReadonlyArray } +export const GetCustomersByCustomerIDVirtualAccountsByVirtualAccountIDHistory200 = Schema.Struct({ "count": Schema.Number.annotate({ "description": "The number of events returned" }).check(Schema.isInt().annotate({ "expected": "an integer" })), "data": Schema.Array(VirtualAccountEvent).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" })) }).annotate({ "title": "Virtual Account history" }) +export type GetStaticMemosParams = { readonly "status"?: VirtualAccountActivationStatus, readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string } +export const GetStaticMemosParams = Schema.Struct({ "status": Schema.optionalKey(VirtualAccountActivationStatus), "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String) }) +export type GetStaticMemosQuery = { readonly "status"?: VirtualAccountActivationStatus, readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string } +export const GetStaticMemosQuery = Schema.Struct({ "status": Schema.optionalKey(VirtualAccountActivationStatus), "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String) }) +export type GetStaticMemos200 = { readonly "count": number, readonly "data": ReadonlyArray } +export const GetStaticMemos200 = Schema.Struct({ "count": Schema.Number.annotate({ "description": "total number of items in data" }).check(Schema.isInt().annotate({ "expected": "an integer" })), "data": Schema.Array(StaticMemoResponse).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" })) }).annotate({ "title": "Static Memos" }) +export type GetCustomersByCustomerIDStaticMemosParams = { readonly "status"?: VirtualAccountActivationStatus, readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string } +export const GetCustomersByCustomerIDStaticMemosParams = Schema.Struct({ "status": Schema.optionalKey(VirtualAccountActivationStatus), "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String) }) +export type GetCustomersByCustomerIDStaticMemosPathParams = { readonly "customerID": Id } +export const GetCustomersByCustomerIDStaticMemosPathParams = Schema.Struct({ "customerID": Id }) +export type GetCustomersByCustomerIDStaticMemosQuery = { readonly "status"?: VirtualAccountActivationStatus, readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string } +export const GetCustomersByCustomerIDStaticMemosQuery = Schema.Struct({ "status": Schema.optionalKey(VirtualAccountActivationStatus), "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String) }) +export type GetCustomersByCustomerIDStaticMemos200 = { readonly "count": number, readonly "data": ReadonlyArray } +export const GetCustomersByCustomerIDStaticMemos200 = Schema.Struct({ "count": Schema.Number.annotate({ "description": "total number of items in data" }).check(Schema.isInt().annotate({ "expected": "an integer" })), "data": Schema.Array(StaticMemoResponse).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" })) }).annotate({ "title": "Static Memos" }) +export type PostCustomersByCustomerIDStaticMemosParams = { readonly "Idempotency-Key": string } +export const PostCustomersByCustomerIDStaticMemosParams = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostCustomersByCustomerIDStaticMemosPathParams = { readonly "customerID": Id } +export const PostCustomersByCustomerIDStaticMemosPathParams = Schema.Struct({ "customerID": Id }) +export type PostCustomersByCustomerIDStaticMemosHeaders = { readonly "Idempotency-Key": string } +export const PostCustomersByCustomerIDStaticMemosHeaders = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostCustomersByCustomerIDStaticMemosRequestJson = CreateStaticMemo +export const PostCustomersByCustomerIDStaticMemosRequestJson = CreateStaticMemo +export type PostCustomersByCustomerIDStaticMemos200 = StaticMemoResponse +export const PostCustomersByCustomerIDStaticMemos200 = StaticMemoResponse +export type GetCustomersByCustomerIDStaticMemosByStaticMemoIDPathParams = { readonly "customerID": Id, readonly "staticMemoID": Id } +export const GetCustomersByCustomerIDStaticMemosByStaticMemoIDPathParams = Schema.Struct({ "customerID": Id, "staticMemoID": Id }) +export type GetCustomersByCustomerIDStaticMemosByStaticMemoID200 = StaticMemoResponse +export const GetCustomersByCustomerIDStaticMemosByStaticMemoID200 = StaticMemoResponse +export type PutCustomersByCustomerIDStaticMemosByStaticMemoIDPathParams = { readonly "customerID": Id, readonly "staticMemoID": Id } +export const PutCustomersByCustomerIDStaticMemosByStaticMemoIDPathParams = Schema.Struct({ "customerID": Id, "staticMemoID": Id }) +export type PutCustomersByCustomerIDStaticMemosByStaticMemoIDRequestJson = UpdateStaticMemo +export const PutCustomersByCustomerIDStaticMemosByStaticMemoIDRequestJson = UpdateStaticMemo +export type PutCustomersByCustomerIDStaticMemosByStaticMemoID200 = StaticMemoResponse +export const PutCustomersByCustomerIDStaticMemosByStaticMemoID200 = StaticMemoResponse +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDPinParams = { readonly "Idempotency-Key": string } +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDPinParams = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDPinPathParams = { readonly "customerID": Id, readonly "cardAccountID": string } +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDPinPathParams = Schema.Struct({ "customerID": Id, "cardAccountID": Schema.String.annotate({ "format": "uuid" }) }) +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDPinHeaders = { readonly "Idempotency-Key": string } +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDPinHeaders = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDPin200 = CardPinUpdateResponse +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDPin200 = CardPinUpdateResponse +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDPin400 = Error +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDPin400 = Error +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDPin401 = Error +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDPin401 = Error +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDPin500 = Error +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDPin500 = Error +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDEphemeralKeysParams = { readonly "Idempotency-Key": string } +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDEphemeralKeysParams = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDEphemeralKeysPathParams = { readonly "customerID": Id, readonly "cardAccountID": string } +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDEphemeralKeysPathParams = Schema.Struct({ "customerID": Id, "cardAccountID": Schema.String.annotate({ "format": "uuid" }) }) +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDEphemeralKeysHeaders = { readonly "Idempotency-Key": string } +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDEphemeralKeysHeaders = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDEphemeralKeysRequestJson = PostCardAccountEphemeralKeyInput +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDEphemeralKeysRequestJson = PostCardAccountEphemeralKeyInput +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDEphemeralKeys200 = CardAccountEphemeralKeyResponse +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDEphemeralKeys200 = CardAccountEphemeralKeyResponse +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDEphemeralKeys400 = Error +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDEphemeralKeys400 = Error +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDEphemeralKeys401 = Error +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDEphemeralKeys401 = Error +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDEphemeralKeys500 = Error +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDEphemeralKeys500 = Error +export type GetCustomersByCustomerIDStaticMemosByStaticMemoIDHistoryParams = { readonly "deposit_id"?: string, readonly "deposit_ids"?: ReadonlyArray, readonly "tx_hash"?: string, readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string, readonly "event_type"?: "funds_received" | "payment_submitted" | "payment_processed" | "in_review" | "refund" | "refund_in_flight" | "refund_failed" | "microdeposit" | "account_update" | "deactivation" | "activation" } +export const GetCustomersByCustomerIDStaticMemosByStaticMemoIDHistoryParams = Schema.Struct({ "deposit_id": Schema.optionalKey(Schema.String), "deposit_ids": Schema.optionalKey(Schema.Array(Schema.String)), "tx_hash": Schema.optionalKey(Schema.String), "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String), "event_type": Schema.optionalKey(Schema.Literals(["funds_received", "payment_submitted", "payment_processed", "in_review", "refund", "refund_in_flight", "refund_failed", "microdeposit", "account_update", "deactivation", "activation"])) }) +export type GetCustomersByCustomerIDStaticMemosByStaticMemoIDHistoryPathParams = { readonly "customerID": Id, readonly "staticMemoID": Id } +export const GetCustomersByCustomerIDStaticMemosByStaticMemoIDHistoryPathParams = Schema.Struct({ "customerID": Id, "staticMemoID": Id }) +export type GetCustomersByCustomerIDStaticMemosByStaticMemoIDHistoryQuery = { readonly "deposit_id"?: string, readonly "deposit_ids"?: ReadonlyArray, readonly "tx_hash"?: string, readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string, readonly "event_type"?: "funds_received" | "payment_submitted" | "payment_processed" | "in_review" | "refund" | "refund_in_flight" | "refund_failed" | "microdeposit" | "account_update" | "deactivation" | "activation" } +export const GetCustomersByCustomerIDStaticMemosByStaticMemoIDHistoryQuery = Schema.Struct({ "deposit_id": Schema.optionalKey(Schema.String), "deposit_ids": Schema.optionalKey(Schema.Array(Schema.String)), "tx_hash": Schema.optionalKey(Schema.String), "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String), "event_type": Schema.optionalKey(Schema.Literals(["funds_received", "payment_submitted", "payment_processed", "in_review", "refund", "refund_in_flight", "refund_failed", "microdeposit", "account_update", "deactivation", "activation"])) }) +export type GetCustomersByCustomerIDStaticMemosByStaticMemoIDHistory200 = { readonly "count": number, readonly "data": ReadonlyArray } +export const GetCustomersByCustomerIDStaticMemosByStaticMemoIDHistory200 = Schema.Struct({ "count": Schema.Number.annotate({ "description": "The number of events returned" }).check(Schema.isInt().annotate({ "expected": "an integer" })), "data": Schema.Array(StaticMemoEvent).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" })) }).annotate({ "title": "Static Memo history" }) +export type PostCustomersByCustomerIDBatchSettlementSchedulesParams = { readonly "Idempotency-Key": string } +export const PostCustomersByCustomerIDBatchSettlementSchedulesParams = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostCustomersByCustomerIDBatchSettlementSchedulesPathParams = { readonly "customerID": Id } +export const PostCustomersByCustomerIDBatchSettlementSchedulesPathParams = Schema.Struct({ "customerID": Id }) +export type PostCustomersByCustomerIDBatchSettlementSchedulesHeaders = { readonly "Idempotency-Key": string } +export const PostCustomersByCustomerIDBatchSettlementSchedulesHeaders = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostCustomersByCustomerIDBatchSettlementSchedulesRequestJson = CreateBatchSettlementSchedule +export const PostCustomersByCustomerIDBatchSettlementSchedulesRequestJson = CreateBatchSettlementSchedule +export type PostCustomersByCustomerIDBatchSettlementSchedules200 = { readonly "id": Id } +export const PostCustomersByCustomerIDBatchSettlementSchedules200 = Schema.Struct({ "id": Id }).annotate({ "title": "Batch Settlement Schedule" }) +export type PostCustomersByCustomerIDBatchSettlementSchedules400 = Error +export const PostCustomersByCustomerIDBatchSettlementSchedules400 = Error +export type PostCustomersByCustomerIDBatchSettlementSchedules401 = Error +export const PostCustomersByCustomerIDBatchSettlementSchedules401 = Error +export type PostCustomersByCustomerIDBatchSettlementSchedules500 = Error +export const PostCustomersByCustomerIDBatchSettlementSchedules500 = Error +export type GetExternalAccountsParams = { readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string } +export const GetExternalAccountsParams = Schema.Struct({ "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String) }) +export type GetExternalAccountsQuery = { readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string } +export const GetExternalAccountsQuery = Schema.Struct({ "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String) }) +export type GetExternalAccounts200 = { readonly "data": ReadonlyArray, readonly "count"?: number } +export const GetExternalAccounts200 = Schema.Struct({ "data": Schema.Array(ExternalAccountResponse).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" })), "count": Schema.optionalKey(Schema.Number.annotate({ "description": "total number of items in data" }).check(Schema.isInt().annotate({ "expected": "an integer" }))) }).annotate({ "title": "ExternalAccount" }) +export type GetVirtualAccountsParams = { readonly "status"?: VirtualAccountActivationStatus, readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string } +export const GetVirtualAccountsParams = Schema.Struct({ "status": Schema.optionalKey(VirtualAccountActivationStatus), "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String) }) +export type GetVirtualAccountsQuery = { readonly "status"?: VirtualAccountActivationStatus, readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string } +export const GetVirtualAccountsQuery = Schema.Struct({ "status": Schema.optionalKey(VirtualAccountActivationStatus), "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String) }) +export type GetVirtualAccounts200 = { readonly "count": number, readonly "data": ReadonlyArray } +export const GetVirtualAccounts200 = Schema.Struct({ "count": Schema.Number.annotate({ "description": "total number of items in data" }).check(Schema.isInt().annotate({ "expected": "an integer" })), "data": Schema.Array(VirtualAccountResponse).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" })) }).annotate({ "title": "Virtual Accounts" }) +export type GetVirtualAccountsHistoryParams = { readonly "deposit_id"?: string, readonly "deposit_ids"?: ReadonlyArray, readonly "tx_hash"?: string, readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string, readonly "event_type"?: "funds_received" | "payment_submitted" | "payment_processed" | "in_review" | "refund" | "refund_in_flight" | "refund_failed" | "microdeposit" | "account_update" | "deactivation" | "activation", readonly "updated_after_ms"?: number, readonly "updated_before_ms"?: number } +export const GetVirtualAccountsHistoryParams = Schema.Struct({ "deposit_id": Schema.optionalKey(Schema.String), "deposit_ids": Schema.optionalKey(Schema.Array(Schema.String)), "tx_hash": Schema.optionalKey(Schema.String), "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String), "event_type": Schema.optionalKey(Schema.Literals(["funds_received", "payment_submitted", "payment_processed", "in_review", "refund", "refund_in_flight", "refund_failed", "microdeposit", "account_update", "deactivation", "activation"])), "updated_after_ms": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), "updated_before_ms": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))) }) +export type GetVirtualAccountsHistoryQuery = { readonly "deposit_id"?: string, readonly "deposit_ids"?: ReadonlyArray, readonly "tx_hash"?: string, readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string, readonly "event_type"?: "funds_received" | "payment_submitted" | "payment_processed" | "in_review" | "refund" | "refund_in_flight" | "refund_failed" | "microdeposit" | "account_update" | "deactivation" | "activation", readonly "updated_after_ms"?: number, readonly "updated_before_ms"?: number } +export const GetVirtualAccountsHistoryQuery = Schema.Struct({ "deposit_id": Schema.optionalKey(Schema.String), "deposit_ids": Schema.optionalKey(Schema.Array(Schema.String)), "tx_hash": Schema.optionalKey(Schema.String), "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String), "event_type": Schema.optionalKey(Schema.Literals(["funds_received", "payment_submitted", "payment_processed", "in_review", "refund", "refund_in_flight", "refund_failed", "microdeposit", "account_update", "deactivation", "activation"])), "updated_after_ms": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), "updated_before_ms": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))) }) +export type GetVirtualAccountsHistory200 = { readonly "count": number, readonly "data": ReadonlyArray } +export const GetVirtualAccountsHistory200 = Schema.Struct({ "count": Schema.Number.annotate({ "description": "The number of events returned" }).check(Schema.isInt().annotate({ "expected": "an integer" })), "data": Schema.Array(VirtualAccountEvent).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" })) }).annotate({ "title": "Virtual Account history" }) +export type GetDeveloperFees200 = DeveloperFees +export const GetDeveloperFees200 = DeveloperFees +export type GetDeveloperFees400 = Error +export const GetDeveloperFees400 = Error +export type GetDeveloperFees401 = Error +export const GetDeveloperFees401 = Error +export type GetDeveloperFees500 = Error +export const GetDeveloperFees500 = Error +export type PostDeveloperFeesParams = { readonly "Idempotency-Key": string } +export const PostDeveloperFeesParams = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostDeveloperFeesHeaders = { readonly "Idempotency-Key": string } +export const PostDeveloperFeesHeaders = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostDeveloperFeesRequestJson = DeveloperFees +export const PostDeveloperFeesRequestJson = DeveloperFees +export type PostDeveloperFees200 = DeveloperFees +export const PostDeveloperFees200 = DeveloperFees +export type PostDeveloperFees400 = Error +export const PostDeveloperFees400 = Error +export type PostDeveloperFees401 = Error +export const PostDeveloperFees401 = Error +export type PostDeveloperFees500 = Error +export const PostDeveloperFees500 = Error +export type GetDeveloperFeeExternalAccount200 = FeeExternalAccount +export const GetDeveloperFeeExternalAccount200 = FeeExternalAccount +export type GetDeveloperFeeExternalAccount400 = Error +export const GetDeveloperFeeExternalAccount400 = Error +export type GetDeveloperFeeExternalAccount401 = Error +export const GetDeveloperFeeExternalAccount401 = Error +export type GetDeveloperFeeExternalAccount500 = Error +export const GetDeveloperFeeExternalAccount500 = Error +export type PostDeveloperFeeExternalAccountParams = { readonly "Idempotency-Key": string } +export const PostDeveloperFeeExternalAccountParams = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostDeveloperFeeExternalAccountHeaders = { readonly "Idempotency-Key": string } +export const PostDeveloperFeeExternalAccountHeaders = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostDeveloperFeeExternalAccountRequestJson = CreateFeeExternalAccountInput +export const PostDeveloperFeeExternalAccountRequestJson = CreateFeeExternalAccountInput +export type PostDeveloperFeeExternalAccount201 = FeeExternalAccount +export const PostDeveloperFeeExternalAccount201 = FeeExternalAccount +export type PostDeveloperFeeExternalAccount400 = Error +export const PostDeveloperFeeExternalAccount400 = Error +export type PostDeveloperFeeExternalAccount401 = Error +export const PostDeveloperFeeExternalAccount401 = Error +export type PostDeveloperFeeExternalAccount500 = Error +export const PostDeveloperFeeExternalAccount500 = Error +export type GetDeveloperCardsSummaryParams = { readonly "period": "year" | "month" | "week" | "day" | "lifetime", readonly "period_key"?: string } +export const GetDeveloperCardsSummaryParams = Schema.Struct({ "period": Schema.Literals(["year", "month", "week", "day", "lifetime"]), "period_key": Schema.optionalKey(Schema.String) }) +export type GetDeveloperCardsSummaryQuery = { readonly "period": "year" | "month" | "week" | "day" | "lifetime", readonly "period_key"?: string } +export const GetDeveloperCardsSummaryQuery = Schema.Struct({ "period": Schema.Literals(["year", "month", "week", "day", "lifetime"]), "period_key": Schema.optionalKey(Schema.String) }) +export type GetDeveloperCardsSummary200 = CardProgramSummary +export const GetDeveloperCardsSummary200 = CardProgramSummary +export type GetDeveloperCardsSummary400 = Error +export const GetDeveloperCardsSummary400 = Error +export type GetDeveloperCardsSummary401 = Error +export const GetDeveloperCardsSummary401 = Error +export type GetDeveloperCardsSummary500 = Error +export const GetDeveloperCardsSummary500 = Error +export type GetDeveloperCardsDesigns200 = CardDesigns +export const GetDeveloperCardsDesigns200 = CardDesigns +export type GetDeveloperCardsDesigns400 = Error +export const GetDeveloperCardsDesigns400 = Error +export type GetDeveloperCardsDesigns401 = Error +export const GetDeveloperCardsDesigns401 = Error +export type GetDeveloperCardsDesigns500 = Error +export const GetDeveloperCardsDesigns500 = Error +export type PostApiKeysRequestJson = CreateApiKeyInput +export const PostApiKeysRequestJson = CreateApiKeyInput +export type PostApiKeys201 = ApiKeyWithSecret +export const PostApiKeys201 = ApiKeyWithSecret +export type PostApiKeys400 = Error +export const PostApiKeys400 = Error +export type PostApiKeys401 = Error +export const PostApiKeys401 = Error +export type PostApiKeys500 = Error +export const PostApiKeys500 = Error +export type GetApiKeysWhoami200 = ApiKey +export const GetApiKeysWhoami200 = ApiKey +export type GetApiKeysWhoami401 = Error +export const GetApiKeysWhoami401 = Error +export type GetApiKeysWhoami500 = Error +export const GetApiKeysWhoami500 = Error +export type GetKycLinksParams = { readonly "customer_id"?: string, readonly "email"?: string, readonly "starting_after"?: string, readonly "ending_before"?: string, readonly "limit"?: number } +export const GetKycLinksParams = Schema.Struct({ "customer_id": Schema.optionalKey(Schema.String), "email": Schema.optionalKey(Schema.String), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String), "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))) }) +export type GetKycLinksQuery = { readonly "customer_id"?: string, readonly "email"?: string, readonly "starting_after"?: string, readonly "ending_before"?: string, readonly "limit"?: number } +export const GetKycLinksQuery = Schema.Struct({ "customer_id": Schema.optionalKey(Schema.String), "email": Schema.optionalKey(Schema.String), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String), "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))) }) +export type GetKycLinks200 = { readonly "count": number, readonly "data": ReadonlyArray } +export const GetKycLinks200 = Schema.Struct({ "count": Schema.Number.annotate({ "description": "total number of items in data" }).check(Schema.isInt().annotate({ "expected": "an integer" })), "data": Schema.Array(IndividualKycLinkResponse).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" })) }).annotate({ "title": "Kyc Links" }) +export type GetKycLinks401 = Error +export const GetKycLinks401 = Error +export type GetKycLinks404 = Error +export const GetKycLinks404 = Error +export type GetKycLinks500 = Error +export const GetKycLinks500 = Error +export type PostKycLinksParams = { readonly "Idempotency-Key": string } +export const PostKycLinksParams = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostKycLinksHeaders = { readonly "Idempotency-Key": string } +export const PostKycLinksHeaders = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostKycLinksRequestJson = CreateKycLinks +export const PostKycLinksRequestJson = CreateKycLinks +export type PostKycLinks200 = IndividualKycLinkResponse +export const PostKycLinks200 = IndividualKycLinkResponse +export type PostKycLinks400 = Error +export const PostKycLinks400 = Error +export type PostKycLinks401 = Error +export const PostKycLinks401 = Error +export type PostKycLinks500 = Error +export const PostKycLinks500 = Error +export type GetKycLinksByKycLinkIDPathParams = { readonly "kycLinkID": Id } +export const GetKycLinksByKycLinkIDPathParams = Schema.Struct({ "kycLinkID": Id }) +export type GetKycLinksByKycLinkID200 = IndividualKycLinkResponse +export const GetKycLinksByKycLinkID200 = IndividualKycLinkResponse +export type GetKycLinksByKycLinkID401 = Error +export const GetKycLinksByKycLinkID401 = Error +export type GetKycLinksByKycLinkID404 = Error +export const GetKycLinksByKycLinkID404 = Error +export type GetKycLinksByKycLinkID500 = Error +export const GetKycLinksByKycLinkID500 = Error +export type GetRfisParams = { readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string, readonly "customer_id"?: string, readonly "state"?: "on_developer" | "on_bridge" | "closed" } +export const GetRfisParams = Schema.Struct({ "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String), "customer_id": Schema.optionalKey(Schema.String), "state": Schema.optionalKey(Schema.Literals(["on_developer", "on_bridge", "closed"])) }) +export type GetRfisQuery = { readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string, readonly "customer_id"?: string, readonly "state"?: "on_developer" | "on_bridge" | "closed" } +export const GetRfisQuery = Schema.Struct({ "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String), "customer_id": Schema.optionalKey(Schema.String), "state": Schema.optionalKey(Schema.Literals(["on_developer", "on_bridge", "closed"])) }) +export type GetRfis200 = { readonly "count": number, readonly "data": ReadonlyArray } +export const GetRfis200 = Schema.Struct({ "count": Schema.Number.annotate({ "description": "The number of items returned" }).check(Schema.isInt().annotate({ "expected": "an integer" })), "data": Schema.Array(Rfi).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" })) }).annotate({ "title": "List of RFIs" }) +export type GetRfis400 = Error +export const GetRfis400 = Error +export type GetRfis401 = Error +export const GetRfis401 = Error +export type GetRfis500 = Error +export const GetRfis500 = Error +export type GetRfisByRfiIDPathParams = { readonly "rfiID": Id } +export const GetRfisByRfiIDPathParams = Schema.Struct({ "rfiID": Id }) +export type GetRfisByRfiID200 = Rfi +export const GetRfisByRfiID200 = Rfi +export type GetRfisByRfiID401 = Error +export const GetRfisByRfiID401 = Error +export type GetRfisByRfiID404 = Error +export const GetRfisByRfiID404 = Error +export type GetRfisByRfiID500 = Error +export const GetRfisByRfiID500 = Error +export type GetStaticMemosHistoryParams = { readonly "deposit_id"?: string, readonly "deposit_ids"?: ReadonlyArray, readonly "tx_hash"?: string, readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string, readonly "event_type"?: "funds_received" | "payment_submitted" | "payment_processed" | "in_review" | "refund" | "refund_in_flight" | "refund_failed" | "microdeposit" | "account_update" | "deactivation" | "activation" } +export const GetStaticMemosHistoryParams = Schema.Struct({ "deposit_id": Schema.optionalKey(Schema.String), "deposit_ids": Schema.optionalKey(Schema.Array(Schema.String)), "tx_hash": Schema.optionalKey(Schema.String), "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String), "event_type": Schema.optionalKey(Schema.Literals(["funds_received", "payment_submitted", "payment_processed", "in_review", "refund", "refund_in_flight", "refund_failed", "microdeposit", "account_update", "deactivation", "activation"])) }) +export type GetStaticMemosHistoryQuery = { readonly "deposit_id"?: string, readonly "deposit_ids"?: ReadonlyArray, readonly "tx_hash"?: string, readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string, readonly "event_type"?: "funds_received" | "payment_submitted" | "payment_processed" | "in_review" | "refund" | "refund_in_flight" | "refund_failed" | "microdeposit" | "account_update" | "deactivation" | "activation" } +export const GetStaticMemosHistoryQuery = Schema.Struct({ "deposit_id": Schema.optionalKey(Schema.String), "deposit_ids": Schema.optionalKey(Schema.Array(Schema.String)), "tx_hash": Schema.optionalKey(Schema.String), "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String), "event_type": Schema.optionalKey(Schema.Literals(["funds_received", "payment_submitted", "payment_processed", "in_review", "refund", "refund_in_flight", "refund_failed", "microdeposit", "account_update", "deactivation", "activation"])) }) +export type GetStaticMemosHistory200 = { readonly "count": number, readonly "data": ReadonlyArray } +export const GetStaticMemosHistory200 = Schema.Struct({ "count": Schema.Number.annotate({ "description": "The number of events returned" }).check(Schema.isInt().annotate({ "expected": "an integer" })), "data": Schema.Array(StaticMemoEvent).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" })) }).annotate({ "title": "Static Memo history" }) +export type GetFundsRequestsParams = { readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string, readonly "customer_id"?: string, readonly "fraud"?: boolean, readonly "notice_date_starting_on"?: string, readonly "notice_date_ending_on"?: string } +export const GetFundsRequestsParams = Schema.Struct({ "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String), "customer_id": Schema.optionalKey(Schema.String), "fraud": Schema.optionalKey(Schema.Boolean), "notice_date_starting_on": Schema.optionalKey(Schema.String), "notice_date_ending_on": Schema.optionalKey(Schema.String) }) +export type GetFundsRequestsQuery = { readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string, readonly "customer_id"?: string, readonly "fraud"?: boolean, readonly "notice_date_starting_on"?: string, readonly "notice_date_ending_on"?: string } +export const GetFundsRequestsQuery = Schema.Struct({ "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String), "customer_id": Schema.optionalKey(Schema.String), "fraud": Schema.optionalKey(Schema.Boolean), "notice_date_starting_on": Schema.optionalKey(Schema.String), "notice_date_ending_on": Schema.optionalKey(Schema.String) }) +export type GetFundsRequests200 = { readonly "count": number, readonly "data": ReadonlyArray } +export const GetFundsRequests200 = Schema.Struct({ "count": Schema.Number.annotate({ "description": "The number of items returned" }).check(Schema.isInt().annotate({ "expected": "an integer" })), "data": Schema.Array(FundsRequest).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" })) }).annotate({ "title": "List of funds requests" }) +export type GetWebhooks200 = { readonly "data": ReadonlyArray } +export const GetWebhooks200 = Schema.Struct({ "data": Schema.Array(Webhook).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" })) }).annotate({ "title": "Webhooks" }) +export type GetWebhooks401 = Error +export const GetWebhooks401 = Error +export type GetWebhooks500 = Error +export const GetWebhooks500 = Error +export type PostWebhooksParams = { readonly "Idempotency-Key": string } +export const PostWebhooksParams = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostWebhooksHeaders = { readonly "Idempotency-Key": string } +export const PostWebhooksHeaders = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostWebhooksRequestJson = CreateWebhook +export const PostWebhooksRequestJson = CreateWebhook +export type PostWebhooks201 = Webhook +export const PostWebhooks201 = Webhook +export type PostWebhooks400 = Error +export const PostWebhooks400 = Error +export type PostWebhooks401 = Error +export const PostWebhooks401 = Error +export type PostWebhooks500 = Error +export const PostWebhooks500 = Error +export type PutWebhooksByWebhookIDPathParams = { readonly "webhookID": Id } +export const PutWebhooksByWebhookIDPathParams = Schema.Struct({ "webhookID": Id }) +export type PutWebhooksByWebhookIDRequestJson = PutWebhookPayload +export const PutWebhooksByWebhookIDRequestJson = PutWebhookPayload +export type PutWebhooksByWebhookID200 = Webhook +export const PutWebhooksByWebhookID200 = Webhook +export type PutWebhooksByWebhookID401 = Error +export const PutWebhooksByWebhookID401 = Error +export type PutWebhooksByWebhookID404 = Error +export const PutWebhooksByWebhookID404 = Error +export type PutWebhooksByWebhookID500 = Error +export const PutWebhooksByWebhookID500 = Error +export type DeleteWebhooksByWebhookIDPathParams = { readonly "webhookID": Id } +export const DeleteWebhooksByWebhookIDPathParams = Schema.Struct({ "webhookID": Id }) +export type DeleteWebhooksByWebhookID200 = Webhook +export const DeleteWebhooksByWebhookID200 = Webhook +export type DeleteWebhooksByWebhookID401 = Error +export const DeleteWebhooksByWebhookID401 = Error +export type DeleteWebhooksByWebhookID404 = Error +export const DeleteWebhooksByWebhookID404 = Error +export type DeleteWebhooksByWebhookID500 = Error +export const DeleteWebhooksByWebhookID500 = Error +export type GetWebhooksByWebhookIDEventsPathParams = { readonly "webhookID": Id } +export const GetWebhooksByWebhookIDEventsPathParams = Schema.Struct({ "webhookID": Id }) +export type GetWebhooksByWebhookIDEvents200 = { readonly "data": ReadonlyArray } +export const GetWebhooksByWebhookIDEvents200 = Schema.Struct({ "data": Schema.Array(WebhookEvent).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" })) }).annotate({ "title": "Webhook Events" }) +export type GetWebhooksByWebhookIDEvents401 = Error +export const GetWebhooksByWebhookIDEvents401 = Error +export type GetWebhooksByWebhookIDEvents500 = Error +export const GetWebhooksByWebhookIDEvents500 = Error +export type GetWebhooksByWebhookIDLogsPathParams = { readonly "webhookID": Id } +export const GetWebhooksByWebhookIDLogsPathParams = Schema.Struct({ "webhookID": Id }) +export type GetWebhooksByWebhookIDLogs200 = { readonly "count": number, readonly "data": ReadonlyArray } +export const GetWebhooksByWebhookIDLogs200 = Schema.Struct({ "count": Schema.Number.annotate({ "description": "The number of logs returned" }).check(Schema.isInt().annotate({ "expected": "an integer" })), "data": Schema.Array(WebhookEventDeliveryLog).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" })) }).annotate({ "title": "Delivery Logs" }) +export type GetWebhooksByWebhookIDLogs401 = Error +export const GetWebhooksByWebhookIDLogs401 = Error +export type GetWebhooksByWebhookIDLogs500 = Error +export const GetWebhooksByWebhookIDLogs500 = Error +export type PostWebhooksByWebhookIDSendParams = { readonly "Idempotency-Key": string } +export const PostWebhooksByWebhookIDSendParams = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostWebhooksByWebhookIDSendPathParams = { readonly "webhookID": Id } +export const PostWebhooksByWebhookIDSendPathParams = Schema.Struct({ "webhookID": Id }) +export type PostWebhooksByWebhookIDSendHeaders = { readonly "Idempotency-Key": string } +export const PostWebhooksByWebhookIDSendHeaders = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostWebhooksByWebhookIDSendRequestJson = SendWebhookPayload +export const PostWebhooksByWebhookIDSendRequestJson = SendWebhookPayload +export type PostWebhooksByWebhookIDSend200 = { readonly "message": string } +export const PostWebhooksByWebhookIDSend200 = Schema.Struct({ "message": Schema.String.annotate({ "description": "Message indicating the status of the request" }) }).annotate({ "title": "Webhook Event Sent" }) +export type PostWebhooksByWebhookIDSend401 = Error +export const PostWebhooksByWebhookIDSend401 = Error +export type PostWebhooksByWebhookIDSend500 = Error +export const PostWebhooksByWebhookIDSend500 = Error +export type GetWebhookEventsParams = { readonly "starting_after"?: string, readonly "ending_before"?: string, readonly "limit"?: number, readonly "category"?: "customer" | "external_account" | "kyc_link" | "liquidation_address" | "liquidation_address.drain" | "static_memo.activity" | "transfer" | "virtual_account" | "virtual_account.activity" | "bridge_wallet.activity" | "shift4_base_deposit" | "indexed_deposit" | "card_account" | "posted_card_account_transaction" | "card_transaction" | "card_withdrawal" } +export const GetWebhookEventsParams = Schema.Struct({ "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String), "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 100 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(500).annotate({ "expected": "a value less than or equal to 500" }))), "category": Schema.optionalKey(Schema.Literals(["customer", "external_account", "kyc_link", "liquidation_address", "liquidation_address.drain", "static_memo.activity", "transfer", "virtual_account", "virtual_account.activity", "bridge_wallet.activity", "shift4_base_deposit", "indexed_deposit", "card_account", "posted_card_account_transaction", "card_transaction", "card_withdrawal"])) }) +export type GetWebhookEventsQuery = { readonly "starting_after"?: string, readonly "ending_before"?: string, readonly "limit"?: number, readonly "category"?: "customer" | "external_account" | "kyc_link" | "liquidation_address" | "liquidation_address.drain" | "static_memo.activity" | "transfer" | "virtual_account" | "virtual_account.activity" | "bridge_wallet.activity" | "shift4_base_deposit" | "indexed_deposit" | "card_account" | "posted_card_account_transaction" | "card_transaction" | "card_withdrawal" } +export const GetWebhookEventsQuery = Schema.Struct({ "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String), "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 100 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(500).annotate({ "expected": "a value less than or equal to 500" }))), "category": Schema.optionalKey(Schema.Literals(["customer", "external_account", "kyc_link", "liquidation_address", "liquidation_address.drain", "static_memo.activity", "transfer", "virtual_account", "virtual_account.activity", "bridge_wallet.activity", "shift4_base_deposit", "indexed_deposit", "card_account", "posted_card_account_transaction", "card_transaction", "card_withdrawal"])) }) +export type GetWebhookEvents200 = { readonly "data": ReadonlyArray, readonly "count": number } +export const GetWebhookEvents200 = Schema.Struct({ "data": Schema.Array(WebhookEvent), "count": Schema.Number.annotate({ "description": "Number of webhook events returned in this response" }).check(Schema.isInt().annotate({ "expected": "an integer" })) }) +export type GetWebhookEvents400 = Error +export const GetWebhookEvents400 = Error +export type GetWebhookEvents401 = Error +export const GetWebhookEvents401 = Error +export type GetWebhookEvents500 = Error +export const GetWebhookEvents500 = Error +export type GetAssociatedPersonsByAssociatedPersonIDPathParams = { readonly "associatedPersonID": Id } +export const GetAssociatedPersonsByAssociatedPersonIDPathParams = Schema.Struct({ "associatedPersonID": Id }) +export type GetAssociatedPersonsByAssociatedPersonID200 = AssociatedPersonResponse +export const GetAssociatedPersonsByAssociatedPersonID200 = AssociatedPersonResponse +export type GetAssociatedPersonsByAssociatedPersonID401 = Error +export const GetAssociatedPersonsByAssociatedPersonID401 = Error +export type GetAssociatedPersonsByAssociatedPersonID404 = Error +export const GetAssociatedPersonsByAssociatedPersonID404 = Error +export type GetAssociatedPersonsByAssociatedPersonID500 = Error +export const GetAssociatedPersonsByAssociatedPersonID500 = Error +export type PutAssociatedPersonsByAssociatedPersonIDPathParams = { readonly "associatedPersonID": Id } +export const PutAssociatedPersonsByAssociatedPersonIDPathParams = Schema.Struct({ "associatedPersonID": Id }) +export type PutAssociatedPersonsByAssociatedPersonIDRequestJson = AssociatedPerson +export const PutAssociatedPersonsByAssociatedPersonIDRequestJson = AssociatedPerson +export type PutAssociatedPersonsByAssociatedPersonID200 = AssociatedPersonResponse +export const PutAssociatedPersonsByAssociatedPersonID200 = AssociatedPersonResponse +export type PutAssociatedPersonsByAssociatedPersonID400 = Error +export const PutAssociatedPersonsByAssociatedPersonID400 = Error +export type PutAssociatedPersonsByAssociatedPersonID401 = Error +export const PutAssociatedPersonsByAssociatedPersonID401 = Error +export type PutAssociatedPersonsByAssociatedPersonID404 = Error +export const PutAssociatedPersonsByAssociatedPersonID404 = Error +export type PutAssociatedPersonsByAssociatedPersonID500 = Error +export const PutAssociatedPersonsByAssociatedPersonID500 = Error +export type DeleteAssociatedPersonsByAssociatedPersonIDPathParams = { readonly "associatedPersonID": Id } +export const DeleteAssociatedPersonsByAssociatedPersonIDPathParams = Schema.Struct({ "associatedPersonID": Id }) +export type DeleteAssociatedPersonsByAssociatedPersonID200 = AssociatedPersonResponse +export const DeleteAssociatedPersonsByAssociatedPersonID200 = AssociatedPersonResponse +export type DeleteAssociatedPersonsByAssociatedPersonID401 = Error +export const DeleteAssociatedPersonsByAssociatedPersonID401 = Error +export type DeleteAssociatedPersonsByAssociatedPersonID404 = Error +export const DeleteAssociatedPersonsByAssociatedPersonID404 = Error +export type DeleteAssociatedPersonsByAssociatedPersonID500 = Error +export const DeleteAssociatedPersonsByAssociatedPersonID500 = Error +export type PostTravelRuleDataByIdParams = { readonly "Idempotency-Key": string } +export const PostTravelRuleDataByIdParams = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostTravelRuleDataByIdPathParams = { readonly "id": string } +export const PostTravelRuleDataByIdPathParams = Schema.Struct({ "id": Schema.String }) +export type PostTravelRuleDataByIdHeaders = { readonly "Idempotency-Key": string } +export const PostTravelRuleDataByIdHeaders = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostTravelRuleDataByIdRequestJson = TravelRuleData +export const PostTravelRuleDataByIdRequestJson = TravelRuleData +export type PostTravelRuleDataById200 = { readonly "message": string } +export const PostTravelRuleDataById200 = Schema.Struct({ "message": Schema.String.annotate({ "description": "Message indicating the status of the request." }) }) +export type PostTravelRuleDataById400 = Error +export const PostTravelRuleDataById400 = Error +export type PostTravelRuleDataById401 = Error +export const PostTravelRuleDataById401 = Error +export type PostTravelRuleDataById404 = Error +export const PostTravelRuleDataById404 = Error +export type PostTravelRuleDataById500 = Error +export const PostTravelRuleDataById500 = Error +export type GetExchangeRatesParams = { readonly "from": "brl" | "cop" | "eur" | "gbp" | "mxn" | "usd" | "usdt", readonly "to": "brl" | "cop" | "eur" | "gbp" | "mxn" | "usd" | "usdt" } +export const GetExchangeRatesParams = Schema.Struct({ "from": Schema.Literals(["brl", "cop", "eur", "gbp", "mxn", "usd", "usdt"]), "to": Schema.Literals(["brl", "cop", "eur", "gbp", "mxn", "usd", "usdt"]) }) +export type GetExchangeRatesQuery = { readonly "from": "brl" | "cop" | "eur" | "gbp" | "mxn" | "usd" | "usdt", readonly "to": "brl" | "cop" | "eur" | "gbp" | "mxn" | "usd" | "usdt" } +export const GetExchangeRatesQuery = Schema.Struct({ "from": Schema.Literals(["brl", "cop", "eur", "gbp", "mxn", "usd", "usdt"]), "to": Schema.Literals(["brl", "cop", "eur", "gbp", "mxn", "usd", "usdt"]) }) +export type GetExchangeRates200 = { readonly "midmarket_rate"?: string, readonly "buy_rate"?: string, readonly "sell_rate"?: string, readonly "updated_at"?: string } +export const GetExchangeRates200 = Schema.Struct({ "midmarket_rate": Schema.optionalKey(Schema.String.annotate({ "description": "The midmarket exchange rate.", "examples": ["0.93425"] })), "buy_rate": Schema.optionalKey(Schema.String.annotate({ "description": "The rate for buying the target currency, including Bridge's fee.", "examples": ["0.9389"] })), "sell_rate": Schema.optionalKey(Schema.String.annotate({ "description": "The rate for selling the target currency, including Bridge's fee.", "examples": ["0.9296"] })), "updated_at": Schema.optionalKey(Schema.String.annotate({ "description": "The timestamp when the exchange rate was last collected from the market data provider.", "examples": ["2026-01-15T12:00:00.000Z"], "format": "date-time" })) }) +export type GetListsOccupationCodes200 = ReadonlyArray<{ readonly "display_name"?: string, readonly "code"?: string }> +export const GetListsOccupationCodes200 = Schema.Array(Schema.Struct({ "display_name": Schema.optionalKey(Schema.String.annotate({ "description": "Human readable name that customers can select.", "examples": ["Accountant and auditor"] })), "code": Schema.optionalKey(Schema.String.annotate({ "description": "The corresponding code that should be sent to the Bridge API representing the customers selection.", "examples": ["132011"] })) })) +export type GetListsCountries200 = { readonly "count": number, readonly "data": ReadonlyArray } +export const GetListsCountries200 = Schema.Struct({ "count": Schema.Number.annotate({ "description": "The total number of countries recognized by Bridge" }).check(Schema.isInt().annotate({ "expected": "an integer" })), "data": Schema.Array(Country).annotate({ "description": "The list of countries recognized by Bridge" }).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" })) }).annotate({ "title": "Countries" }) +export type GetCryptoReturnPolicies200 = ReadonlyArray +export const GetCryptoReturnPolicies200 = Schema.Array(CryptoReturnPolicy) +export type GetCryptoReturnPolicies401 = Error +export const GetCryptoReturnPolicies401 = Error +export type GetCryptoReturnPolicies500 = Error +export const GetCryptoReturnPolicies500 = Error +export type PostCryptoReturnPoliciesParams = { readonly "Idempotency-Key": string } +export const PostCryptoReturnPoliciesParams = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostCryptoReturnPoliciesHeaders = { readonly "Idempotency-Key": string } +export const PostCryptoReturnPoliciesHeaders = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostCryptoReturnPoliciesRequestJson = PostCryptoReturnPoliciesInput +export const PostCryptoReturnPoliciesRequestJson = PostCryptoReturnPoliciesInput +export type PostCryptoReturnPolicies201 = CryptoReturnPolicy +export const PostCryptoReturnPolicies201 = CryptoReturnPolicy +export type PostCryptoReturnPolicies400 = Error +export const PostCryptoReturnPolicies400 = Error +export type PostCryptoReturnPolicies401 = Error +export const PostCryptoReturnPolicies401 = Error +export type PostCryptoReturnPolicies500 = Error +export const PostCryptoReturnPolicies500 = Error +export type PutCryptoReturnPoliciesByPolicyIDPathParams = { readonly "policyID": string } +export const PutCryptoReturnPoliciesByPolicyIDPathParams = Schema.Struct({ "policyID": Schema.String }) +export type PutCryptoReturnPoliciesByPolicyIDRequestJson = PostCryptoReturnPoliciesInput +export const PutCryptoReturnPoliciesByPolicyIDRequestJson = PostCryptoReturnPoliciesInput +export type PutCryptoReturnPoliciesByPolicyID200 = CryptoReturnPolicy +export const PutCryptoReturnPoliciesByPolicyID200 = CryptoReturnPolicy +export type PutCryptoReturnPoliciesByPolicyID400 = Error +export const PutCryptoReturnPoliciesByPolicyID400 = Error +export type PutCryptoReturnPoliciesByPolicyID401 = Error +export const PutCryptoReturnPoliciesByPolicyID401 = Error +export type PutCryptoReturnPoliciesByPolicyID404 = Error +export const PutCryptoReturnPoliciesByPolicyID404 = Error +export type PutCryptoReturnPoliciesByPolicyID500 = Error +export const PutCryptoReturnPoliciesByPolicyID500 = Error +export type DeleteCryptoReturnPoliciesByPolicyIDPathParams = { readonly "policyID": string } +export const DeleteCryptoReturnPoliciesByPolicyIDPathParams = Schema.Struct({ "policyID": Schema.String }) +export type DeleteCryptoReturnPoliciesByPolicyID200 = CryptoReturnPolicy +export const DeleteCryptoReturnPoliciesByPolicyID200 = CryptoReturnPolicy +export type DeleteCryptoReturnPoliciesByPolicyID401 = Error +export const DeleteCryptoReturnPoliciesByPolicyID401 = Error +export type DeleteCryptoReturnPoliciesByPolicyID404 = Error +export const DeleteCryptoReturnPoliciesByPolicyID404 = Error +export type DeleteCryptoReturnPoliciesByPolicyID500 = Error +export const DeleteCryptoReturnPoliciesByPolicyID500 = Error +export type GetCustomersByCustomerIDCardAccountsByCardAccountIDPathParams = { readonly "customerID": Id, readonly "cardAccountID": Id } +export const GetCustomersByCustomerIDCardAccountsByCardAccountIDPathParams = Schema.Struct({ "customerID": Id, "cardAccountID": Id }) +export type GetCustomersByCustomerIDCardAccountsByCardAccountID200 = CardAccount +export const GetCustomersByCustomerIDCardAccountsByCardAccountID200 = CardAccount +export type GetCustomersByCustomerIDCardAccountsByCardAccountID401 = Error +export const GetCustomersByCustomerIDCardAccountsByCardAccountID401 = Error +export type GetCustomersByCustomerIDCardAccountsByCardAccountID500 = Error +export const GetCustomersByCustomerIDCardAccountsByCardAccountID500 = Error +export type PutCustomersByCustomerIDCardAccountsByCardAccountIDPathParams = { readonly "customerID": Id, readonly "cardAccountID": Id } +export const PutCustomersByCustomerIDCardAccountsByCardAccountIDPathParams = Schema.Struct({ "customerID": Id, "cardAccountID": Id }) +export type PutCustomersByCustomerIDCardAccountsByCardAccountIDRequestJson = { readonly "currency"?: string, readonly "status"?: "inactive" } +export const PutCustomersByCustomerIDCardAccountsByCardAccountIDRequestJson = Schema.Struct({ "currency": Schema.optionalKey(Schema.String.annotate({ "description": "The new settlement currency for the card account." })), "status": Schema.optionalKey(Schema.Literal("inactive").annotate({ "description": "The desired status for the card account. Currently only \"inactive\" is supported." })) }) +export type PutCustomersByCustomerIDCardAccountsByCardAccountID200 = CardAccount +export const PutCustomersByCustomerIDCardAccountsByCardAccountID200 = CardAccount +export type PutCustomersByCustomerIDCardAccountsByCardAccountID400 = Error +export const PutCustomersByCustomerIDCardAccountsByCardAccountID400 = Error +export type PutCustomersByCustomerIDCardAccountsByCardAccountID401 = Error +export const PutCustomersByCustomerIDCardAccountsByCardAccountID401 = Error +export type PutCustomersByCustomerIDCardAccountsByCardAccountID500 = Error +export const PutCustomersByCustomerIDCardAccountsByCardAccountID500 = Error +export type GetCustomersByCustomerIDCardAccountsPathParams = { readonly "customerID": Id } +export const GetCustomersByCustomerIDCardAccountsPathParams = Schema.Struct({ "customerID": Id }) +export type GetCustomersByCustomerIDCardAccounts200 = { readonly "count": number, readonly "data": ReadonlyArray } +export const GetCustomersByCustomerIDCardAccounts200 = Schema.Struct({ "count": Schema.Number.annotate({ "description": "The number of card accounts returned" }).check(Schema.isInt().annotate({ "expected": "an integer" })), "data": Schema.Array(CardAccount).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" })) }).annotate({ "title": "Array of all card accounts" }) +export type GetCustomersByCustomerIDCardAccounts401 = Error +export const GetCustomersByCustomerIDCardAccounts401 = Error +export type GetCustomersByCustomerIDCardAccounts500 = Error +export const GetCustomersByCustomerIDCardAccounts500 = Error +export type PostCustomersByCustomerIDCardAccountsParams = { readonly "Idempotency-Key": string } +export const PostCustomersByCustomerIDCardAccountsParams = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostCustomersByCustomerIDCardAccountsPathParams = { readonly "customerID": Id } +export const PostCustomersByCustomerIDCardAccountsPathParams = Schema.Struct({ "customerID": Id }) +export type PostCustomersByCustomerIDCardAccountsHeaders = { readonly "Idempotency-Key": string } +export const PostCustomersByCustomerIDCardAccountsHeaders = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostCustomersByCustomerIDCardAccountsRequestJson = PostCardAccountsInput +export const PostCustomersByCustomerIDCardAccountsRequestJson = PostCardAccountsInput +export type PostCustomersByCustomerIDCardAccounts201 = CardAccount +export const PostCustomersByCustomerIDCardAccounts201 = CardAccount +export type PostCustomersByCustomerIDCardAccounts400 = Error +export const PostCustomersByCustomerIDCardAccounts400 = Error +export type PostCustomersByCustomerIDCardAccounts401 = Error +export const PostCustomersByCustomerIDCardAccounts401 = Error +export type PostCustomersByCustomerIDCardAccounts500 = Error +export const PostCustomersByCustomerIDCardAccounts500 = Error +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDFreezeParams = { readonly "Idempotency-Key": string } +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDFreezeParams = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDFreezePathParams = { readonly "customerID": Id, readonly "cardAccountID": Id } +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDFreezePathParams = Schema.Struct({ "customerID": Id, "cardAccountID": Id }) +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDFreezeHeaders = { readonly "Idempotency-Key": string } +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDFreezeHeaders = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDFreezeRequestJson = PostCardFreezeInput +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDFreezeRequestJson = PostCardFreezeInput +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDFreeze200 = { readonly "status": "freeze_created" | "freeze_replaced", readonly "card_account_id": string, readonly "initiator": "developer" | "customer" | "bridge", readonly "reason": "lost_or_stolen" | "suspicious_activity" | "planned_inactivity" | "suspected_fraud" | "other", readonly "reason_detail"?: string, readonly "starting_at"?: string, readonly "ending_at"?: string, readonly "created_at": string } & { readonly [x: string]: Schema.Json } +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDFreeze200 = Schema.StructWithRest(Schema.Struct({ "status": Schema.Literals(["freeze_created", "freeze_replaced"]).annotate({ "description": "The processing status of the freeze request", "readOnly": true }), "card_account_id": Schema.String.annotate({ "description": "Card account ID" }).check(Schema.isMinLength(1).annotate({ "expected": "a value with a length of at least 1" })).check(Schema.isMaxLength(42).annotate({ "expected": "a value with a length of at most 42" })).check(Schema.isPattern(new RegExp("[a-z0-9]*")).annotate({ "expected": "a string matching the RegExp [a-z0-9]*" })), "initiator": Schema.Literals(["developer", "customer", "bridge"]).annotate({ "description": "The party that initiated the freeze. Card account responses also include freezes initiated by Bridge." }), "reason": Schema.Literals(["lost_or_stolen", "suspicious_activity", "planned_inactivity", "suspected_fraud", "other"]).annotate({ "description": "The reason of the freeze" }), "reason_detail": Schema.optionalKey(Schema.String.annotate({ "description": "A more detailed reason for the freeze" })), "starting_at": Schema.optionalKey(Schema.String.annotate({ "description": "The start time of the freeze, in ISO8601 format" })), "ending_at": Schema.optionalKey(Schema.String.annotate({ "description": "The end time of the freeze, in ISO8601 format" })), "created_at": Schema.String.annotate({ "description": "The creation time of the freeze, in ISO8601 format", "readOnly": true }) }), [Schema.Record(Schema.String, Schema.Json.annotate({ "expected": "JSON value" }))]).annotate({ "description": "Card freeze" }) +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDFreeze400 = Error +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDFreeze400 = Error +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDFreeze401 = Error +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDFreeze401 = Error +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDFreeze500 = Error +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDFreeze500 = Error +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDUnfreezeParams = { readonly "Idempotency-Key": string } +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDUnfreezeParams = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDUnfreezePathParams = { readonly "customerID": Id, readonly "cardAccountID": Id } +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDUnfreezePathParams = Schema.Struct({ "customerID": Id, "cardAccountID": Id }) +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDUnfreezeHeaders = { readonly "Idempotency-Key": string } +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDUnfreezeHeaders = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDUnfreezeRequestJson = PostCardUnfreezeInput +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDUnfreezeRequestJson = PostCardUnfreezeInput +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDUnfreeze200 = CardUnfreezeResponse +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDUnfreeze200 = CardUnfreezeResponse +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDUnfreeze400 = Error +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDUnfreeze400 = Error +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDUnfreeze401 = Error +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDUnfreeze401 = Error +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDUnfreeze500 = Error +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDUnfreeze500 = Error +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDCreateMobileWalletProvisioningRequestParams = { readonly "Idempotency-Key": string } +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDCreateMobileWalletProvisioningRequestParams = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDCreateMobileWalletProvisioningRequestPathParams = { readonly "customerID": Id, readonly "cardAccountID": Id } +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDCreateMobileWalletProvisioningRequestPathParams = Schema.Struct({ "customerID": Id, "cardAccountID": Id }) +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDCreateMobileWalletProvisioningRequestHeaders = { readonly "Idempotency-Key": string } +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDCreateMobileWalletProvisioningRequestHeaders = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDCreateMobileWalletProvisioningRequestRequestJson = PostCardPushProvisioningInput +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDCreateMobileWalletProvisioningRequestRequestJson = PostCardPushProvisioningInput +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDCreateMobileWalletProvisioningRequest200 = CardPushProvisioningResponse +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDCreateMobileWalletProvisioningRequest200 = CardPushProvisioningResponse +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDCreateMobileWalletProvisioningRequest400 = Error +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDCreateMobileWalletProvisioningRequest400 = Error +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDCreateMobileWalletProvisioningRequest401 = Error +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDCreateMobileWalletProvisioningRequest401 = Error +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDCreateMobileWalletProvisioningRequest500 = Error +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDCreateMobileWalletProvisioningRequest500 = Error +export type GetCustomersByCustomerIDCardAccountsByCardAccountIDAuthorizationsParams = { readonly "limit"?: number, readonly "starting_time"?: string, readonly "ending_time"?: string, readonly "status"?: "approved" | "denied" } +export const GetCustomersByCustomerIDCardAccountsByCardAccountIDAuthorizationsParams = Schema.Struct({ "limit": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), "starting_time": Schema.optionalKey(Schema.String), "ending_time": Schema.optionalKey(Schema.String), "status": Schema.optionalKey(Schema.Literals(["approved", "denied"])) }) +export type GetCustomersByCustomerIDCardAccountsByCardAccountIDAuthorizationsPathParams = { readonly "customerID": Id, readonly "cardAccountID": Id } +export const GetCustomersByCustomerIDCardAccountsByCardAccountIDAuthorizationsPathParams = Schema.Struct({ "customerID": Id, "cardAccountID": Id }) +export type GetCustomersByCustomerIDCardAccountsByCardAccountIDAuthorizationsQuery = { readonly "limit"?: number, readonly "starting_time"?: string, readonly "ending_time"?: string, readonly "status"?: "approved" | "denied" } +export const GetCustomersByCustomerIDCardAccountsByCardAccountIDAuthorizationsQuery = Schema.Struct({ "limit": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), "starting_time": Schema.optionalKey(Schema.String), "ending_time": Schema.optionalKey(Schema.String), "status": Schema.optionalKey(Schema.Literals(["approved", "denied"])) }) +export type GetCustomersByCustomerIDCardAccountsByCardAccountIDAuthorizations200 = { readonly "count": number, readonly "data": ReadonlyArray } +export const GetCustomersByCustomerIDCardAccountsByCardAccountIDAuthorizations200 = Schema.Struct({ "count": Schema.Number.annotate({ "description": "The number of card authorizations returned" }).check(Schema.isInt().annotate({ "expected": "an integer" })), "data": Schema.Array(CardAuthorization).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" })) }).annotate({ "title": "List of pending card authorizations" }) +export type GetCustomersByCustomerIDCardAccountsByCardAccountIDAuthorizations401 = Error +export const GetCustomersByCustomerIDCardAccountsByCardAccountIDAuthorizations401 = Error +export type GetCustomersByCustomerIDCardAccountsByCardAccountIDAuthorizations500 = Error +export const GetCustomersByCustomerIDCardAccountsByCardAccountIDAuthorizations500 = Error +export type GetCustomersByCustomerIDCardAccountsByCardAccountIDTransactionsParams = { readonly "limit"?: number, readonly "starting_time"?: string, readonly "ending_time"?: string, readonly "page_size"?: string, readonly "page"?: string, readonly "status"?: ReadonlyArray<"pending" | "posted">, readonly "pagination_token"?: string, readonly "category_family"?: "cards" | "crypto" } +export const GetCustomersByCustomerIDCardAccountsByCardAccountIDTransactionsParams = Schema.Struct({ "limit": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), "starting_time": Schema.optionalKey(Schema.String), "ending_time": Schema.optionalKey(Schema.String), "page_size": Schema.optionalKey(Schema.String), "page": Schema.optionalKey(Schema.String), "status": Schema.optionalKey(Schema.Array(Schema.Literals(["pending", "posted"]))), "pagination_token": Schema.optionalKey(Schema.String), "category_family": Schema.optionalKey(Schema.Literals(["cards", "crypto"])) }) +export type GetCustomersByCustomerIDCardAccountsByCardAccountIDTransactionsPathParams = { readonly "customerID": Id, readonly "cardAccountID": Id } +export const GetCustomersByCustomerIDCardAccountsByCardAccountIDTransactionsPathParams = Schema.Struct({ "customerID": Id, "cardAccountID": Id }) +export type GetCustomersByCustomerIDCardAccountsByCardAccountIDTransactionsQuery = { readonly "limit"?: number, readonly "starting_time"?: string, readonly "ending_time"?: string, readonly "page_size"?: string, readonly "page"?: string, readonly "status"?: ReadonlyArray<"pending" | "posted">, readonly "pagination_token"?: string, readonly "category_family"?: "cards" | "crypto" } +export const GetCustomersByCustomerIDCardAccountsByCardAccountIDTransactionsQuery = Schema.Struct({ "limit": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), "starting_time": Schema.optionalKey(Schema.String), "ending_time": Schema.optionalKey(Schema.String), "page_size": Schema.optionalKey(Schema.String), "page": Schema.optionalKey(Schema.String), "status": Schema.optionalKey(Schema.Array(Schema.Literals(["pending", "posted"]))), "pagination_token": Schema.optionalKey(Schema.String), "category_family": Schema.optionalKey(Schema.Literals(["cards", "crypto"])) }) +export type GetCustomersByCustomerIDCardAccountsByCardAccountIDTransactions200 = { readonly "page": number, readonly "pagination_token"?: string, readonly "count": number, readonly "total_pages": number, readonly "total_count": number, readonly "data": ReadonlyArray } +export const GetCustomersByCustomerIDCardAccountsByCardAccountIDTransactions200 = Schema.Struct({ "page": Schema.Number.annotate({ "description": "The current page number, starting at 1. Note that this will be returned only for navigating posted transactions." }).check(Schema.isInt().annotate({ "expected": "an integer" })), "pagination_token": Schema.optionalKey(Schema.String.annotate({ "description": "The pagination token to be used to retrieve the next page of transactions. If not provided, use the `page` parameter to navigate by page number." })), "count": Schema.Number.annotate({ "description": "The number of transactions returned" }).check(Schema.isInt().annotate({ "expected": "an integer" })), "total_pages": Schema.Number.annotate({ "description": "The total number of pages" }).check(Schema.isInt().annotate({ "expected": "an integer" })), "total_count": Schema.Number.annotate({ "description": "The total number of transactions" }).check(Schema.isInt().annotate({ "expected": "an integer" })), "data": Schema.Array(CardTransaction).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" })) }).annotate({ "title": "List of card transactions" }) +export type GetCustomersByCustomerIDCardAccountsByCardAccountIDTransactions401 = Error +export const GetCustomersByCustomerIDCardAccountsByCardAccountIDTransactions401 = Error +export type GetCustomersByCustomerIDCardAccountsByCardAccountIDTransactions500 = Error +export const GetCustomersByCustomerIDCardAccountsByCardAccountIDTransactions500 = Error +export type GetCustomersByCustomerIDCardAccountsByCardAccountIDTransactionsByTransactionIDPathParams = { readonly "customerID": Id, readonly "cardAccountID": Id, readonly "transactionID": Id } +export const GetCustomersByCustomerIDCardAccountsByCardAccountIDTransactionsByTransactionIDPathParams = Schema.Struct({ "customerID": Id, "cardAccountID": Id, "transactionID": Id }) +export type GetCustomersByCustomerIDCardAccountsByCardAccountIDTransactionsByTransactionID200 = CardTransaction +export const GetCustomersByCustomerIDCardAccountsByCardAccountIDTransactionsByTransactionID200 = CardTransaction +export type GetCustomersByCustomerIDCardAccountsByCardAccountIDTransactionsByTransactionID401 = Error +export const GetCustomersByCustomerIDCardAccountsByCardAccountIDTransactionsByTransactionID401 = Error +export type GetCustomersByCustomerIDCardAccountsByCardAccountIDTransactionsByTransactionID500 = Error +export const GetCustomersByCustomerIDCardAccountsByCardAccountIDTransactionsByTransactionID500 = Error +export type GetCustomersByCustomerIDCardAccountsByCardAccountIDAuthControlsPathParams = { readonly "customerID": Id, readonly "cardAccountID": Id } +export const GetCustomersByCustomerIDCardAccountsByCardAccountIDAuthControlsPathParams = Schema.Struct({ "customerID": Id, "cardAccountID": Id }) +export type GetCustomersByCustomerIDCardAccountsByCardAccountIDAuthControls200 = { readonly "customer_id": string, readonly "card_account_id": string, readonly "spending_limits": ReadonlyArray } +export const GetCustomersByCustomerIDCardAccountsByCardAccountIDAuthControls200 = Schema.Struct({ "customer_id": Schema.String.annotate({ "description": "The ID of the customer" }), "card_account_id": Schema.String.annotate({ "description": "The ID of the card account" }), "spending_limits": Schema.Array(CardSpendingLimit).annotate({ "description": "The various spending limits for the card account for the current time period" }) }).annotate({ "title": "Authorization controls" }) +export type GetCustomersByCustomerIDCardAccountsByCardAccountIDAuthControls401 = Error +export const GetCustomersByCustomerIDCardAccountsByCardAccountIDAuthControls401 = Error +export type GetCustomersByCustomerIDCardAccountsByCardAccountIDAuthControls500 = Error +export const GetCustomersByCustomerIDCardAccountsByCardAccountIDAuthControls500 = Error +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDDepositAddressesParams = { readonly "Idempotency-Key": string } +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDDepositAddressesParams = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDDepositAddressesPathParams = { readonly "customerID": Id, readonly "cardAccountID": Id } +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDDepositAddressesPathParams = Schema.Struct({ "customerID": Id, "cardAccountID": Id }) +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDDepositAddressesHeaders = { readonly "Idempotency-Key": string } +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDDepositAddressesHeaders = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDDepositAddressesRequestJson = PostCardAccountDepositAddressInput +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDDepositAddressesRequestJson = PostCardAccountDepositAddressInput +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDDepositAddresses200 = CardAccountFundingInstructions +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDDepositAddresses200 = CardAccountFundingInstructions +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDDepositAddresses400 = Error +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDDepositAddresses400 = Error +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDDepositAddresses401 = Error +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDDepositAddresses401 = Error +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDDepositAddresses500 = Error +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDDepositAddresses500 = Error +export type GetCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawalsParams = { readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string } +export const GetCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawalsParams = Schema.Struct({ "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String) }) +export type GetCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawalsPathParams = { readonly "customerID": Id, readonly "cardAccountID": Id } +export const GetCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawalsPathParams = Schema.Struct({ "customerID": Id, "cardAccountID": Id }) +export type GetCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawalsQuery = { readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string } +export const GetCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawalsQuery = Schema.Struct({ "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String) }) +export type GetCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawals200 = { readonly "count": number, readonly "data": ReadonlyArray } +export const GetCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawals200 = Schema.Struct({ "count": Schema.Number.annotate({ "description": "The number of withdrawals returned" }).check(Schema.isInt().annotate({ "expected": "an integer" })), "data": Schema.Array(CardWithdrawal).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" })) }).annotate({ "title": "List of withdrawals" }) +export type GetCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawals401 = Error +export const GetCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawals401 = Error +export type GetCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawals500 = Error +export const GetCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawals500 = Error +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawalsParams = { readonly "Idempotency-Key": string } +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawalsParams = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawalsPathParams = { readonly "customerID": Id, readonly "cardAccountID": Id } +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawalsPathParams = Schema.Struct({ "customerID": Id, "cardAccountID": Id }) +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawalsHeaders = { readonly "Idempotency-Key": string } +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawalsHeaders = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawalsRequestJson = CardWithdrawal +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawalsRequestJson = CardWithdrawal +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawals201 = CardWithdrawal +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawals201 = CardWithdrawal +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawals400 = Error +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawals400 = Error +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawals401 = Error +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawals401 = Error +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawals500 = Error +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawals500 = Error +export type GetCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawalsByCardWithdrawalIDPathParams = { readonly "customerID": Id, readonly "cardAccountID": Id, readonly "cardWithdrawalID": Id } +export const GetCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawalsByCardWithdrawalIDPathParams = Schema.Struct({ "customerID": Id, "cardAccountID": Id, "cardWithdrawalID": Id }) +export type GetCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawalsByCardWithdrawalID200 = CardWithdrawal +export const GetCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawalsByCardWithdrawalID200 = CardWithdrawal +export type GetCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawalsByCardWithdrawalID401 = Error +export const GetCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawalsByCardWithdrawalID401 = Error +export type GetCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawalsByCardWithdrawalID500 = Error +export const GetCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawalsByCardWithdrawalID500 = Error +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDStatementsPeriodPdfPathParams = { readonly "customerID": Id, readonly "cardAccountID": Id, readonly "period": string } +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDStatementsPeriodPdfPathParams = Schema.Struct({ "customerID": Id, "cardAccountID": Id, "period": Schema.String }) +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDStatementsPeriodPdf200ApplicationPdf = Uint8Array +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDStatementsPeriodPdf200ApplicationPdf = Schema.Uint8Array.annotate({ "format": "binary" }) +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDStatementsPeriodPdf400 = Error +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDStatementsPeriodPdf400 = Error +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDStatementsPeriodPdf401 = Error +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDStatementsPeriodPdf401 = Error +export type PostCustomersByCustomerIDCardAccountsByCardAccountIDStatementsPeriodPdf500 = Error +export const PostCustomersByCustomerIDCardAccountsByCardAccountIDStatementsPeriodPdf500 = Error +export type PostCardholdersByCardholderIDCardsByCardIDStatementsPeriodPdfPathParams = { readonly "cardholderID": string, readonly "cardID": string, readonly "period": string } +export const PostCardholdersByCardholderIDCardsByCardIDStatementsPeriodPdfPathParams = Schema.Struct({ "cardholderID": Schema.String, "cardID": Schema.String, "period": Schema.String }) +export type PostCardholdersByCardholderIDCardsByCardIDStatementsPeriodPdf200ApplicationPdf = Uint8Array +export const PostCardholdersByCardholderIDCardsByCardIDStatementsPeriodPdf200ApplicationPdf = Schema.Uint8Array.annotate({ "format": "binary" }) +export type PostCardholdersByCardholderIDCardsByCardIDStatementsPeriodPdf400 = Error +export const PostCardholdersByCardholderIDCardsByCardIDStatementsPeriodPdf400 = Error +export type PostCardholdersByCardholderIDCardsByCardIDStatementsPeriodPdf401 = Error +export const PostCardholdersByCardholderIDCardsByCardIDStatementsPeriodPdf401 = Error +export type PostCardholdersByCardholderIDCardsByCardIDStatementsPeriodPdf500 = Error +export const PostCardholdersByCardholderIDCardsByCardIDStatementsPeriodPdf500 = Error +export type GetLiquidationAddressesDrainsParams = { readonly "tx_hash"?: string, readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string, readonly "updated_after_ms"?: number, readonly "updated_before_ms"?: number, readonly "drain_id"?: string } +export const GetLiquidationAddressesDrainsParams = Schema.Struct({ "tx_hash": Schema.optionalKey(Schema.String), "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String), "updated_after_ms": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), "updated_before_ms": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), "drain_id": Schema.optionalKey(Schema.String) }) +export type GetLiquidationAddressesDrainsQuery = { readonly "tx_hash"?: string, readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string, readonly "updated_after_ms"?: number, readonly "updated_before_ms"?: number, readonly "drain_id"?: string } +export const GetLiquidationAddressesDrainsQuery = Schema.Struct({ "tx_hash": Schema.optionalKey(Schema.String), "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String), "updated_after_ms": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), "updated_before_ms": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), "drain_id": Schema.optionalKey(Schema.String) }) +export type GetLiquidationAddressesDrains200 = { readonly "count": number, readonly "data": ReadonlyArray } +export const GetLiquidationAddressesDrains200 = Schema.Struct({ "count": Schema.Number.annotate({ "description": "The number of events returned" }).check(Schema.isInt().annotate({ "expected": "an integer" })), "data": Schema.Array(Drain).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" })) }).annotate({ "title": "Liquidation Address history" }) +export type GetLiquidationAddressesDrains400 = Error +export const GetLiquidationAddressesDrains400 = Error +export type GetLiquidationAddressesDrains401 = Error +export const GetLiquidationAddressesDrains401 = Error +export type GetLiquidationAddressesDrains500 = Error +export const GetLiquidationAddressesDrains500 = Error +export type GetLiquidationAddressesDrainsPendingParams = { readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string, readonly "updated_after_ms"?: number, readonly "updated_before_ms"?: number } +export const GetLiquidationAddressesDrainsPendingParams = Schema.Struct({ "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String), "updated_after_ms": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), "updated_before_ms": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))) }) +export type GetLiquidationAddressesDrainsPendingQuery = { readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string, readonly "updated_after_ms"?: number, readonly "updated_before_ms"?: number } +export const GetLiquidationAddressesDrainsPendingQuery = Schema.Struct({ "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String), "updated_after_ms": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))), "updated_before_ms": Schema.optionalKey(Schema.Number.check(Schema.isInt().annotate({ "expected": "an integer" }))) }) +export type GetLiquidationAddressesDrainsPending200 = { readonly "count": number, readonly "data": ReadonlyArray } +export const GetLiquidationAddressesDrainsPending200 = Schema.Struct({ "count": Schema.Number.annotate({ "description": "The number of drains returned" }).check(Schema.isInt().annotate({ "expected": "an integer" })), "data": Schema.Array(Drain).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" })) }).annotate({ "title": "PendingDrains" }) +export type GetLiquidationAddressesDrainsPending400 = Error +export const GetLiquidationAddressesDrainsPending400 = Error +export type GetLiquidationAddressesDrainsPending401 = Error +export const GetLiquidationAddressesDrainsPending401 = Error +export type GetLiquidationAddressesDrainsPending500 = Error +export const GetLiquidationAddressesDrainsPending500 = Error +export type GetFeesConfigurationsParams = { readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string } +export const GetFeesConfigurationsParams = Schema.Struct({ "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String) }) +export type GetFeesConfigurationsQuery = { readonly "limit"?: number, readonly "starting_after"?: string, readonly "ending_before"?: string } +export const GetFeesConfigurationsQuery = Schema.Struct({ "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 10 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" }))), "starting_after": Schema.optionalKey(Schema.String), "ending_before": Schema.optionalKey(Schema.String) }) +export type GetFeesConfigurations200 = { readonly "count": number, readonly "data": ReadonlyArray } +export const GetFeesConfigurations200 = Schema.Struct({ "count": Schema.Number.annotate({ "description": "total number of items in data" }).check(Schema.isInt().annotate({ "expected": "an integer" })), "data": Schema.Array(DeveloperFeeConfig).check(Schema.isMinLength(0).annotate({ "expected": "a value with a length of at least 0" })) }).annotate({ "title": "DeveloperFeeConfigs" }) +export type GetFeesConfigurations400 = Error +export const GetFeesConfigurations400 = Error +export type GetFeesConfigurations401 = Error +export const GetFeesConfigurations401 = Error +export type GetFeesConfigurations500 = Error +export const GetFeesConfigurations500 = Error +export type PostFeesConfigurationsParams = { readonly "Idempotency-Key": string } +export const PostFeesConfigurationsParams = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostFeesConfigurationsHeaders = { readonly "Idempotency-Key": string } +export const PostFeesConfigurationsHeaders = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostFeesConfigurationsRequestJson = CreateDeveloperFeeConfig +export const PostFeesConfigurationsRequestJson = CreateDeveloperFeeConfig +export type PostFeesConfigurations201 = DeveloperFeeConfig +export const PostFeesConfigurations201 = DeveloperFeeConfig +export type PostFeesConfigurations400 = Error +export const PostFeesConfigurations400 = Error +export type PostFeesConfigurations401 = Error +export const PostFeesConfigurations401 = Error +export type PostFeesConfigurations500 = Error +export const PostFeesConfigurations500 = Error +export type GetFeesConfigurationsByDeveloperFeeConfigIDPathParams = { readonly "developerFeeConfigID": Id } +export const GetFeesConfigurationsByDeveloperFeeConfigIDPathParams = Schema.Struct({ "developerFeeConfigID": Id }) +export type GetFeesConfigurationsByDeveloperFeeConfigID200 = DeveloperFeeConfig +export const GetFeesConfigurationsByDeveloperFeeConfigID200 = DeveloperFeeConfig +export type GetFeesConfigurationsByDeveloperFeeConfigID400 = Error +export const GetFeesConfigurationsByDeveloperFeeConfigID400 = Error +export type GetFeesConfigurationsByDeveloperFeeConfigID401 = Error +export const GetFeesConfigurationsByDeveloperFeeConfigID401 = Error +export type GetFeesConfigurationsByDeveloperFeeConfigID404 = Error +export const GetFeesConfigurationsByDeveloperFeeConfigID404 = Error +export type GetFeesConfigurationsByDeveloperFeeConfigID500 = Error +export const GetFeesConfigurationsByDeveloperFeeConfigID500 = Error +export type PutFeesConfigurationsByDeveloperFeeConfigIDPathParams = { readonly "developerFeeConfigID": Id } +export const PutFeesConfigurationsByDeveloperFeeConfigIDPathParams = Schema.Struct({ "developerFeeConfigID": Id }) +export type PutFeesConfigurationsByDeveloperFeeConfigIDRequestJson = UpdateDeveloperFeeConfig +export const PutFeesConfigurationsByDeveloperFeeConfigIDRequestJson = UpdateDeveloperFeeConfig +export type PutFeesConfigurationsByDeveloperFeeConfigID200 = DeveloperFeeConfig +export const PutFeesConfigurationsByDeveloperFeeConfigID200 = DeveloperFeeConfig +export type PutFeesConfigurationsByDeveloperFeeConfigID400 = Error +export const PutFeesConfigurationsByDeveloperFeeConfigID400 = Error +export type PutFeesConfigurationsByDeveloperFeeConfigID401 = Error +export const PutFeesConfigurationsByDeveloperFeeConfigID401 = Error +export type PutFeesConfigurationsByDeveloperFeeConfigID404 = Error +export const PutFeesConfigurationsByDeveloperFeeConfigID404 = Error +export type PutFeesConfigurationsByDeveloperFeeConfigID500 = Error +export const PutFeesConfigurationsByDeveloperFeeConfigID500 = Error +export type GetRewardsByCurrencyPathParams = { readonly "currency": string } +export const GetRewardsByCurrencyPathParams = Schema.Struct({ "currency": Schema.String }) +export type GetRewardsByCurrency200 = DeveloperRewardSummary +export const GetRewardsByCurrency200 = DeveloperRewardSummary +export type GetRewardsByCurrency401 = Error +export const GetRewardsByCurrency401 = Error +export type GetRewardsByCurrency500 = Error +export const GetRewardsByCurrency500 = Error +export type GetRewardsByCurrencyHistoryParams = { readonly "limit"?: number, readonly "cursor"?: string } +export const GetRewardsByCurrencyHistoryParams = Schema.Struct({ "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 30 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(90).annotate({ "expected": "a value less than or equal to 90" }))), "cursor": Schema.optionalKey(Schema.String) }) +export type GetRewardsByCurrencyHistoryPathParams = { readonly "currency": string } +export const GetRewardsByCurrencyHistoryPathParams = Schema.Struct({ "currency": Schema.String }) +export type GetRewardsByCurrencyHistoryQuery = { readonly "limit"?: number, readonly "cursor"?: string } +export const GetRewardsByCurrencyHistoryQuery = Schema.Struct({ "limit": Schema.optionalKey(Schema.Number.annotate({ "default": 30 }).check(Schema.isInt().annotate({ "expected": "an integer" })).check(Schema.isGreaterThanOrEqualTo(1).annotate({ "expected": "a value greater than or equal to 1" })).check(Schema.isLessThanOrEqualTo(90).annotate({ "expected": "a value less than or equal to 90" }))), "cursor": Schema.optionalKey(Schema.String) }) +export type GetRewardsByCurrencyHistory200 = DeveloperRewardHistory +export const GetRewardsByCurrencyHistory200 = DeveloperRewardHistory +export type GetRewardsByCurrencyHistory400 = Error +export const GetRewardsByCurrencyHistory400 = Error +export type GetRewardsByCurrencyHistory401 = Error +export const GetRewardsByCurrencyHistory401 = Error +export type GetRewardsByCurrencyHistory500 = Error +export const GetRewardsByCurrencyHistory500 = Error +export type GetRewardsByCurrencyCustomerByCustomerIDPathParams = { readonly "currency": string, readonly "customerID": Id } +export const GetRewardsByCurrencyCustomerByCustomerIDPathParams = Schema.Struct({ "currency": Schema.String, "customerID": Id }) +export type GetRewardsByCurrencyCustomerByCustomerID200 = CustomerRewardSummary +export const GetRewardsByCurrencyCustomerByCustomerID200 = CustomerRewardSummary +export type GetRewardsByCurrencyCustomerByCustomerID401 = Error +export const GetRewardsByCurrencyCustomerByCustomerID401 = Error +export type GetRewardsByCurrencyCustomerByCustomerID500 = Error +export const GetRewardsByCurrencyCustomerByCustomerID500 = Error +export type GetRewardsByCurrencyCustomerByCustomerIDHistoryPathParams = { readonly "currency": string, readonly "customerID": Id } +export const GetRewardsByCurrencyCustomerByCustomerIDHistoryPathParams = Schema.Struct({ "currency": Schema.String, "customerID": Id }) +export type GetRewardsByCurrencyCustomerByCustomerIDHistory200 = CustomerRewardHistory +export const GetRewardsByCurrencyCustomerByCustomerIDHistory200 = CustomerRewardHistory +export type GetRewardsByCurrencyCustomerByCustomerIDHistory401 = Error +export const GetRewardsByCurrencyCustomerByCustomerIDHistory401 = Error +export type GetRewardsByCurrencyCustomerByCustomerIDHistory500 = Error +export const GetRewardsByCurrencyCustomerByCustomerIDHistory500 = Error +export type PostCustomersByCustomerIDSimulateKycApprovalParams = { readonly "Idempotency-Key": string } +export const PostCustomersByCustomerIDSimulateKycApprovalParams = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostCustomersByCustomerIDSimulateKycApprovalPathParams = { readonly "customerID": Id } +export const PostCustomersByCustomerIDSimulateKycApprovalPathParams = Schema.Struct({ "customerID": Id }) +export type PostCustomersByCustomerIDSimulateKycApprovalHeaders = { readonly "Idempotency-Key": string } +export const PostCustomersByCustomerIDSimulateKycApprovalHeaders = Schema.Struct({ "Idempotency-Key": Schema.String }) +export type PostCustomersByCustomerIDSimulateKycApproval200 = SimulateKycApprovalResponse +export const PostCustomersByCustomerIDSimulateKycApproval200 = SimulateKycApprovalResponse +export type PostCustomersByCustomerIDSimulateKycApproval401 = Error +export const PostCustomersByCustomerIDSimulateKycApproval401 = Error +export type PostCustomersByCustomerIDSimulateKycApproval404 = Error +export const PostCustomersByCustomerIDSimulateKycApproval404 = Error +export type PostCustomersByCustomerIDSimulateKycApproval500 = Error +export const PostCustomersByCustomerIDSimulateKycApproval500 = Error + +export const ApiKeySecurity = HttpApiSecurity.apiKey({ key: "Api-Key", in: "header" }) + +export class ApiKeySecurityMiddleware extends HttpApiMiddleware.Service()("ApiKey security", { security: { "ApiKey": ApiKeySecurity } }) {} + +class BridgeWalletsGroup extends HttpApiGroup.make("bridgeWallets") + .add(HttpApiEndpoint.get("getWallets", "/wallets", { query: GetWalletsQuery, success: GetWallets200, error: [GetWallets400.pipe(HttpApiSchema.status(400)), GetWallets401.pipe(HttpApiSchema.status(401)), GetWallets404.pipe(HttpApiSchema.status(404)), GetWallets500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getWallets") + .annotate(OpenApi.Summary, "Get all Bridge Wallets") + .annotate(OpenApi.Description, "List of Bridge Wallets"), + HttpApiEndpoint.get("getWalletsTotalBalances", "/wallets/total_balances", { success: GetWalletsTotalBalances200, error: [GetWalletsTotalBalances400.pipe(HttpApiSchema.status(400)), GetWalletsTotalBalances401.pipe(HttpApiSchema.status(401)), GetWalletsTotalBalances404.pipe(HttpApiSchema.status(404)), GetWalletsTotalBalances500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getWalletsTotalBalances") + .annotate(OpenApi.Summary, "Get total balances of all Bridge Wallets") + .annotate(OpenApi.Description, "Get the total balances of all Bridge Wallets"), + HttpApiEndpoint.get("getWalletsByBridgeWalletID", "/wallets/:bridgeWalletID", { params: GetWalletsByBridgeWalletIDPathParams, success: GetWalletsByBridgeWalletID200, error: [GetWalletsByBridgeWalletID400.pipe(HttpApiSchema.status(400)), GetWalletsByBridgeWalletID401.pipe(HttpApiSchema.status(401)), GetWalletsByBridgeWalletID404.pipe(HttpApiSchema.status(404)), GetWalletsByBridgeWalletID500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getWalletsByBridgeWalletID") + .annotate(OpenApi.Summary, "Get a Bridge Wallet") + .annotate(OpenApi.Description, "Retrieve a Bridge Wallet by its ID"), + HttpApiEndpoint.get("getWalletsByBridgeWalletIDHistory", "/wallets/:bridgeWalletID/history", { params: GetWalletsByBridgeWalletIDHistoryPathParams, query: GetWalletsByBridgeWalletIDHistoryQuery, success: GetWalletsByBridgeWalletIDHistory200, error: [GetWalletsByBridgeWalletIDHistory400.pipe(HttpApiSchema.status(400)), GetWalletsByBridgeWalletIDHistory401.pipe(HttpApiSchema.status(401)), GetWalletsByBridgeWalletIDHistory404.pipe(HttpApiSchema.status(404)), GetWalletsByBridgeWalletIDHistory500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getWalletsByBridgeWalletIDHistory") + .annotate(OpenApi.Summary, "Get transaction history for a Bridge Wallet") + .annotate(OpenApi.Description, "Get the list of transactions involving this Bridge Wallet"), + HttpApiEndpoint.get("getCustomersByCustomerIDWallets", "/customers/:customerID/wallets", { params: GetCustomersByCustomerIDWalletsPathParams, query: GetCustomersByCustomerIDWalletsQuery, success: GetCustomersByCustomerIDWallets200, error: [GetCustomersByCustomerIDWallets400.pipe(HttpApiSchema.status(400)), GetCustomersByCustomerIDWallets401.pipe(HttpApiSchema.status(401)), GetCustomersByCustomerIDWallets404.pipe(HttpApiSchema.status(404)), GetCustomersByCustomerIDWallets500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getCustomersByCustomerIDWallets") + .annotate(OpenApi.Summary, "Get all Bridge Wallets for a customer") + .annotate(OpenApi.Description, "List of Bridge Wallets for the specified Customer ID"), + HttpApiEndpoint.post("postCustomersByCustomerIDWallets", "/customers/:customerID/wallets", { params: PostCustomersByCustomerIDWalletsPathParams, headers: PostCustomersByCustomerIDWalletsHeaders, payload: PostCustomersByCustomerIDWalletsRequestJson, success: PostCustomersByCustomerIDWallets201.pipe(HttpApiSchema.status(201)), error: [PostCustomersByCustomerIDWallets400.pipe(HttpApiSchema.status(400)), PostCustomersByCustomerIDWallets401.pipe(HttpApiSchema.status(401)), PostCustomersByCustomerIDWallets404.pipe(HttpApiSchema.status(404)), PostCustomersByCustomerIDWallets500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "postCustomersByCustomerIDWallets") + .annotate(OpenApi.Summary, "Create a Bridge Wallet"), + HttpApiEndpoint.get("getCustomersByCustomerIDWalletsByBridgeWalletID", "/customers/:customerID/wallets/:bridgeWalletID", { params: GetCustomersByCustomerIDWalletsByBridgeWalletIDPathParams, success: GetCustomersByCustomerIDWalletsByBridgeWalletID200, error: [GetCustomersByCustomerIDWalletsByBridgeWalletID400.pipe(HttpApiSchema.status(400)), GetCustomersByCustomerIDWalletsByBridgeWalletID401.pipe(HttpApiSchema.status(401)), GetCustomersByCustomerIDWalletsByBridgeWalletID404.pipe(HttpApiSchema.status(404)), GetCustomersByCustomerIDWalletsByBridgeWalletID500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getCustomersByCustomerIDWalletsByBridgeWalletID") + .annotate(OpenApi.Summary, "Get a Bridge Wallet") + .annotate(OpenApi.Description, "Retrieve a Bridge Wallet for the specified Bridge Wallet ID")) {} + +class CustomersGroup extends HttpApiGroup.make("customers") + .add(HttpApiEndpoint.get("getCustomers", "/customers", { query: GetCustomersQuery, success: GetCustomers200, error: [GetCustomers401.pipe(HttpApiSchema.status(401)), GetCustomers500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getCustomers") + .annotate(OpenApi.Summary, "Get all customers") + .annotate(OpenApi.Description, "Get the full list of all customers created on Bridge"), + HttpApiEndpoint.post("postCustomers", "/customers", { headers: PostCustomersHeaders, payload: PostCustomersRequestJson, success: PostCustomers201.pipe(HttpApiSchema.status(201)), error: [PostCustomers400.pipe(HttpApiSchema.status(400)), PostCustomers401.pipe(HttpApiSchema.status(401)), PostCustomers500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "postCustomers") + .annotate(OpenApi.Summary, "Create a customer"), + HttpApiEndpoint.get("getCustomersByCustomerID", "/customers/:customerID", { params: GetCustomersByCustomerIDPathParams, success: GetCustomersByCustomerID200, error: [GetCustomersByCustomerID401.pipe(HttpApiSchema.status(401)), GetCustomersByCustomerID404.pipe(HttpApiSchema.status(404)), GetCustomersByCustomerID500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getCustomersByCustomerID") + .annotate(OpenApi.Summary, "Get a single customer object") + .annotate(OpenApi.Description, "Retrieve a customer object from the passed in customer ID"), + HttpApiEndpoint.put("putCustomersByCustomerID", "/customers/:customerID", { params: PutCustomersByCustomerIDPathParams, payload: PutCustomersByCustomerIDRequestJson, success: PutCustomersByCustomerID200, error: [PutCustomersByCustomerID401.pipe(HttpApiSchema.status(401)), PutCustomersByCustomerID404.pipe(HttpApiSchema.status(404)), PutCustomersByCustomerID500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "putCustomersByCustomerID") + .annotate(OpenApi.Summary, "Update a single customer object") + .annotate(OpenApi.Description, "Updates to be made to the specified customer.\n\nNo fields are strictly required by the API. It is generally valid to provide any subset of data in a PUT request. For business customers, associated persons cannot be updated via PUT, and should instead be managed using v0/associated_persons."), + HttpApiEndpoint.delete("deleteCustomersByCustomerID", "/customers/:customerID", { params: DeleteCustomersByCustomerIDPathParams, success: DeleteCustomersByCustomerID200, error: [DeleteCustomersByCustomerID401.pipe(HttpApiSchema.status(401)), DeleteCustomersByCustomerID404.pipe(HttpApiSchema.status(404)), DeleteCustomersByCustomerID500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "deleteCustomersByCustomerID") + .annotate(OpenApi.Summary, "Delete a single customer object") + .annotate(OpenApi.Description, "Delete a customer object from the passed in customer ID"), + HttpApiEndpoint.get("getCustomersByCustomerIDAssociatedPersons", "/customers/:customerID/associated_persons", { params: GetCustomersByCustomerIDAssociatedPersonsPathParams, success: GetCustomersByCustomerIDAssociatedPersons200, error: [GetCustomersByCustomerIDAssociatedPersons401.pipe(HttpApiSchema.status(401)), GetCustomersByCustomerIDAssociatedPersons404.pipe(HttpApiSchema.status(404)), GetCustomersByCustomerIDAssociatedPersons500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getCustomersByCustomerIDAssociatedPersons") + .annotate(OpenApi.Summary, "Get associated persons for a business customer") + .annotate(OpenApi.Description, "Get all associated persons for a business customer."), + HttpApiEndpoint.post("postCustomersByCustomerIDAssociatedPersons", "/customers/:customerID/associated_persons", { params: PostCustomersByCustomerIDAssociatedPersonsPathParams, headers: PostCustomersByCustomerIDAssociatedPersonsHeaders, payload: PostCustomersByCustomerIDAssociatedPersonsRequestJson, success: PostCustomersByCustomerIDAssociatedPersons201.pipe(HttpApiSchema.status(201)), error: [PostCustomersByCustomerIDAssociatedPersons400.pipe(HttpApiSchema.status(400)), PostCustomersByCustomerIDAssociatedPersons401.pipe(HttpApiSchema.status(401)), PostCustomersByCustomerIDAssociatedPersons404.pipe(HttpApiSchema.status(404)), PostCustomersByCustomerIDAssociatedPersons500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "postCustomersByCustomerIDAssociatedPersons") + .annotate(OpenApi.Summary, "Create a new associated person for a business customer"), + HttpApiEndpoint.get("getCustomersByCustomerIDAssociatedPersonsByAssociatedPersonID", "/customers/:customerID/associated_persons/:associatedPersonID", { params: GetCustomersByCustomerIDAssociatedPersonsByAssociatedPersonIDPathParams, success: GetCustomersByCustomerIDAssociatedPersonsByAssociatedPersonID200, error: [GetCustomersByCustomerIDAssociatedPersonsByAssociatedPersonID401.pipe(HttpApiSchema.status(401)), GetCustomersByCustomerIDAssociatedPersonsByAssociatedPersonID404.pipe(HttpApiSchema.status(404)), GetCustomersByCustomerIDAssociatedPersonsByAssociatedPersonID500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getCustomersByCustomerIDAssociatedPersonsByAssociatedPersonID") + .annotate(OpenApi.Summary, "Get a single associated person") + .annotate(OpenApi.Description, "Retrieve an associated person by ID"), + HttpApiEndpoint.put("putCustomersByCustomerIDAssociatedPersonsByAssociatedPersonID", "/customers/:customerID/associated_persons/:associatedPersonID", { params: PutCustomersByCustomerIDAssociatedPersonsByAssociatedPersonIDPathParams, payload: PutCustomersByCustomerIDAssociatedPersonsByAssociatedPersonIDRequestJson, success: PutCustomersByCustomerIDAssociatedPersonsByAssociatedPersonID200, error: [PutCustomersByCustomerIDAssociatedPersonsByAssociatedPersonID400.pipe(HttpApiSchema.status(400)), PutCustomersByCustomerIDAssociatedPersonsByAssociatedPersonID401.pipe(HttpApiSchema.status(401)), PutCustomersByCustomerIDAssociatedPersonsByAssociatedPersonID404.pipe(HttpApiSchema.status(404)), PutCustomersByCustomerIDAssociatedPersonsByAssociatedPersonID500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "putCustomersByCustomerIDAssociatedPersonsByAssociatedPersonID") + .annotate(OpenApi.Summary, "Update a single associated person"), + HttpApiEndpoint.delete("deleteCustomersByCustomerIDAssociatedPersonsByAssociatedPersonID", "/customers/:customerID/associated_persons/:associatedPersonID", { params: DeleteCustomersByCustomerIDAssociatedPersonsByAssociatedPersonIDPathParams, success: DeleteCustomersByCustomerIDAssociatedPersonsByAssociatedPersonID200, error: [DeleteCustomersByCustomerIDAssociatedPersonsByAssociatedPersonID401.pipe(HttpApiSchema.status(401)), DeleteCustomersByCustomerIDAssociatedPersonsByAssociatedPersonID404.pipe(HttpApiSchema.status(404)), DeleteCustomersByCustomerIDAssociatedPersonsByAssociatedPersonID500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "deleteCustomersByCustomerIDAssociatedPersonsByAssociatedPersonID") + .annotate(OpenApi.Summary, "Delete a single associated person") + .annotate(OpenApi.Description, "Delete an associated person by ID"), + HttpApiEndpoint.get("getCustomersByCustomerIDTosAcceptanceLink", "/customers/:customerID/tos_acceptance_link", { params: GetCustomersByCustomerIDTosAcceptanceLinkPathParams, success: GetCustomersByCustomerIDTosAcceptanceLink200, error: [GetCustomersByCustomerIDTosAcceptanceLink401.pipe(HttpApiSchema.status(401)), GetCustomersByCustomerIDTosAcceptanceLink500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getCustomersByCustomerIDTosAcceptanceLink") + .annotate(OpenApi.Summary, "Retrieve a hosted URL for ToS acceptance for an existing customer") + .annotate(OpenApi.Description, "The page at the returned URL will guide the user through the Bridge Terms of Service (ToS) acceptance flow. This can be used by existing customers to accept a new version of the ToS."), + HttpApiEndpoint.get("getCustomersByCustomerIDKycLink", "/customers/:customerID/kyc_link", { params: GetCustomersByCustomerIDKycLinkPathParams, query: GetCustomersByCustomerIDKycLinkQuery, success: GetCustomersByCustomerIDKycLink200, error: [GetCustomersByCustomerIDKycLink401.pipe(HttpApiSchema.status(401)), GetCustomersByCustomerIDKycLink500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getCustomersByCustomerIDKycLink") + .annotate(OpenApi.Summary, "Retrieve a hosted KYC Link for an existing customer") + .annotate(OpenApi.Description, "The page at the returned URL will guide the user through a Bridge KYC flow. This can be used by existing customers to provide additional KYC information required for certain features or services that Bridge offers.\n\nFor example, to enable an existing customer to use the `SEPA`/`Euro` services, they are required to provide `proof of address`. An additional parameter, `endorsement=sepa`, can be included to request a KYC link specifically for this purpose"), + HttpApiEndpoint.get("getCustomersByCustomerIDTransfers", "/customers/:customerID/transfers", { params: GetCustomersByCustomerIDTransfersPathParams, query: GetCustomersByCustomerIDTransfersQuery, success: GetCustomersByCustomerIDTransfers200, error: [GetCustomersByCustomerIDTransfers401.pipe(HttpApiSchema.status(401)), GetCustomersByCustomerIDTransfers500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getCustomersByCustomerIDTransfers") + .annotate(OpenApi.Summary, "Get all transfers") + .annotate(OpenApi.Description, "Get all active and completed transfers for a customer."), + HttpApiEndpoint.get("getCustomersByCustomerIDTransfersStaticTemplates", "/customers/:customerID/transfers/static_templates", { params: GetCustomersByCustomerIDTransfersStaticTemplatesPathParams, query: GetCustomersByCustomerIDTransfersStaticTemplatesQuery, success: GetCustomersByCustomerIDTransfersStaticTemplates200, error: [GetCustomersByCustomerIDTransfersStaticTemplates401.pipe(HttpApiSchema.status(401)), GetCustomersByCustomerIDTransfersStaticTemplates404.pipe(HttpApiSchema.status(404)), GetCustomersByCustomerIDTransfersStaticTemplates500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getCustomersByCustomerIDTransfersStaticTemplates") + .annotate(OpenApi.Summary, "Get all static templates for a customer") + .annotate(OpenApi.Description, "Get all static templates for a customer. Static templates are transfers that are used as templates for other transfers and can be created using the static_templates feature flag."), + HttpApiEndpoint.post("postCustomersTosLinks", "/customers/tos_links", { headers: PostCustomersTosLinksHeaders, success: PostCustomersTosLinks201.pipe(HttpApiSchema.status(201)), error: [PostCustomersTosLinks401.pipe(HttpApiSchema.status(401)), PostCustomersTosLinks500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "postCustomersTosLinks") + .annotate(OpenApi.Summary, "Request a hosted URL for ToS acceptance for new customer creation") + .annotate(OpenApi.Description, "The URL endpoint returned will guide the user through a Bridge TOS flow. Signing this acceptance flow is a requirement for creating customers.")) {} + +class ExternalAccountsGroup extends HttpApiGroup.make("externalAccounts") + .add(HttpApiEndpoint.get("getCustomersByCustomerIDExternalAccounts", "/customers/:customerID/external_accounts", { params: GetCustomersByCustomerIDExternalAccountsPathParams, query: GetCustomersByCustomerIDExternalAccountsQuery, success: GetCustomersByCustomerIDExternalAccounts200, error: [GetCustomersByCustomerIDExternalAccounts401.pipe(HttpApiSchema.status(401)), GetCustomersByCustomerIDExternalAccounts500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getCustomersByCustomerIDExternalAccounts") + .annotate(OpenApi.Summary, "Get all External Accounts") + .annotate(OpenApi.Description, "Get all External Accounts for a passed in customer."), + HttpApiEndpoint.post("postCustomersByCustomerIDExternalAccounts", "/customers/:customerID/external_accounts", { params: PostCustomersByCustomerIDExternalAccountsPathParams, headers: PostCustomersByCustomerIDExternalAccountsHeaders, payload: PostCustomersByCustomerIDExternalAccountsRequestJson, success: PostCustomersByCustomerIDExternalAccounts201.pipe(HttpApiSchema.status(201)), error: [PostCustomersByCustomerIDExternalAccounts400.pipe(HttpApiSchema.status(400)), PostCustomersByCustomerIDExternalAccounts401.pipe(HttpApiSchema.status(401)), PostCustomersByCustomerIDExternalAccounts500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "postCustomersByCustomerIDExternalAccounts") + .annotate(OpenApi.Summary, "Create a new External Account") + .annotate(OpenApi.Description, "_Note_: If adding US external accounts, we recommend reading through the US Beneficiary Address Validation doc ([link](https://apidocs.bridge.xyz/docs/us-beneficiary-address-validation)) to avoid issues related to incorrect addresses."), + HttpApiEndpoint.get("getCustomersByCustomerIDExternalAccountsByExternalAccountID", "/customers/:customerID/external_accounts/:externalAccountID", { params: GetCustomersByCustomerIDExternalAccountsByExternalAccountIDPathParams, success: GetCustomersByCustomerIDExternalAccountsByExternalAccountID200, error: [GetCustomersByCustomerIDExternalAccountsByExternalAccountID401.pipe(HttpApiSchema.status(401)), GetCustomersByCustomerIDExternalAccountsByExternalAccountID404.pipe(HttpApiSchema.status(404)), GetCustomersByCustomerIDExternalAccountsByExternalAccountID500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getCustomersByCustomerIDExternalAccountsByExternalAccountID") + .annotate(OpenApi.Summary, "Retrieve an External Account object") + .annotate(OpenApi.Description, "Retrieve an External Account object (banks, debit cards etc) from the passed in customer ID and External Account ID"), + HttpApiEndpoint.put("putCustomersByCustomerIDExternalAccountsByExternalAccountID", "/customers/:customerID/external_accounts/:externalAccountID", { params: PutCustomersByCustomerIDExternalAccountsByExternalAccountIDPathParams, payload: PutCustomersByCustomerIDExternalAccountsByExternalAccountIDRequestJson, success: PutCustomersByCustomerIDExternalAccountsByExternalAccountID200, error: [PutCustomersByCustomerIDExternalAccountsByExternalAccountID400.pipe(HttpApiSchema.status(400)), PutCustomersByCustomerIDExternalAccountsByExternalAccountID401.pipe(HttpApiSchema.status(401)), PutCustomersByCustomerIDExternalAccountsByExternalAccountID500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "putCustomersByCustomerIDExternalAccountsByExternalAccountID") + .annotate(OpenApi.Summary, "Update an External Account"), + HttpApiEndpoint.delete("deleteCustomersByCustomerIDExternalAccountsByExternalAccountID", "/customers/:customerID/external_accounts/:externalAccountID", { params: DeleteCustomersByCustomerIDExternalAccountsByExternalAccountIDPathParams, success: DeleteCustomersByCustomerIDExternalAccountsByExternalAccountID200, error: [DeleteCustomersByCustomerIDExternalAccountsByExternalAccountID401.pipe(HttpApiSchema.status(401)), DeleteCustomersByCustomerIDExternalAccountsByExternalAccountID404.pipe(HttpApiSchema.status(404)), DeleteCustomersByCustomerIDExternalAccountsByExternalAccountID500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "deleteCustomersByCustomerIDExternalAccountsByExternalAccountID") + .annotate(OpenApi.Summary, "Delete a single External Account object") + .annotate(OpenApi.Description, "Delete an External Account object from the passed in External Account ID"), + HttpApiEndpoint.post("postCustomersByCustomerIDExternalAccountsByExternalAccountIDDeactivate", "/customers/:customerID/external_accounts/:externalAccountID/deactivate", { params: PostCustomersByCustomerIDExternalAccountsByExternalAccountIDDeactivatePathParams, headers: PostCustomersByCustomerIDExternalAccountsByExternalAccountIDDeactivateHeaders, success: PostCustomersByCustomerIDExternalAccountsByExternalAccountIDDeactivate200, error: [PostCustomersByCustomerIDExternalAccountsByExternalAccountIDDeactivate401.pipe(HttpApiSchema.status(401)), PostCustomersByCustomerIDExternalAccountsByExternalAccountIDDeactivate404.pipe(HttpApiSchema.status(404)), PostCustomersByCustomerIDExternalAccountsByExternalAccountIDDeactivate500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "postCustomersByCustomerIDExternalAccountsByExternalAccountIDDeactivate") + .annotate(OpenApi.Summary, "Deactivate an External Account") + .annotate(OpenApi.Description, "Deactivate an active External Account. The External Account is preserved and can be reactivated later via the reactivate endpoint."), + HttpApiEndpoint.post("postCustomersByCustomerIDExternalAccountsByExternalAccountIDVerify", "/customers/:customerID/external_accounts/:externalAccountID/verify", { params: PostCustomersByCustomerIDExternalAccountsByExternalAccountIDVerifyPathParams, success: PostCustomersByCustomerIDExternalAccountsByExternalAccountIDVerify200, error: [PostCustomersByCustomerIDExternalAccountsByExternalAccountIDVerify400.pipe(HttpApiSchema.status(400)), PostCustomersByCustomerIDExternalAccountsByExternalAccountIDVerify401.pipe(HttpApiSchema.status(401)), PostCustomersByCustomerIDExternalAccountsByExternalAccountIDVerify404.pipe(HttpApiSchema.status(404)), PostCustomersByCustomerIDExternalAccountsByExternalAccountIDVerify409.pipe(HttpApiSchema.status(409)), PostCustomersByCustomerIDExternalAccountsByExternalAccountIDVerify500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "postCustomersByCustomerIDExternalAccountsByExternalAccountIDVerify") + .annotate(OpenApi.Summary, "Verify an External Account") + .annotate(OpenApi.Description, "Trigger a verification check for an external account. Verifies that the `account_owner_name` matches the actual account holder at the receiving bank.\n\nSupported for `iban` (EUR), `gb` (GBP), `pix` (BRL), `clabe` (MXN), `bre_b` (COP), and `co_bank_transfer` (COP, PSE) account types only. Does not require an Idempotency-Key header.\n\nAfter triggering, poll the external account's `account_verification` field until `completed_at` is populated."), + HttpApiEndpoint.post("postCustomersByCustomerIDExternalAccountsByExternalAccountIDReactivate", "/customers/:customerID/external_accounts/:externalAccountID/reactivate", { params: PostCustomersByCustomerIDExternalAccountsByExternalAccountIDReactivatePathParams, headers: PostCustomersByCustomerIDExternalAccountsByExternalAccountIDReactivateHeaders, success: PostCustomersByCustomerIDExternalAccountsByExternalAccountIDReactivate200, error: PostCustomersByCustomerIDExternalAccountsByExternalAccountIDReactivate400.pipe(HttpApiSchema.status(400)) }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "postCustomersByCustomerIDExternalAccountsByExternalAccountIDReactivate") + .annotate(OpenApi.Summary, "Reactivate an External Account") + .annotate(OpenApi.Description, "Reactivate a previously deactivated External Account"), + HttpApiEndpoint.get("getExternalAccounts", "/external_accounts", { query: GetExternalAccountsQuery, success: GetExternalAccounts200 }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getExternalAccounts") + .annotate(OpenApi.Summary, "Get all External Accounts") + .annotate(OpenApi.Description, "Get all External Accounts.")) {} + +class FiatPayoutConfigurationGroup extends HttpApiGroup.make("fiatPayoutConfiguration") + .add(HttpApiEndpoint.get("getCustomersByCustomerIDFiatPayoutConfiguration", "/customers/:customerID/fiat_payout_configuration", { params: GetCustomersByCustomerIDFiatPayoutConfigurationPathParams, success: GetCustomersByCustomerIDFiatPayoutConfiguration200, error: [GetCustomersByCustomerIDFiatPayoutConfiguration401.pipe(HttpApiSchema.status(401)), GetCustomersByCustomerIDFiatPayoutConfiguration404.pipe(HttpApiSchema.status(404)), GetCustomersByCustomerIDFiatPayoutConfiguration500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getCustomersByCustomerIDFiatPayoutConfiguration") + .annotate(OpenApi.Summary, "Get the fiat payout configuration for a customer") + .annotate(OpenApi.Description, "Retrieve the fiat payout configuration for the given customer ID. This configuration determines which payout method (bridge, developer, payment_provider, or customer) is used for each currency and payment rail combination.\n\nThe configuration is a nested hash structure where:\n- Top-level keys are currency codes (e.g., \"usd\", \"eur\", \"brl\", \"mxn\")\n- Second-level keys are payment rail codes (e.g., \"wire\", \"ach\", \"sepa\", \"pix\", \"spei\")\n- Values are payout names: `bridge`, `developer`, `payment_provider`, or `customer`\n\nCurrently, only the following values are supported for the payout method:\n- usd.wire: `developer`, `customer`\n- usd.ach: `bridge`\n- eur.sepa: `bridge`\n- brl.pix: `payment_provider`\n- mxn.spei: `payment_provider`"), + HttpApiEndpoint.patch("patchCustomersByCustomerIDFiatPayoutConfiguration", "/customers/:customerID/fiat_payout_configuration", { params: PatchCustomersByCustomerIDFiatPayoutConfigurationPathParams, payload: PatchCustomersByCustomerIDFiatPayoutConfigurationRequestJson, success: PatchCustomersByCustomerIDFiatPayoutConfiguration200, error: [PatchCustomersByCustomerIDFiatPayoutConfiguration400.pipe(HttpApiSchema.status(400)), PatchCustomersByCustomerIDFiatPayoutConfiguration401.pipe(HttpApiSchema.status(401)), PatchCustomersByCustomerIDFiatPayoutConfiguration403.pipe(HttpApiSchema.status(403)), PatchCustomersByCustomerIDFiatPayoutConfiguration404.pipe(HttpApiSchema.status(404)), PatchCustomersByCustomerIDFiatPayoutConfiguration500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "patchCustomersByCustomerIDFiatPayoutConfiguration") + .annotate(OpenApi.Summary, "Update the fiat payout configuration for a customer") + .annotate(OpenApi.Description, "Update the fiat payout configuration for the given customer ID. This configuration determines which payout method (bridge, developer, payment_provider, or customer) is used for each currency and payment rail combination.\n\nThe configuration is a nested hash structure where:\n- Top-level keys are currency codes (e.g., \"usd\", \"eur\", \"brl\", \"mxn\")\n- Second-level keys are payment rail codes (e.g., \"wire\", \"ach\", \"sepa\", \"pix\", \"spei\")\n- Values are payout names: `bridge`, `developer`, `payment_provider`, or `customer`\n\nCurrently, only the following values are supported for the payout method:\n- usd.wire: `developer`, `customer`\n- usd.ach: `bridge`\n- eur.sepa: `bridge`\n- brl.pix: `payment_provider`\n- mxn.spei: `payment_provider`\n\nOnly the currency/payment rail combinations provided will be updated. Other existing configurations will remain unchanged.")) {} + +class PlaidGroup extends HttpApiGroup.make("plaid") + .add(HttpApiEndpoint.post("postCustomersByCustomerIDPlaidLinkRequests", "/customers/:customerID/plaid_link_requests", { params: PostCustomersByCustomerIDPlaidLinkRequestsPathParams, headers: PostCustomersByCustomerIDPlaidLinkRequestsHeaders, success: PostCustomersByCustomerIDPlaidLinkRequests201.pipe(HttpApiSchema.status(201)), error: [PostCustomersByCustomerIDPlaidLinkRequests400.pipe(HttpApiSchema.status(400)), PostCustomersByCustomerIDPlaidLinkRequests401.pipe(HttpApiSchema.status(401)), PostCustomersByCustomerIDPlaidLinkRequests500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "postCustomersByCustomerIDPlaidLinkRequests") + .annotate(OpenApi.Summary, "Generate a Plaid Link token for a customer"), + HttpApiEndpoint.post("postPlaidExchangePublicTokenByLinkToken", "/plaid_exchange_public_token/:link_token", { params: PostPlaidExchangePublicTokenByLinkTokenPathParams, payload: PostPlaidExchangePublicTokenByLinkTokenRequestJson, success: PostPlaidExchangePublicTokenByLinkToken201.pipe(HttpApiSchema.status(201)), error: [PostPlaidExchangePublicTokenByLinkToken400.pipe(HttpApiSchema.status(400)), PostPlaidExchangePublicTokenByLinkToken401.pipe(HttpApiSchema.status(401)), PostPlaidExchangePublicTokenByLinkToken500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "postPlaidExchangePublicTokenByLinkToken") + .annotate(OpenApi.Summary, "Exchange Plaid public token for an access token")) {} + +class TransfersGroup extends HttpApiGroup.make("transfers") + .add(HttpApiEndpoint.get("getTransfers", "/transfers", { query: GetTransfersQuery, success: GetTransfers200, error: [GetTransfers401.pipe(HttpApiSchema.status(401)), GetTransfers500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getTransfers") + .annotate(OpenApi.Summary, "Get all transfers"), + HttpApiEndpoint.post("postTransfers", "/transfers", { headers: PostTransfersHeaders, payload: PostTransfersRequestJson, success: PostTransfers201.pipe(HttpApiSchema.status(201)), error: [PostTransfers400.pipe(HttpApiSchema.status(400)), PostTransfers401.pipe(HttpApiSchema.status(401)), PostTransfers403.pipe(HttpApiSchema.status(403)), PostTransfers409.pipe(HttpApiSchema.status(409)), PostTransfers500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "postTransfers") + .annotate(OpenApi.Summary, "Create a transfer") + .annotate(OpenApi.Description, "Create a transfer.\n\nIf this transfer cannot be created because the funding source is temporarily busy processing another update, this endpoint may return `409 resource_state_conflict`.\nThis is a transient, retryable response. You may safely retry the same request with the same `Idempotency-Key`."), + HttpApiEndpoint.get("getTransfersPending", "/transfers/pending", { query: GetTransfersPendingQuery, success: GetTransfersPending200, error: [GetTransfersPending400.pipe(HttpApiSchema.status(400)), GetTransfersPending401.pipe(HttpApiSchema.status(401)), GetTransfersPending500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getTransfersPending") + .annotate(OpenApi.Summary, "List transfers with pending USDT trades") + .annotate(OpenApi.Description, "Returns transfers that have a stuck USDT-to-USD trade awaiting execution. Results are sorted by creation time (newest first) and paginated.\n\nUse `POST /transfers/{transferID}/execute` to force-execute a pending trade at the current market rate."), + HttpApiEndpoint.get("getTransfersByTransferID", "/transfers/:transferID", { params: GetTransfersByTransferIDPathParams, success: GetTransfersByTransferID200, error: [GetTransfersByTransferID401.pipe(HttpApiSchema.status(401)), GetTransfersByTransferID404.pipe(HttpApiSchema.status(404)), GetTransfersByTransferID500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getTransfersByTransferID") + .annotate(OpenApi.Summary, "Get a transfer") + .annotate(OpenApi.Description, "Retrieve a transfer object from the passed in transfer ID"), + HttpApiEndpoint.put("putTransfersByTransferID", "/transfers/:transferID", { params: PutTransfersByTransferIDPathParams, payload: PutTransfersByTransferIDRequestJson, success: PutTransfersByTransferID201.pipe(HttpApiSchema.status(201)), error: [PutTransfersByTransferID400.pipe(HttpApiSchema.status(400)), PutTransfersByTransferID401.pipe(HttpApiSchema.status(401)), PutTransfersByTransferID403.pipe(HttpApiSchema.status(403)), PutTransfersByTransferID500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "putTransfersByTransferID") + .annotate(OpenApi.Summary, "Update a transfer") + .annotate(OpenApi.Description, "Update a transfer that was previously created. Must be in the awaiting_funds state."), + HttpApiEndpoint.delete("deleteTransfersByTransferID", "/transfers/:transferID", { params: DeleteTransfersByTransferIDPathParams, success: HttpApiSchema.Empty(200), error: [DeleteTransfersByTransferID401.pipe(HttpApiSchema.status(401)), DeleteTransfersByTransferID404.pipe(HttpApiSchema.status(404)), DeleteTransfersByTransferID500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "deleteTransfersByTransferID") + .annotate(OpenApi.Summary, "Delete a transfer") + .annotate(OpenApi.Description, "Delete a transfer that was previously created. Must be in the awaiting_funds state."), + HttpApiEndpoint.post("postTransfersByTransferIDExecute", "/transfers/:transferID/execute", { params: PostTransfersByTransferIDExecutePathParams, headers: PostTransfersByTransferIDExecuteHeaders, success: PostTransfersByTransferIDExecute200, error: [PostTransfersByTransferIDExecute400.pipe(HttpApiSchema.status(400)), PostTransfersByTransferIDExecute401.pipe(HttpApiSchema.status(401)), PostTransfersByTransferIDExecute404.pipe(HttpApiSchema.status(404)), PostTransfersByTransferIDExecute500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "postTransfersByTransferIDExecute") + .annotate(OpenApi.Summary, "Execute a pending USDT trade on a transfer") + .annotate(OpenApi.Description, "Force-executes a stuck USDT-to-USD trade at the current market rate. The transfer must have a pending trade (i.e. appear in `GET /transfers/pending`).\n\nAfter execution, the transfer will continue processing normally with the executed market rate."), + HttpApiEndpoint.get("getTransfersStaticTemplates", "/transfers/static_templates", { query: GetTransfersStaticTemplatesQuery, success: GetTransfersStaticTemplates200, error: [GetTransfersStaticTemplates401.pipe(HttpApiSchema.status(401)), GetTransfersStaticTemplates500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getTransfersStaticTemplates") + .annotate(OpenApi.Summary, "Get all static templates")) {} + +class PrefundedAccountsGroup extends HttpApiGroup.make("prefundedAccounts") + .add(HttpApiEndpoint.get("getPrefundedAccounts", "/prefunded_accounts", { success: GetPrefundedAccounts200, error: [GetPrefundedAccounts401.pipe(HttpApiSchema.status(401)), GetPrefundedAccounts404.pipe(HttpApiSchema.status(404)), GetPrefundedAccounts500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getPrefundedAccounts") + .annotate(OpenApi.Summary, "Get a list of all Prefunded Account") + .annotate(OpenApi.Description, "Retrieve a all Prefunded Accounts"), + HttpApiEndpoint.get("getPrefundedAccountsByPrefundedAccountID", "/prefunded_accounts/:prefundedAccountID", { params: GetPrefundedAccountsByPrefundedAccountIDPathParams, success: GetPrefundedAccountsByPrefundedAccountID200, error: [GetPrefundedAccountsByPrefundedAccountID401.pipe(HttpApiSchema.status(401)), GetPrefundedAccountsByPrefundedAccountID404.pipe(HttpApiSchema.status(404)), GetPrefundedAccountsByPrefundedAccountID500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getPrefundedAccountsByPrefundedAccountID") + .annotate(OpenApi.Summary, "Get details for a specific Prefunded Account") + .annotate(OpenApi.Description, "Retrieve a Prefunded Account"), + HttpApiEndpoint.get("getPrefundedAccountsByPrefundedAccountIDHistory", "/prefunded_accounts/:prefundedAccountID/history", { params: GetPrefundedAccountsByPrefundedAccountIDHistoryPathParams, query: GetPrefundedAccountsByPrefundedAccountIDHistoryQuery, success: GetPrefundedAccountsByPrefundedAccountIDHistory200, error: [GetPrefundedAccountsByPrefundedAccountIDHistory401.pipe(HttpApiSchema.status(401)), GetPrefundedAccountsByPrefundedAccountIDHistory404.pipe(HttpApiSchema.status(404)), GetPrefundedAccountsByPrefundedAccountIDHistory500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getPrefundedAccountsByPrefundedAccountIDHistory") + .annotate(OpenApi.Summary, "Get funding history of a Prefunded Account") + .annotate(OpenApi.Description, "Retrieve the funding events and returns for a Prefunded Account")) {} + +class LiquidationAddressesGroup extends HttpApiGroup.make("liquidationAddresses") + .add(HttpApiEndpoint.get("getCustomersByCustomerIDLiquidationAddresses", "/customers/:customerID/liquidation_addresses", { params: GetCustomersByCustomerIDLiquidationAddressesPathParams, query: GetCustomersByCustomerIDLiquidationAddressesQuery, success: GetCustomersByCustomerIDLiquidationAddresses200, error: [GetCustomersByCustomerIDLiquidationAddresses400.pipe(HttpApiSchema.status(400)), GetCustomersByCustomerIDLiquidationAddresses401.pipe(HttpApiSchema.status(401)), GetCustomersByCustomerIDLiquidationAddresses500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getCustomersByCustomerIDLiquidationAddresses") + .annotate(OpenApi.Summary, "Get all Liquidation Addresses for a customer") + .annotate(OpenApi.Description, "Get Liquidation Addresses"), + HttpApiEndpoint.post("postCustomersByCustomerIDLiquidationAddresses", "/customers/:customerID/liquidation_addresses", { params: PostCustomersByCustomerIDLiquidationAddressesPathParams, headers: PostCustomersByCustomerIDLiquidationAddressesHeaders, payload: PostCustomersByCustomerIDLiquidationAddressesRequestJson, success: PostCustomersByCustomerIDLiquidationAddresses201.pipe(HttpApiSchema.status(201)), error: [PostCustomersByCustomerIDLiquidationAddresses400.pipe(HttpApiSchema.status(400)), PostCustomersByCustomerIDLiquidationAddresses401.pipe(HttpApiSchema.status(401)), PostCustomersByCustomerIDLiquidationAddresses500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "postCustomersByCustomerIDLiquidationAddresses") + .annotate(OpenApi.Summary, "Create a Liquidation Address"), + HttpApiEndpoint.get("getLiquidationAddresses", "/liquidation_addresses", { query: GetLiquidationAddressesQuery, success: GetLiquidationAddresses200, error: [GetLiquidationAddresses400.pipe(HttpApiSchema.status(400)), GetLiquidationAddresses401.pipe(HttpApiSchema.status(401)), GetLiquidationAddresses500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getLiquidationAddresses") + .annotate(OpenApi.Summary, "Get all Liquidation Addresses") + .annotate(OpenApi.Description, "Get Liquidation Addresses"), + HttpApiEndpoint.get("getCustomersByCustomerIDLiquidationAddressesByLiquidationAddressID", "/customers/:customerID/liquidation_addresses/:liquidationAddressID", { params: GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDPathParams, success: GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressID200, error: [GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressID400.pipe(HttpApiSchema.status(400)), GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressID401.pipe(HttpApiSchema.status(401)), GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressID404.pipe(HttpApiSchema.status(404)), GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressID500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getCustomersByCustomerIDLiquidationAddressesByLiquidationAddressID") + .annotate(OpenApi.Summary, "Get a Liquidation Address") + .annotate(OpenApi.Description, "Retrieve a Liquidation Address for the specified Liquidation Address ID"), + HttpApiEndpoint.put("putCustomersByCustomerIDLiquidationAddressesByLiquidationAddressID", "/customers/:customerID/liquidation_addresses/:liquidationAddressID", { params: PutCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDPathParams, payload: PutCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDRequestJson, success: PutCustomersByCustomerIDLiquidationAddressesByLiquidationAddressID200, error: [PutCustomersByCustomerIDLiquidationAddressesByLiquidationAddressID400.pipe(HttpApiSchema.status(400)), PutCustomersByCustomerIDLiquidationAddressesByLiquidationAddressID401.pipe(HttpApiSchema.status(401)), PutCustomersByCustomerIDLiquidationAddressesByLiquidationAddressID500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "putCustomersByCustomerIDLiquidationAddressesByLiquidationAddressID") + .annotate(OpenApi.Summary, "Update a Liquidation Address") + .annotate(OpenApi.Description, "Update a Liquidation Address for the specified liquidation address ID. Fields (`external_account_id`, `custom_developer_fee_percent`, `destination`) can be updated independently and are not all required."), + HttpApiEndpoint.get("getCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDDrains", "/customers/:customerID/liquidation_addresses/:liquidationAddressID/drains", { params: GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDDrainsPathParams, query: GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDDrainsQuery, success: GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDDrains200, error: [GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDDrains400.pipe(HttpApiSchema.status(400)), GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDDrains401.pipe(HttpApiSchema.status(401)), GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDDrains500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDDrains") + .annotate(OpenApi.Summary, "Get drain history of a Liquidation Address") + .annotate(OpenApi.Description, "Get drain history of a Liquidation Address"), + HttpApiEndpoint.post("postCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDDrainsByDrainIDExecute", "/customers/:customerID/liquidation_addresses/:liquidationAddressID/drains/:drainID/execute", { params: PostCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDDrainsByDrainIDExecutePathParams, headers: PostCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDDrainsByDrainIDExecuteHeaders, success: PostCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDDrainsByDrainIDExecute200, error: [PostCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDDrainsByDrainIDExecute400.pipe(HttpApiSchema.status(400)), PostCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDDrainsByDrainIDExecute401.pipe(HttpApiSchema.status(401)), PostCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDDrainsByDrainIDExecute404.pipe(HttpApiSchema.status(404)), PostCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDDrainsByDrainIDExecute500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "postCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDDrainsByDrainIDExecute") + .annotate(OpenApi.Summary, "Execute a pending USDT trade on a drain") + .annotate(OpenApi.Description, "Force-executes a stuck USDT-to-USD trade at the current market rate. The drain must have a pending trade (i.e. appear in `GET /liquidation_addresses/drains/pending`).\n\nAfter execution, the drain will continue processing normally with the executed market rate."), + HttpApiEndpoint.get("getCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDBalances", "/customers/:customerID/liquidation_addresses/:liquidationAddressID/balances", { params: GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDBalancesPathParams, success: GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDBalances200, error: [GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDBalances400.pipe(HttpApiSchema.status(400)), GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDBalances401.pipe(HttpApiSchema.status(401)), GetCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDBalances500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getCustomersByCustomerIDLiquidationAddressesByLiquidationAddressIDBalances") + .annotate(OpenApi.Summary, "[Deprecated upstream] Get the balance of a Liquidation Address (deprecated)") + .annotate(OpenApi.Description, "Get the balance of a Liquidation Address. Note that most Liquidation Addresses no longer hold a balance. To check recent activity on a Liquidation Address, use the `/customers/{customerID}/liquidation_addresses/{liquidationAddressID}/drains` endpoint.") + .annotate(OpenApi.Deprecated, true), + HttpApiEndpoint.get("getLiquidationAddressesDrains", "/liquidation_addresses/drains", { query: GetLiquidationAddressesDrainsQuery, success: GetLiquidationAddressesDrains200, error: [GetLiquidationAddressesDrains400.pipe(HttpApiSchema.status(400)), GetLiquidationAddressesDrains401.pipe(HttpApiSchema.status(401)), GetLiquidationAddressesDrains500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getLiquidationAddressesDrains") + .annotate(OpenApi.Summary, "Liquidation Address Activity Across All Customers") + .annotate(OpenApi.Description, "History of activity across all customers and Liquidation Addresses"), + HttpApiEndpoint.get("getLiquidationAddressesDrainsPending", "/liquidation_addresses/drains/pending", { query: GetLiquidationAddressesDrainsPendingQuery, success: GetLiquidationAddressesDrainsPending200, error: [GetLiquidationAddressesDrainsPending400.pipe(HttpApiSchema.status(400)), GetLiquidationAddressesDrainsPending401.pipe(HttpApiSchema.status(401)), GetLiquidationAddressesDrainsPending500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getLiquidationAddressesDrainsPending") + .annotate(OpenApi.Summary, "List drains with pending USDT trades") + .annotate(OpenApi.Description, "Returns drains that have a stuck USDT-to-USD trade awaiting execution. Results are sorted by creation time (newest first) and paginated.\n\nUse `POST /customers/{customerID}/liquidation_addresses/{liquidationAddressID}/drains/{drainID}/execute` to force-execute a pending trade at the current market rate.")) {} + +class VirtualAccountsGroup extends HttpApiGroup.make("virtualAccounts") + .add(HttpApiEndpoint.get("getCustomersByCustomerIDVirtualAccounts", "/customers/:customerID/virtual_accounts", { params: GetCustomersByCustomerIDVirtualAccountsPathParams, query: GetCustomersByCustomerIDVirtualAccountsQuery, success: GetCustomersByCustomerIDVirtualAccounts200 }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getCustomersByCustomerIDVirtualAccounts") + .annotate(OpenApi.Summary, "List Virtual Accounts by Customer") + .annotate(OpenApi.Description, "List all Virtual Account objects for a customer"), + HttpApiEndpoint.post("postCustomersByCustomerIDVirtualAccounts", "/customers/:customerID/virtual_accounts", { params: PostCustomersByCustomerIDVirtualAccountsPathParams, headers: PostCustomersByCustomerIDVirtualAccountsHeaders, payload: PostCustomersByCustomerIDVirtualAccountsRequestJson, success: PostCustomersByCustomerIDVirtualAccounts200 }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "postCustomersByCustomerIDVirtualAccounts") + .annotate(OpenApi.Summary, "Create a Virtual Account") + .annotate(OpenApi.Description, "Create a Virtual Account or Virtual IBAN for the specified customer"), + HttpApiEndpoint.get("getCustomersByCustomerIDVirtualAccountsByVirtualAccountID", "/customers/:customerID/virtual_accounts/:virtualAccountID", { params: GetCustomersByCustomerIDVirtualAccountsByVirtualAccountIDPathParams, success: GetCustomersByCustomerIDVirtualAccountsByVirtualAccountID200 }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getCustomersByCustomerIDVirtualAccountsByVirtualAccountID") + .annotate(OpenApi.Summary, "Get a Virtual Account") + .annotate(OpenApi.Description, "Retrieve the Virtual Account object from the passed ID"), + HttpApiEndpoint.put("putCustomersByCustomerIDVirtualAccountsByVirtualAccountID", "/customers/:customerID/virtual_accounts/:virtualAccountID", { params: PutCustomersByCustomerIDVirtualAccountsByVirtualAccountIDPathParams, payload: PutCustomersByCustomerIDVirtualAccountsByVirtualAccountIDRequestJson, success: PutCustomersByCustomerIDVirtualAccountsByVirtualAccountID200 }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "putCustomersByCustomerIDVirtualAccountsByVirtualAccountID") + .annotate(OpenApi.Summary, "Update a Virtual Account") + .annotate(OpenApi.Description, "Update instructions for an existing Virtual Account"), + HttpApiEndpoint.post("postCustomersByCustomerIDVirtualAccountsByVirtualAccountIDDeactivate", "/customers/:customerID/virtual_accounts/:virtualAccountID/deactivate", { params: PostCustomersByCustomerIDVirtualAccountsByVirtualAccountIDDeactivatePathParams, headers: PostCustomersByCustomerIDVirtualAccountsByVirtualAccountIDDeactivateHeaders, success: PostCustomersByCustomerIDVirtualAccountsByVirtualAccountIDDeactivate200 }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "postCustomersByCustomerIDVirtualAccountsByVirtualAccountIDDeactivate") + .annotate(OpenApi.Summary, "Deactivate a Virtual Account") + .annotate(OpenApi.Description, "Deactivate a Virtual Account to prevent it from acceping new incoming transactions"), + HttpApiEndpoint.post("postCustomersByCustomerIDVirtualAccountsByVirtualAccountIDReactivate", "/customers/:customerID/virtual_accounts/:virtualAccountID/reactivate", { params: PostCustomersByCustomerIDVirtualAccountsByVirtualAccountIDReactivatePathParams, headers: PostCustomersByCustomerIDVirtualAccountsByVirtualAccountIDReactivateHeaders, success: PostCustomersByCustomerIDVirtualAccountsByVirtualAccountIDReactivate200 }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "postCustomersByCustomerIDVirtualAccountsByVirtualAccountIDReactivate") + .annotate(OpenApi.Summary, "Reactivate a Virtual Account") + .annotate(OpenApi.Description, "Reactivate a previously deactivated Virtual Account"), + HttpApiEndpoint.get("getCustomersByCustomerIDVirtualAccountsByVirtualAccountIDHistory", "/customers/:customerID/virtual_accounts/:virtualAccountID/history", { params: GetCustomersByCustomerIDVirtualAccountsByVirtualAccountIDHistoryPathParams, query: GetCustomersByCustomerIDVirtualAccountsByVirtualAccountIDHistoryQuery, success: GetCustomersByCustomerIDVirtualAccountsByVirtualAccountIDHistory200 }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getCustomersByCustomerIDVirtualAccountsByVirtualAccountIDHistory") + .annotate(OpenApi.Summary, "Virtual Account Activity") + .annotate(OpenApi.Description, "History of activity for a Virtual Account"), + HttpApiEndpoint.get("getVirtualAccounts", "/virtual_accounts", { query: GetVirtualAccountsQuery, success: GetVirtualAccounts200 }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getVirtualAccounts") + .annotate(OpenApi.Summary, "List Virtual Accounts") + .annotate(OpenApi.Description, "List all Virtual Account objects"), + HttpApiEndpoint.get("getVirtualAccountsHistory", "/virtual_accounts/history", { query: GetVirtualAccountsHistoryQuery, success: GetVirtualAccountsHistory200 }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getVirtualAccountsHistory") + .annotate(OpenApi.Summary, "Virtual Account Activity Across All Customers") + .annotate(OpenApi.Description, "History of activity across all customers and Virtual Accounts")) {} + +class StaticMemosGroup extends HttpApiGroup.make("staticMemos") + .add(HttpApiEndpoint.get("getStaticMemos", "/static_memos", { query: GetStaticMemosQuery, success: GetStaticMemos200 }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getStaticMemos") + .annotate(OpenApi.Summary, "List Static Memos") + .annotate(OpenApi.Description, "List all Static Memo objects"), + HttpApiEndpoint.get("getCustomersByCustomerIDStaticMemos", "/customers/:customerID/static_memos", { params: GetCustomersByCustomerIDStaticMemosPathParams, query: GetCustomersByCustomerIDStaticMemosQuery, success: GetCustomersByCustomerIDStaticMemos200 }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getCustomersByCustomerIDStaticMemos") + .annotate(OpenApi.Summary, "List Static Memos for Customer") + .annotate(OpenApi.Description, "List all Static Memo objects for a customer"), + HttpApiEndpoint.post("postCustomersByCustomerIDStaticMemos", "/customers/:customerID/static_memos", { params: PostCustomersByCustomerIDStaticMemosPathParams, headers: PostCustomersByCustomerIDStaticMemosHeaders, payload: PostCustomersByCustomerIDStaticMemosRequestJson, success: PostCustomersByCustomerIDStaticMemos200 }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "postCustomersByCustomerIDStaticMemos") + .annotate(OpenApi.Summary, "Create a Static Memo") + .annotate(OpenApi.Description, "Create a Static Memo for the specified customer"), + HttpApiEndpoint.get("getCustomersByCustomerIDStaticMemosByStaticMemoID", "/customers/:customerID/static_memos/:staticMemoID", { params: GetCustomersByCustomerIDStaticMemosByStaticMemoIDPathParams, success: GetCustomersByCustomerIDStaticMemosByStaticMemoID200 }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getCustomersByCustomerIDStaticMemosByStaticMemoID") + .annotate(OpenApi.Summary, "Get a Static Memo") + .annotate(OpenApi.Description, "Retrieve the Static Memo object from the passed ID"), + HttpApiEndpoint.put("putCustomersByCustomerIDStaticMemosByStaticMemoID", "/customers/:customerID/static_memos/:staticMemoID", { params: PutCustomersByCustomerIDStaticMemosByStaticMemoIDPathParams, payload: PutCustomersByCustomerIDStaticMemosByStaticMemoIDRequestJson, success: PutCustomersByCustomerIDStaticMemosByStaticMemoID200 }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "putCustomersByCustomerIDStaticMemosByStaticMemoID") + .annotate(OpenApi.Summary, "Update a Static Memo") + .annotate(OpenApi.Description, "Update instructions for an existing Static Memo"), + HttpApiEndpoint.get("getCustomersByCustomerIDStaticMemosByStaticMemoIDHistory", "/customers/:customerID/static_memos/:staticMemoID/history", { params: GetCustomersByCustomerIDStaticMemosByStaticMemoIDHistoryPathParams, query: GetCustomersByCustomerIDStaticMemosByStaticMemoIDHistoryQuery, success: GetCustomersByCustomerIDStaticMemosByStaticMemoIDHistory200 }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getCustomersByCustomerIDStaticMemosByStaticMemoIDHistory") + .annotate(OpenApi.Summary, "Static Memo Activity") + .annotate(OpenApi.Description, "History of activity for a Static Memo"), + HttpApiEndpoint.get("getStaticMemosHistory", "/static_memos/history", { query: GetStaticMemosHistoryQuery, success: GetStaticMemosHistory200 }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getStaticMemosHistory") + .annotate(OpenApi.Summary, "Static Memo Activity Across All Customers") + .annotate(OpenApi.Description, "History of activity across all customers and Virtual Accounts")) {} + +class CardsGroup extends HttpApiGroup.make("cards") + .add(HttpApiEndpoint.post("postCustomersByCustomerIDCardAccountsByCardAccountIDPin", "/customers/:customerID/card_accounts/:cardAccountID/pin", { params: PostCustomersByCustomerIDCardAccountsByCardAccountIDPinPathParams, headers: PostCustomersByCustomerIDCardAccountsByCardAccountIDPinHeaders, success: PostCustomersByCustomerIDCardAccountsByCardAccountIDPin200, error: [PostCustomersByCustomerIDCardAccountsByCardAccountIDPin400.pipe(HttpApiSchema.status(400)), PostCustomersByCustomerIDCardAccountsByCardAccountIDPin401.pipe(HttpApiSchema.status(401)), PostCustomersByCustomerIDCardAccountsByCardAccountIDPin500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "postCustomersByCustomerIDCardAccountsByCardAccountIDPin") + .annotate(OpenApi.Summary, "Create Card PIN Update URL") + .annotate(OpenApi.Description, "Generates a URL that can be used to render a secure frame to update the PIN for a card account. The URL is single-use and time-limited."), + HttpApiEndpoint.post("postCustomersByCustomerIDCardAccountsByCardAccountIDEphemeralKeys", "/customers/:customerID/card_accounts/:cardAccountID/ephemeral_keys", { params: PostCustomersByCustomerIDCardAccountsByCardAccountIDEphemeralKeysPathParams, headers: PostCustomersByCustomerIDCardAccountsByCardAccountIDEphemeralKeysHeaders, payload: [PostCustomersByCustomerIDCardAccountsByCardAccountIDEphemeralKeysRequestJson, HttpApiSchema.NoContent], success: PostCustomersByCustomerIDCardAccountsByCardAccountIDEphemeralKeys200, error: [PostCustomersByCustomerIDCardAccountsByCardAccountIDEphemeralKeys400.pipe(HttpApiSchema.status(400)), PostCustomersByCustomerIDCardAccountsByCardAccountIDEphemeralKeys401.pipe(HttpApiSchema.status(401)), PostCustomersByCustomerIDCardAccountsByCardAccountIDEphemeralKeys500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "postCustomersByCustomerIDCardAccountsByCardAccountIDEphemeralKeys") + .annotate(OpenApi.Summary, "Generate an Ephemeral Key to Reveal Card Details") + .annotate(OpenApi.Description, "Generates a one-time ephemeral key that can be used to reveal card details. Please see the integration guide on [safely revealing card details](https://apidocs.bridge.xyz/docs/safely-reveal-card-details-to-customers) for more information."), + HttpApiEndpoint.get("getDeveloperCardsSummary", "/developer/cards/summary", { query: GetDeveloperCardsSummaryQuery, success: GetDeveloperCardsSummary200, error: [GetDeveloperCardsSummary400.pipe(HttpApiSchema.status(400)), GetDeveloperCardsSummary401.pipe(HttpApiSchema.status(401)), GetDeveloperCardsSummary500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getDeveloperCardsSummary") + .annotate(OpenApi.Summary, "Get a summary of your card program") + .annotate(OpenApi.Description, "Get a summary of your card program, optionally for a specific period."), + HttpApiEndpoint.get("getDeveloperCardsDesigns", "/developer/cards/designs", { success: GetDeveloperCardsDesigns200, error: [GetDeveloperCardsDesigns400.pipe(HttpApiSchema.status(400)), GetDeveloperCardsDesigns401.pipe(HttpApiSchema.status(401)), GetDeveloperCardsDesigns500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getDeveloperCardsDesigns") + .annotate(OpenApi.Summary, "Get a listing of your card program's card designs") + .annotate(OpenApi.Description, "Get a listing of the designs that you can use to issue a card with."), + HttpApiEndpoint.get("getCustomersByCustomerIDCardAccountsByCardAccountID", "/customers/:customerID/card_accounts/:cardAccountID", { params: GetCustomersByCustomerIDCardAccountsByCardAccountIDPathParams, success: GetCustomersByCustomerIDCardAccountsByCardAccountID200, error: [GetCustomersByCustomerIDCardAccountsByCardAccountID401.pipe(HttpApiSchema.status(401)), GetCustomersByCustomerIDCardAccountsByCardAccountID500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getCustomersByCustomerIDCardAccountsByCardAccountID") + .annotate(OpenApi.Summary, "Retrieve a card account") + .annotate(OpenApi.Description, "Retrieve the card account with the specified ID"), + HttpApiEndpoint.put("putCustomersByCustomerIDCardAccountsByCardAccountID", "/customers/:customerID/card_accounts/:cardAccountID", { params: PutCustomersByCustomerIDCardAccountsByCardAccountIDPathParams, payload: PutCustomersByCustomerIDCardAccountsByCardAccountIDRequestJson, success: PutCustomersByCustomerIDCardAccountsByCardAccountID200, error: [PutCustomersByCustomerIDCardAccountsByCardAccountID400.pipe(HttpApiSchema.status(400)), PutCustomersByCustomerIDCardAccountsByCardAccountID401.pipe(HttpApiSchema.status(401)), PutCustomersByCustomerIDCardAccountsByCardAccountID500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "putCustomersByCustomerIDCardAccountsByCardAccountID") + .annotate(OpenApi.Summary, "Update a card account") + .annotate(OpenApi.Description, "Update a card account. Supports changing the settlement currency or closing a card account by setting the status to \"inactive\". Closing permanently cancels all associated cards and is irreversible."), + HttpApiEndpoint.get("getCustomersByCustomerIDCardAccounts", "/customers/:customerID/card_accounts", { params: GetCustomersByCustomerIDCardAccountsPathParams, success: GetCustomersByCustomerIDCardAccounts200, error: [GetCustomersByCustomerIDCardAccounts401.pipe(HttpApiSchema.status(401)), GetCustomersByCustomerIDCardAccounts500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getCustomersByCustomerIDCardAccounts") + .annotate(OpenApi.Summary, "Get all card accounts") + .annotate(OpenApi.Description, "Retrieve all card accounts for a customer. Currently, only one account is supported. An empty array will be returned if no card has been provisioned"), + HttpApiEndpoint.post("postCustomersByCustomerIDCardAccounts", "/customers/:customerID/card_accounts", { params: PostCustomersByCustomerIDCardAccountsPathParams, headers: PostCustomersByCustomerIDCardAccountsHeaders, payload: PostCustomersByCustomerIDCardAccountsRequestJson, success: PostCustomersByCustomerIDCardAccounts201.pipe(HttpApiSchema.status(201)), error: [PostCustomersByCustomerIDCardAccounts400.pipe(HttpApiSchema.status(400)), PostCustomersByCustomerIDCardAccounts401.pipe(HttpApiSchema.status(401)), PostCustomersByCustomerIDCardAccounts500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "postCustomersByCustomerIDCardAccounts") + .annotate(OpenApi.Summary, "[Deprecated upstream] Provision a card account") + .annotate(OpenApi.Description, "Provision a card account. NOTE: the legacy Bridge Cards API is deprecated, and stablecoin card issuing capabilities are now natively integrated into Stripe Issuing. Please see [this guide](https://apidocs.bridge.xyz/platform/cards/overview/stripe-issuing) for more details on how to enable your account for Stripe Issuing.") + .annotate(OpenApi.Deprecated, true), + HttpApiEndpoint.post("postCustomersByCustomerIDCardAccountsByCardAccountIDFreeze", "/customers/:customerID/card_accounts/:cardAccountID/freeze", { params: PostCustomersByCustomerIDCardAccountsByCardAccountIDFreezePathParams, headers: PostCustomersByCustomerIDCardAccountsByCardAccountIDFreezeHeaders, payload: [PostCustomersByCustomerIDCardAccountsByCardAccountIDFreezeRequestJson, HttpApiSchema.NoContent], success: PostCustomersByCustomerIDCardAccountsByCardAccountIDFreeze200, error: [PostCustomersByCustomerIDCardAccountsByCardAccountIDFreeze400.pipe(HttpApiSchema.status(400)), PostCustomersByCustomerIDCardAccountsByCardAccountIDFreeze401.pipe(HttpApiSchema.status(401)), PostCustomersByCustomerIDCardAccountsByCardAccountIDFreeze500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "postCustomersByCustomerIDCardAccountsByCardAccountIDFreeze") + .annotate(OpenApi.Summary, "Place a freeze on the card account") + .annotate(OpenApi.Description, "Place a freeze on the card account"), + HttpApiEndpoint.post("postCustomersByCustomerIDCardAccountsByCardAccountIDUnfreeze", "/customers/:customerID/card_accounts/:cardAccountID/unfreeze", { params: PostCustomersByCustomerIDCardAccountsByCardAccountIDUnfreezePathParams, headers: PostCustomersByCustomerIDCardAccountsByCardAccountIDUnfreezeHeaders, payload: [PostCustomersByCustomerIDCardAccountsByCardAccountIDUnfreezeRequestJson, HttpApiSchema.NoContent], success: PostCustomersByCustomerIDCardAccountsByCardAccountIDUnfreeze200, error: [PostCustomersByCustomerIDCardAccountsByCardAccountIDUnfreeze400.pipe(HttpApiSchema.status(400)), PostCustomersByCustomerIDCardAccountsByCardAccountIDUnfreeze401.pipe(HttpApiSchema.status(401)), PostCustomersByCustomerIDCardAccountsByCardAccountIDUnfreeze500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "postCustomersByCustomerIDCardAccountsByCardAccountIDUnfreeze") + .annotate(OpenApi.Summary, "Unfreeze the card account") + .annotate(OpenApi.Description, "Remove the freeze on the card account placed by the specified initiator"), + HttpApiEndpoint.post("postCustomersByCustomerIDCardAccountsByCardAccountIDCreateMobileWalletProvisioningRequest", "/customers/:customerID/card_accounts/:cardAccountID/create_mobile_wallet_provisioning_request", { params: PostCustomersByCustomerIDCardAccountsByCardAccountIDCreateMobileWalletProvisioningRequestPathParams, headers: PostCustomersByCustomerIDCardAccountsByCardAccountIDCreateMobileWalletProvisioningRequestHeaders, payload: [PostCustomersByCustomerIDCardAccountsByCardAccountIDCreateMobileWalletProvisioningRequestRequestJson, HttpApiSchema.NoContent], success: PostCustomersByCustomerIDCardAccountsByCardAccountIDCreateMobileWalletProvisioningRequest200, error: [PostCustomersByCustomerIDCardAccountsByCardAccountIDCreateMobileWalletProvisioningRequest400.pipe(HttpApiSchema.status(400)), PostCustomersByCustomerIDCardAccountsByCardAccountIDCreateMobileWalletProvisioningRequest401.pipe(HttpApiSchema.status(401)), PostCustomersByCustomerIDCardAccountsByCardAccountIDCreateMobileWalletProvisioningRequest500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "postCustomersByCustomerIDCardAccountsByCardAccountIDCreateMobileWalletProvisioningRequest") + .annotate(OpenApi.Summary, "Create a mobile wallet push provisioning request") + .annotate(OpenApi.Description, "Create a request to push-provision a virtual card to a mobile wallet. This endpoint is part of a multiple-step integration that must be completed with each mobile wallet partner"), + HttpApiEndpoint.get("getCustomersByCustomerIDCardAccountsByCardAccountIDAuthorizations", "/customers/:customerID/card_accounts/:cardAccountID/authorizations", { params: GetCustomersByCustomerIDCardAccountsByCardAccountIDAuthorizationsPathParams, query: GetCustomersByCustomerIDCardAccountsByCardAccountIDAuthorizationsQuery, success: GetCustomersByCustomerIDCardAccountsByCardAccountIDAuthorizations200, error: [GetCustomersByCustomerIDCardAccountsByCardAccountIDAuthorizations401.pipe(HttpApiSchema.status(401)), GetCustomersByCustomerIDCardAccountsByCardAccountIDAuthorizations500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getCustomersByCustomerIDCardAccountsByCardAccountIDAuthorizations") + .annotate(OpenApi.Summary, "Retrieve pending card authorizations") + .annotate(OpenApi.Description, "Retrieve pending card authorizations.\nNote: this endpoint is not paginated"), + HttpApiEndpoint.get("getCustomersByCustomerIDCardAccountsByCardAccountIDTransactions", "/customers/:customerID/card_accounts/:cardAccountID/transactions", { params: GetCustomersByCustomerIDCardAccountsByCardAccountIDTransactionsPathParams, query: GetCustomersByCustomerIDCardAccountsByCardAccountIDTransactionsQuery, success: GetCustomersByCustomerIDCardAccountsByCardAccountIDTransactions200, error: [GetCustomersByCustomerIDCardAccountsByCardAccountIDTransactions401.pipe(HttpApiSchema.status(401)), GetCustomersByCustomerIDCardAccountsByCardAccountIDTransactions500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getCustomersByCustomerIDCardAccountsByCardAccountIDTransactions") + .annotate(OpenApi.Summary, "Retrieve card transactions") + .annotate(OpenApi.Description, "Retrieve completed card transactions and card-related crypto transaction activities"), + HttpApiEndpoint.get("getCustomersByCustomerIDCardAccountsByCardAccountIDTransactionsByTransactionID", "/customers/:customerID/card_accounts/:cardAccountID/transactions/:transactionID", { params: GetCustomersByCustomerIDCardAccountsByCardAccountIDTransactionsByTransactionIDPathParams, success: GetCustomersByCustomerIDCardAccountsByCardAccountIDTransactionsByTransactionID200, error: [GetCustomersByCustomerIDCardAccountsByCardAccountIDTransactionsByTransactionID401.pipe(HttpApiSchema.status(401)), GetCustomersByCustomerIDCardAccountsByCardAccountIDTransactionsByTransactionID500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getCustomersByCustomerIDCardAccountsByCardAccountIDTransactionsByTransactionID") + .annotate(OpenApi.Summary, "Retrieve a card transaction") + .annotate(OpenApi.Description, "Retrieve a card transaction with the specified ID"), + HttpApiEndpoint.get("getCustomersByCustomerIDCardAccountsByCardAccountIDAuthControls", "/customers/:customerID/card_accounts/:cardAccountID/auth_controls", { params: GetCustomersByCustomerIDCardAccountsByCardAccountIDAuthControlsPathParams, success: GetCustomersByCustomerIDCardAccountsByCardAccountIDAuthControls200, error: [GetCustomersByCustomerIDCardAccountsByCardAccountIDAuthControls401.pipe(HttpApiSchema.status(401)), GetCustomersByCustomerIDCardAccountsByCardAccountIDAuthControls500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getCustomersByCustomerIDCardAccountsByCardAccountIDAuthControls") + .annotate(OpenApi.Summary, "Retrieve authorization controls") + .annotate(OpenApi.Description, "Retrieve the applicable spend limits for the given card account"), + HttpApiEndpoint.post("postCustomersByCustomerIDCardAccountsByCardAccountIDDepositAddresses", "/customers/:customerID/card_accounts/:cardAccountID/deposit_addresses", { params: PostCustomersByCustomerIDCardAccountsByCardAccountIDDepositAddressesPathParams, headers: PostCustomersByCustomerIDCardAccountsByCardAccountIDDepositAddressesHeaders, payload: PostCustomersByCustomerIDCardAccountsByCardAccountIDDepositAddressesRequestJson, success: PostCustomersByCustomerIDCardAccountsByCardAccountIDDepositAddresses200, error: [PostCustomersByCustomerIDCardAccountsByCardAccountIDDepositAddresses400.pipe(HttpApiSchema.status(400)), PostCustomersByCustomerIDCardAccountsByCardAccountIDDepositAddresses401.pipe(HttpApiSchema.status(401)), PostCustomersByCustomerIDCardAccountsByCardAccountIDDepositAddresses500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "postCustomersByCustomerIDCardAccountsByCardAccountIDDepositAddresses") + .annotate(OpenApi.Summary, "Provision an additional top-up deposit address for the card account") + .annotate(OpenApi.Description, "Provision an additional deposit address for the card account, to allow topping up the card from multiple chains. This is only applicable to Bridge-custodied top-up card accounts. These additional deposit addresses will also be shown in the `additional_funding_instructions` field when fetching the card account details afterwards."), + HttpApiEndpoint.get("getCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawals", "/customers/:customerID/card_accounts/:cardAccountID/withdrawals", { params: GetCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawalsPathParams, query: GetCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawalsQuery, success: GetCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawals200, error: [GetCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawals401.pipe(HttpApiSchema.status(401)), GetCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawals500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawals") + .annotate(OpenApi.Summary, "Retrieve the withdrawal history of funds") + .annotate(OpenApi.Description, "Retrieve the withdrawal history of funds, applicable to top-up accounts only"), + HttpApiEndpoint.post("postCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawals", "/customers/:customerID/card_accounts/:cardAccountID/withdrawals", { params: PostCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawalsPathParams, headers: PostCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawalsHeaders, payload: PostCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawalsRequestJson, success: PostCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawals201.pipe(HttpApiSchema.status(201)), error: [PostCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawals400.pipe(HttpApiSchema.status(400)), PostCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawals401.pipe(HttpApiSchema.status(401)), PostCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawals500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "postCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawals") + .annotate(OpenApi.Summary, "Create a funds withdrawal request") + .annotate(OpenApi.Description, "Request a funds withdrawal from the card account, applicable to top-up accounts only. For Bridge wallets, create a [transfer](/api-reference/transfers/create-a-transfer) from the Bridge wallet."), + HttpApiEndpoint.get("getCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawalsByCardWithdrawalID", "/customers/:customerID/card_accounts/:cardAccountID/withdrawals/:cardWithdrawalID", { params: GetCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawalsByCardWithdrawalIDPathParams, success: GetCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawalsByCardWithdrawalID200, error: [GetCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawalsByCardWithdrawalID401.pipe(HttpApiSchema.status(401)), GetCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawalsByCardWithdrawalID500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getCustomersByCustomerIDCardAccountsByCardAccountIDWithdrawalsByCardWithdrawalID") + .annotate(OpenApi.Summary, "Retrieve a card withdrawal") + .annotate(OpenApi.Description, "Retrieve a card withdrawal with the specified ID, applicable to top-up accounts only"), + HttpApiEndpoint.post("postCustomersByCustomerIDCardAccountsByCardAccountIDStatementsPeriodPdf", "/customers/:customerID/card_accounts/:cardAccountID/statements/:period.pdf", { params: PostCustomersByCustomerIDCardAccountsByCardAccountIDStatementsPeriodPdfPathParams, success: PostCustomersByCustomerIDCardAccountsByCardAccountIDStatementsPeriodPdf200ApplicationPdf.pipe(HttpApiSchema.asUint8Array({ contentType: "application/pdf" })), error: [PostCustomersByCustomerIDCardAccountsByCardAccountIDStatementsPeriodPdf400.pipe(HttpApiSchema.status(400)), PostCustomersByCustomerIDCardAccountsByCardAccountIDStatementsPeriodPdf401.pipe(HttpApiSchema.status(401)), PostCustomersByCustomerIDCardAccountsByCardAccountIDStatementsPeriodPdf500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "postCustomersByCustomerIDCardAccountsByCardAccountIDStatementsPeriodPdf") + .annotate(OpenApi.Summary, "Generate a card account statement") + .annotate(OpenApi.Description, "Generate a card account statement for the specified period"), + HttpApiEndpoint.post("postCardholdersByCardholderIDCardsByCardIDStatementsPeriodPdf", "/cardholders/:cardholderID/cards/:cardID/statements/:period.pdf", { params: PostCardholdersByCardholderIDCardsByCardIDStatementsPeriodPdfPathParams, success: PostCardholdersByCardholderIDCardsByCardIDStatementsPeriodPdf200ApplicationPdf.pipe(HttpApiSchema.asUint8Array({ contentType: "application/pdf" })), error: [PostCardholdersByCardholderIDCardsByCardIDStatementsPeriodPdf400.pipe(HttpApiSchema.status(400)), PostCardholdersByCardholderIDCardsByCardIDStatementsPeriodPdf401.pipe(HttpApiSchema.status(401)), PostCardholdersByCardholderIDCardsByCardIDStatementsPeriodPdf500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "postCardholdersByCardholderIDCardsByCardIDStatementsPeriodPdf") + .annotate(OpenApi.Summary, "Generate a card statement using Stripe IDs") + .annotate(OpenApi.Description, "Generate a card account statement for the specified period, using Stripe cardholder and card IDs instead of Bridge internal IDs")) {} + +class BatchSettlementsGroup extends HttpApiGroup.make("batchSettlements") + .add(HttpApiEndpoint.post("postCustomersByCustomerIDBatchSettlementSchedules", "/customers/:customerID/batch_settlement_schedules", { params: PostCustomersByCustomerIDBatchSettlementSchedulesPathParams, headers: PostCustomersByCustomerIDBatchSettlementSchedulesHeaders, payload: PostCustomersByCustomerIDBatchSettlementSchedulesRequestJson, success: PostCustomersByCustomerIDBatchSettlementSchedules200, error: [PostCustomersByCustomerIDBatchSettlementSchedules400.pipe(HttpApiSchema.status(400)), PostCustomersByCustomerIDBatchSettlementSchedules401.pipe(HttpApiSchema.status(401)), PostCustomersByCustomerIDBatchSettlementSchedules500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "postCustomersByCustomerIDBatchSettlementSchedules") + .annotate(OpenApi.Summary, "[Deprecated upstream] Create a Batch Settlement Schedule") + .annotate(OpenApi.Description, "Creates a Batch Settlement Schedule that can be used as the destination of a liquidation address.") + .annotate(OpenApi.Deprecated, true)) {} + +class DevelopersGroup extends HttpApiGroup.make("developers") + .add(HttpApiEndpoint.get("getDeveloperFees", "/developer/fees", { success: GetDeveloperFees200, error: [GetDeveloperFees400.pipe(HttpApiSchema.status(400)), GetDeveloperFees401.pipe(HttpApiSchema.status(401)), GetDeveloperFees500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getDeveloperFees") + .annotate(OpenApi.Summary, "Get the configured fees") + .annotate(OpenApi.Description, "Get fees that have been configured for supported products."), + HttpApiEndpoint.post("postDeveloperFees", "/developer/fees", { headers: PostDeveloperFeesHeaders, payload: PostDeveloperFeesRequestJson, success: PostDeveloperFees200, error: [PostDeveloperFees400.pipe(HttpApiSchema.status(400)), PostDeveloperFees401.pipe(HttpApiSchema.status(401)), PostDeveloperFees500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "postDeveloperFees") + .annotate(OpenApi.Summary, "Update the configured fees") + .annotate(OpenApi.Description, "Update fees for supported products."), + HttpApiEndpoint.get("getDeveloperFeeExternalAccount", "/developer/fee_external_account", { success: GetDeveloperFeeExternalAccount200, error: [GetDeveloperFeeExternalAccount400.pipe(HttpApiSchema.status(400)), GetDeveloperFeeExternalAccount401.pipe(HttpApiSchema.status(401)), GetDeveloperFeeExternalAccount500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getDeveloperFeeExternalAccount") + .annotate(OpenApi.Summary, "Get the configured fee External Account") + .annotate(OpenApi.Description, "Get the configured fee External Account."), + HttpApiEndpoint.post("postDeveloperFeeExternalAccount", "/developer/fee_external_account", { headers: PostDeveloperFeeExternalAccountHeaders, payload: PostDeveloperFeeExternalAccountRequestJson, success: PostDeveloperFeeExternalAccount201.pipe(HttpApiSchema.status(201)), error: [PostDeveloperFeeExternalAccount400.pipe(HttpApiSchema.status(400)), PostDeveloperFeeExternalAccount401.pipe(HttpApiSchema.status(401)), PostDeveloperFeeExternalAccount500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "postDeveloperFeeExternalAccount") + .annotate(OpenApi.Summary, "Configure a fee External Account") + .annotate(OpenApi.Description, "Configure a fee External Account.")) {} + +class ApiKeysGroup extends HttpApiGroup.make("apiKeys") + .add(HttpApiEndpoint.post("postApiKeys", "/api_keys", { payload: PostApiKeysRequestJson, success: PostApiKeys201.pipe(HttpApiSchema.status(201)), error: [PostApiKeys400.pipe(HttpApiSchema.status(400)), PostApiKeys401.pipe(HttpApiSchema.status(401)), PostApiKeys500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "postApiKeys") + .annotate(OpenApi.Summary, "Create a scoped API key") + .annotate(OpenApi.Description, "Create a new API key restricted to a subset of scopes. The returned `value` is the only\nopportunity to retrieve the plaintext secret — store it securely. This endpoint does not\naccept an `Idempotency-Key` header; each call creates a new key.\n\nCallers may only grant scopes they themselves hold (scope subsetting). Unrestricted keys\nmay create scoped keys; scoped keys need the `api_key:create` scope. Up to 500 scoped\nkeys may exist per developer."), + HttpApiEndpoint.get("getApiKeysWhoami", "/api_keys/whoami", { success: GetApiKeysWhoami200, error: [GetApiKeysWhoami401.pipe(HttpApiSchema.status(401)), GetApiKeysWhoami500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getApiKeysWhoami") + .annotate(OpenApi.Summary, "Describe the calling API key") + .annotate(OpenApi.Description, "Return metadata about the API key authenticating this request, including its scopes. The plaintext secret is never returned.")) {} + +class KycLinksGroup extends HttpApiGroup.make("kycLinks") + .add(HttpApiEndpoint.get("getKycLinks", "/kyc_links", { query: GetKycLinksQuery, success: GetKycLinks200, error: [GetKycLinks401.pipe(HttpApiSchema.status(401)), GetKycLinks404.pipe(HttpApiSchema.status(404)), GetKycLinks500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getKycLinks") + .annotate(OpenApi.Summary, "Get all KYC links.") + .annotate(OpenApi.Description, "Retrieve the full list of kyc links."), + HttpApiEndpoint.post("postKycLinks", "/kyc_links", { headers: PostKycLinksHeaders, payload: PostKycLinksRequestJson, success: PostKycLinks200, error: [PostKycLinks400.pipe(HttpApiSchema.status(400)), PostKycLinks401.pipe(HttpApiSchema.status(401)), PostKycLinks500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "postKycLinks") + .annotate(OpenApi.Summary, "Generate the Links needs to complete KYC for an individual or business"), + HttpApiEndpoint.get("getKycLinksByKycLinkID", "/kyc_links/:kycLinkID", { params: GetKycLinksByKycLinkIDPathParams, success: GetKycLinksByKycLinkID200, error: [GetKycLinksByKycLinkID401.pipe(HttpApiSchema.status(401)), GetKycLinksByKycLinkID404.pipe(HttpApiSchema.status(404)), GetKycLinksByKycLinkID500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getKycLinksByKycLinkID") + .annotate(OpenApi.Summary, "Check the status of a KYC link") + .annotate(OpenApi.Description, "Retrieve the status of a KYC request from the passed in KYC link id")) {} + +class RfisGroup extends HttpApiGroup.make("rfis") + .add(HttpApiEndpoint.get("getRfis", "/rfis", { query: GetRfisQuery, success: GetRfis200, error: [GetRfis400.pipe(HttpApiSchema.status(400)), GetRfis401.pipe(HttpApiSchema.status(401)), GetRfis500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getRfis") + .annotate(OpenApi.Summary, "Get all RFIs") + .annotate(OpenApi.Description, "Retrieve a list of requests for information (RFIs) raised against your developer or customer accounts"), + HttpApiEndpoint.get("getRfisByRfiID", "/rfis/:rfiID", { params: GetRfisByRfiIDPathParams, success: GetRfisByRfiID200, error: [GetRfisByRfiID401.pipe(HttpApiSchema.status(401)), GetRfisByRfiID404.pipe(HttpApiSchema.status(404)), GetRfisByRfiID500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getRfisByRfiID") + .annotate(OpenApi.Summary, "Get an RFI") + .annotate(OpenApi.Description, "Retrieve a single request for information (RFI) by id")) {} + +class FundsRequestsGroup extends HttpApiGroup.make("fundsRequests") + .add(HttpApiEndpoint.get("getFundsRequests", "/funds_requests", { query: GetFundsRequestsQuery, success: GetFundsRequests200 }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getFundsRequests") + .annotate(OpenApi.Summary, "Get all funds requests") + .annotate(OpenApi.Description, "Retrieve a list of all funds requests submitted by partnered banks and financial institutions")) {} + +class WebhooksGroup extends HttpApiGroup.make("webhooks") + .add(HttpApiEndpoint.get("getWebhooks", "/webhooks", { success: GetWebhooks200, error: [GetWebhooks401.pipe(HttpApiSchema.status(401)), GetWebhooks500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getWebhooks") + .annotate(OpenApi.Summary, "Get all webhook endpoints") + .annotate(OpenApi.Description, "Get the full list of active and disabled webhook endpoints configured on Bridge"), + HttpApiEndpoint.post("postWebhooks", "/webhooks", { headers: PostWebhooksHeaders, payload: PostWebhooksRequestJson, success: PostWebhooks201.pipe(HttpApiSchema.status(201)), error: [PostWebhooks400.pipe(HttpApiSchema.status(400)), PostWebhooks401.pipe(HttpApiSchema.status(401)), PostWebhooks500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "postWebhooks") + .annotate(OpenApi.Summary, "Create a webhook endpoint") + .annotate(OpenApi.Description, "Create a new webhook endpoint to receive events from Bridge. Webhook endpoints begin in a disabled state and can be enabled with a PUT request. A maximum of 5 webhooks can be active or disabled at one time. Webhook endpoints can be created in Sandbox, but no webhook events will be sent."), + HttpApiEndpoint.put("putWebhooksByWebhookID", "/webhooks/:webhookID", { params: PutWebhooksByWebhookIDPathParams, payload: PutWebhooksByWebhookIDRequestJson, success: PutWebhooksByWebhookID200, error: [PutWebhooksByWebhookID401.pipe(HttpApiSchema.status(401)), PutWebhooksByWebhookID404.pipe(HttpApiSchema.status(404)), PutWebhooksByWebhookID500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "putWebhooksByWebhookID") + .annotate(OpenApi.Summary, "Update a webhook") + .annotate(OpenApi.Description, "Update the specified webhook object"), + HttpApiEndpoint.delete("deleteWebhooksByWebhookID", "/webhooks/:webhookID", { params: DeleteWebhooksByWebhookIDPathParams, success: DeleteWebhooksByWebhookID200, error: [DeleteWebhooksByWebhookID401.pipe(HttpApiSchema.status(401)), DeleteWebhooksByWebhookID404.pipe(HttpApiSchema.status(404)), DeleteWebhooksByWebhookID500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "deleteWebhooksByWebhookID") + .annotate(OpenApi.Summary, "Delete a webhook") + .annotate(OpenApi.Description, "Delete the specified webhook object. This webhook will no longer be accessible via API."), + HttpApiEndpoint.get("getWebhooksByWebhookIDEvents", "/webhooks/:webhookID/events", { params: GetWebhooksByWebhookIDEventsPathParams, success: GetWebhooksByWebhookIDEvents200, error: [GetWebhooksByWebhookIDEvents401.pipe(HttpApiSchema.status(401)), GetWebhooksByWebhookIDEvents500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getWebhooksByWebhookIDEvents") + .annotate(OpenApi.Summary, "List upcoming events") + .annotate(OpenApi.Description, "List the next 10 events that will be delivered to the specified webhook."), + HttpApiEndpoint.get("getWebhooksByWebhookIDLogs", "/webhooks/:webhookID/logs", { params: GetWebhooksByWebhookIDLogsPathParams, success: GetWebhooksByWebhookIDLogs200, error: [GetWebhooksByWebhookIDLogs401.pipe(HttpApiSchema.status(401)), GetWebhooksByWebhookIDLogs500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getWebhooksByWebhookIDLogs") + .annotate(OpenApi.Summary, "View logs") + .annotate(OpenApi.Description, "Display the most recent logs for deliveries to the specified webhook."), + HttpApiEndpoint.post("postWebhooksByWebhookIDSend", "/webhooks/:webhookID/send", { params: PostWebhooksByWebhookIDSendPathParams, headers: PostWebhooksByWebhookIDSendHeaders, payload: PostWebhooksByWebhookIDSendRequestJson, success: PostWebhooksByWebhookIDSend200, error: [PostWebhooksByWebhookIDSend401.pipe(HttpApiSchema.status(401)), PostWebhooksByWebhookIDSend500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "postWebhooksByWebhookIDSend") + .annotate(OpenApi.Summary, "Send event") + .annotate(OpenApi.Description, "Send an event to the specified webhook endpoint. This will not effect other events in the delivery queue. This operation is possible for both active and disabled webhook endpoints."), + HttpApiEndpoint.get("getWebhookEvents", "/webhook_events", { query: GetWebhookEventsQuery, success: GetWebhookEvents200, error: [GetWebhookEvents400.pipe(HttpApiSchema.status(400)), GetWebhookEvents401.pipe(HttpApiSchema.status(401)), GetWebhookEvents500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getWebhookEvents") + .annotate(OpenApi.Summary, "List webhook events") + .annotate(OpenApi.Description, "List all webhook events for your account. Events are ordered by their event_sequence in ascending order. Results are limited to the events created in last 90 days.")) {} + +class AssociatedPersonsGroup extends HttpApiGroup.make("associatedPersons") + .add(HttpApiEndpoint.get("getAssociatedPersonsByAssociatedPersonID", "/associated_persons/:associatedPersonID", { params: GetAssociatedPersonsByAssociatedPersonIDPathParams, success: GetAssociatedPersonsByAssociatedPersonID200, error: [GetAssociatedPersonsByAssociatedPersonID401.pipe(HttpApiSchema.status(401)), GetAssociatedPersonsByAssociatedPersonID404.pipe(HttpApiSchema.status(404)), GetAssociatedPersonsByAssociatedPersonID500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getAssociatedPersonsByAssociatedPersonID") + .annotate(OpenApi.Summary, "Get a single associated person") + .annotate(OpenApi.Description, "Retrieve an associated person by ID"), + HttpApiEndpoint.put("putAssociatedPersonsByAssociatedPersonID", "/associated_persons/:associatedPersonID", { params: PutAssociatedPersonsByAssociatedPersonIDPathParams, payload: PutAssociatedPersonsByAssociatedPersonIDRequestJson, success: PutAssociatedPersonsByAssociatedPersonID200, error: [PutAssociatedPersonsByAssociatedPersonID400.pipe(HttpApiSchema.status(400)), PutAssociatedPersonsByAssociatedPersonID401.pipe(HttpApiSchema.status(401)), PutAssociatedPersonsByAssociatedPersonID404.pipe(HttpApiSchema.status(404)), PutAssociatedPersonsByAssociatedPersonID500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "putAssociatedPersonsByAssociatedPersonID") + .annotate(OpenApi.Summary, "Update a single associated person"), + HttpApiEndpoint.delete("deleteAssociatedPersonsByAssociatedPersonID", "/associated_persons/:associatedPersonID", { params: DeleteAssociatedPersonsByAssociatedPersonIDPathParams, success: DeleteAssociatedPersonsByAssociatedPersonID200, error: [DeleteAssociatedPersonsByAssociatedPersonID401.pipe(HttpApiSchema.status(401)), DeleteAssociatedPersonsByAssociatedPersonID404.pipe(HttpApiSchema.status(404)), DeleteAssociatedPersonsByAssociatedPersonID500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "deleteAssociatedPersonsByAssociatedPersonID") + .annotate(OpenApi.Summary, "Delete a single associated person") + .annotate(OpenApi.Description, "Delete an associated person by ID")) {} + +class TravelRuleGroup extends HttpApiGroup.make("travelRule") + .add(HttpApiEndpoint.post("postTravelRuleDataById", "/travel_rule_data/:id", { params: PostTravelRuleDataByIdPathParams, headers: PostTravelRuleDataByIdHeaders, payload: PostTravelRuleDataByIdRequestJson, success: PostTravelRuleDataById200, error: [PostTravelRuleDataById400.pipe(HttpApiSchema.status(400)), PostTravelRuleDataById401.pipe(HttpApiSchema.status(401)), PostTravelRuleDataById404.pipe(HttpApiSchema.status(404)), PostTravelRuleDataById500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "postTravelRuleDataById") + .annotate(OpenApi.Summary, "Submit travel rule data.") + .annotate(OpenApi.Description, "Use this endpoint to submit originator, beneficiary, and transfer purpose data for travel rule compliance.")) {} + +class ExchangeRatesGroup extends HttpApiGroup.make("exchangeRates") + .add(HttpApiEndpoint.get("getExchangeRates", "/exchange_rates", { query: GetExchangeRatesQuery, success: GetExchangeRates200 }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getExchangeRates") + .annotate(OpenApi.Summary, "Get current exchange rate between two currencies.") + .annotate(OpenApi.Description, "Returns the current exchange rate from the \"from\" currency to the \"to\" currency.\nThe exchange rate is updated roughly every 30s. Note that as of this writing,\nBridge does not offer a \"quote\" by which a user can lock in a rate for a given\namount of time. This is provided only as a courtesy to estimate what you are\nlikely to get in a subsequent transfer request that involves currency exchange.\n\nAs of March 2026, we support:\n - `USD <> BRL`\n - `USD <> COP`\n - `USD <> EUR`\n - `USD <> GBP`\n - `USD <> MXN`\n - `USD <> USDT`")) {} + +class ListsGroup extends HttpApiGroup.make("lists") + .add(HttpApiEndpoint.get("getListsOccupationCodes", "/lists/occupation_codes", { success: GetListsOccupationCodes200 }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getListsOccupationCodes") + .annotate(OpenApi.Summary, "Get occupation codes") + .annotate(OpenApi.Description, "Provide this list of occupation codes to your users as possible answers to the Source of Funds section in the KYC flow. The returned list will resemble the list of occupation codes found [here](https://apidocs.bridge.xyz/page/sof-eu-most-recent-occupation-list)."), + HttpApiEndpoint.get("getListsCountries", "/lists/countries", { success: GetListsCountries200 }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getListsCountries") + .annotate(OpenApi.Summary, "Get countries") + .annotate(OpenApi.Description, "Returns a list of countries and subdivisions recognized by Bridge. Inclusion in this list does not guarantee Bridge product support for any country or subdivision.")) {} + +class CryptoReturnPoliciesGroup extends HttpApiGroup.make("cryptoReturnPolicies") + .add(HttpApiEndpoint.get("getCryptoReturnPolicies", "/crypto_return_policies", { success: GetCryptoReturnPolicies200, error: [GetCryptoReturnPolicies401.pipe(HttpApiSchema.status(401)), GetCryptoReturnPolicies500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getCryptoReturnPolicies") + .annotate(OpenApi.Summary, "Get all crypto return policies") + .annotate(OpenApi.Description, "Retrieve all crypto return policies for the authenticated developer"), + HttpApiEndpoint.post("postCryptoReturnPolicies", "/crypto_return_policies", { headers: PostCryptoReturnPoliciesHeaders, payload: PostCryptoReturnPoliciesRequestJson, success: PostCryptoReturnPolicies201.pipe(HttpApiSchema.status(201)), error: [PostCryptoReturnPolicies400.pipe(HttpApiSchema.status(400)), PostCryptoReturnPolicies401.pipe(HttpApiSchema.status(401)), PostCryptoReturnPolicies500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "postCryptoReturnPolicies") + .annotate(OpenApi.Summary, "Create a new crypto return policy"), + HttpApiEndpoint.put("putCryptoReturnPoliciesByPolicyID", "/crypto_return_policies/:policyID", { params: PutCryptoReturnPoliciesByPolicyIDPathParams, payload: PutCryptoReturnPoliciesByPolicyIDRequestJson, success: PutCryptoReturnPoliciesByPolicyID200, error: [PutCryptoReturnPoliciesByPolicyID400.pipe(HttpApiSchema.status(400)), PutCryptoReturnPoliciesByPolicyID401.pipe(HttpApiSchema.status(401)), PutCryptoReturnPoliciesByPolicyID404.pipe(HttpApiSchema.status(404)), PutCryptoReturnPoliciesByPolicyID500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "putCryptoReturnPoliciesByPolicyID") + .annotate(OpenApi.Summary, "Update an existing crypto return policy"), + HttpApiEndpoint.delete("deleteCryptoReturnPoliciesByPolicyID", "/crypto_return_policies/:policyID", { params: DeleteCryptoReturnPoliciesByPolicyIDPathParams, success: DeleteCryptoReturnPoliciesByPolicyID200, error: [DeleteCryptoReturnPoliciesByPolicyID401.pipe(HttpApiSchema.status(401)), DeleteCryptoReturnPoliciesByPolicyID404.pipe(HttpApiSchema.status(404)), DeleteCryptoReturnPoliciesByPolicyID500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "deleteCryptoReturnPoliciesByPolicyID") + .annotate(OpenApi.Summary, "Delete a single crypto return policy object") + .annotate(OpenApi.Description, "Delete a crypto return policy object from the passed in crypto return policy ID")) {} + +class DeveloperFeesGroup extends HttpApiGroup.make("developerFees") + .add(HttpApiEndpoint.get("getFeesConfigurations", "/fees/configurations", { query: GetFeesConfigurationsQuery, success: GetFeesConfigurations200, error: [GetFeesConfigurations400.pipe(HttpApiSchema.status(400)), GetFeesConfigurations401.pipe(HttpApiSchema.status(401)), GetFeesConfigurations500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getFeesConfigurations") + .annotate(OpenApi.Summary, "[Upstream x-hidden] Get all Developer Fee Configs") + .annotate(OpenApi.Description, "Beta: available by request only. Contact Bridge to enable this feature for your developer account.\n\nList Developer Fee Configs for the current developer."), + HttpApiEndpoint.post("postFeesConfigurations", "/fees/configurations", { headers: PostFeesConfigurationsHeaders, payload: PostFeesConfigurationsRequestJson, success: PostFeesConfigurations201.pipe(HttpApiSchema.status(201)), error: [PostFeesConfigurations400.pipe(HttpApiSchema.status(400)), PostFeesConfigurations401.pipe(HttpApiSchema.status(401)), PostFeesConfigurations500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "postFeesConfigurations") + .annotate(OpenApi.Summary, "[Upstream x-hidden] Create a Developer Fee Config") + .annotate(OpenApi.Description, "Beta: available by request only. Contact Bridge to enable this feature for your developer account.\n\nCreate a Developer Fee Config."), + HttpApiEndpoint.get("getFeesConfigurationsByDeveloperFeeConfigID", "/fees/configurations/:developerFeeConfigID", { params: GetFeesConfigurationsByDeveloperFeeConfigIDPathParams, success: GetFeesConfigurationsByDeveloperFeeConfigID200, error: [GetFeesConfigurationsByDeveloperFeeConfigID400.pipe(HttpApiSchema.status(400)), GetFeesConfigurationsByDeveloperFeeConfigID401.pipe(HttpApiSchema.status(401)), GetFeesConfigurationsByDeveloperFeeConfigID404.pipe(HttpApiSchema.status(404)), GetFeesConfigurationsByDeveloperFeeConfigID500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getFeesConfigurationsByDeveloperFeeConfigID") + .annotate(OpenApi.Summary, "[Upstream x-hidden] Get a Developer Fee Config") + .annotate(OpenApi.Description, "Beta: available by request only. Contact Bridge to enable this feature for your developer account.\n\nRetrieve a Developer Fee Config for the specified Developer Fee Config ID."), + HttpApiEndpoint.put("putFeesConfigurationsByDeveloperFeeConfigID", "/fees/configurations/:developerFeeConfigID", { params: PutFeesConfigurationsByDeveloperFeeConfigIDPathParams, payload: PutFeesConfigurationsByDeveloperFeeConfigIDRequestJson, success: PutFeesConfigurationsByDeveloperFeeConfigID200, error: [PutFeesConfigurationsByDeveloperFeeConfigID400.pipe(HttpApiSchema.status(400)), PutFeesConfigurationsByDeveloperFeeConfigID401.pipe(HttpApiSchema.status(401)), PutFeesConfigurationsByDeveloperFeeConfigID404.pipe(HttpApiSchema.status(404)), PutFeesConfigurationsByDeveloperFeeConfigID500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "putFeesConfigurationsByDeveloperFeeConfigID") + .annotate(OpenApi.Summary, "[Upstream x-hidden] Update a Developer Fee Config") + .annotate(OpenApi.Description, "Beta: available by request only. Contact Bridge to enable this feature for your developer account.\n\nFully replaces the Developer Fee Config for the specified Developer Fee Config ID.")) {} + +class RewardsGroup extends HttpApiGroup.make("rewards") + .add(HttpApiEndpoint.get("getRewardsByCurrency", "/rewards/:currency", { params: GetRewardsByCurrencyPathParams, success: GetRewardsByCurrency200, error: [GetRewardsByCurrency401.pipe(HttpApiSchema.status(401)), GetRewardsByCurrency500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getRewardsByCurrency") + .annotate(OpenApi.Summary, "Get a summary of all rewards for a given stablecoin") + .annotate(OpenApi.Description, "Get a summary of all rewards for a given stablecoin"), + HttpApiEndpoint.get("getRewardsByCurrencyHistory", "/rewards/:currency/history", { params: GetRewardsByCurrencyHistoryPathParams, query: GetRewardsByCurrencyHistoryQuery, success: GetRewardsByCurrencyHistory200, error: [GetRewardsByCurrencyHistory400.pipe(HttpApiSchema.status(400)), GetRewardsByCurrencyHistory401.pipe(HttpApiSchema.status(401)), GetRewardsByCurrencyHistory500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getRewardsByCurrencyHistory") + .annotate(OpenApi.Summary, "Get daily reward history for a stablecoin") + .annotate(OpenApi.Description, "Returns paginated daily reward records with per-provider breakdowns, AUM, fees, and distribution status. Data is calculated with a t-2 business day lag; the most recent available record corresponds to two business days prior to the current date."), + HttpApiEndpoint.get("getRewardsByCurrencyCustomerByCustomerID", "/rewards/:currency/customer/:customerID", { params: GetRewardsByCurrencyCustomerByCustomerIDPathParams, success: GetRewardsByCurrencyCustomerByCustomerID200, error: [GetRewardsByCurrencyCustomerByCustomerID401.pipe(HttpApiSchema.status(401)), GetRewardsByCurrencyCustomerByCustomerID500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getRewardsByCurrencyCustomerByCustomerID") + .annotate(OpenApi.Summary, "Get a summary of a customer's rewards") + .annotate(OpenApi.Description, "Get a summary of a customer's rewards"), + HttpApiEndpoint.get("getRewardsByCurrencyCustomerByCustomerIDHistory", "/rewards/:currency/customer/:customerID/history", { params: GetRewardsByCurrencyCustomerByCustomerIDHistoryPathParams, success: GetRewardsByCurrencyCustomerByCustomerIDHistory200, error: [GetRewardsByCurrencyCustomerByCustomerIDHistory401.pipe(HttpApiSchema.status(401)), GetRewardsByCurrencyCustomerByCustomerIDHistory500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "getRewardsByCurrencyCustomerByCustomerIDHistory") + .annotate(OpenApi.Summary, "Get a history of a customer's rewards") + .annotate(OpenApi.Description, "Get a history of a customer's rewards. Data is calculated with a t-2 business day lag; the most recent available record corresponds to two business days prior to the current date.")) {} + +class SandboxGroup extends HttpApiGroup.make("sandbox") + .add(HttpApiEndpoint.post("postCustomersByCustomerIDSimulateKycApproval", "/customers/:customerID/simulate_kyc_approval", { params: PostCustomersByCustomerIDSimulateKycApprovalPathParams, headers: PostCustomersByCustomerIDSimulateKycApprovalHeaders, success: PostCustomersByCustomerIDSimulateKycApproval200, error: [PostCustomersByCustomerIDSimulateKycApproval401.pipe(HttpApiSchema.status(401)), PostCustomersByCustomerIDSimulateKycApproval404.pipe(HttpApiSchema.status(404)), PostCustomersByCustomerIDSimulateKycApproval500] }) + .middleware(ApiKeySecurityMiddleware) + .annotate(OpenApi.Identifier, "postCustomersByCustomerIDSimulateKycApproval") + .annotate(OpenApi.Summary, "Simulate KYC approval (sandbox only)") + .annotate(OpenApi.Description, "Simulates a KYC/KYB approval for a customer in the sandbox environment. This endpoint is not available in production.\n\nMimics what happens when a customer completes identity verification through the KYC provider in production:\n- Sets the customer's KYC status to `approved`\n- Populates required entity data (name, address, date of birth) using any data already on the customer, falling back to sandbox defaults\n- Approves any pending endorsements, enabling the customer to initiate transfers\n\nUseful for testing the full customer lifecycle without integrating with a real KYC provider.")) {} + +export class BridgeApi extends HttpApi.make("BridgeApi") + .annotate(OpenApi.Title, "Bridge API") + .annotate(OpenApi.Version, "1") + .annotate(OpenApi.Description, "APIs to move into, out of, and between any form of a dollar") + .annotate(OpenApi.Servers, [{"url":"https://api.bridge.xyz/v0","description":"The base path for all resources"}]) + .add(BridgeWalletsGroup, CustomersGroup, ExternalAccountsGroup, FiatPayoutConfigurationGroup, PlaidGroup, TransfersGroup, PrefundedAccountsGroup, LiquidationAddressesGroup, VirtualAccountsGroup, StaticMemosGroup, CardsGroup, BatchSettlementsGroup, DevelopersGroup, ApiKeysGroup, KycLinksGroup, RfisGroup, FundsRequestsGroup, WebhooksGroup, AssociatedPersonsGroup, TravelRuleGroup, ExchangeRatesGroup, ListsGroup, CryptoReturnPoliciesGroup, DeveloperFeesGroup, RewardsGroup, SandboxGroup) {} diff --git a/packages/bridge/src/index.ts b/packages/bridge/src/index.ts new file mode 100644 index 0000000..478ea7d --- /dev/null +++ b/packages/bridge/src/index.ts @@ -0,0 +1,25 @@ +// Copyright (c) Miso Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +export { + Bridge, + bridgeFetchLayer, + bridgeLayer, + makeBridgeClient, + type BridgeClient +} from "./Bridge.js" +export { + productionBaseUrl, + sandboxBaseUrl, + type BridgeConfig, + type BridgeEnvironment, + type ResolvedBridgeConfig +} from "./Config.js" +export { + BridgeConfigurationError, + BridgeHttpError, + BridgeSchemaError, + BridgeTimeoutError, + BridgeTransportError, + type BridgeClientError +} from "./Errors.js" diff --git a/packages/bridge/src/internal/http.ts b/packages/bridge/src/internal/http.ts new file mode 100644 index 0000000..7915140 --- /dev/null +++ b/packages/bridge/src/internal/http.ts @@ -0,0 +1,391 @@ +import * as Context from "effect/Context" +import * as Effect from "effect/Effect" +import * as Inspectable from "effect/Inspectable" +import * as Pipeable from "effect/Pipeable" +import * as Redacted from "effect/Redacted" +import * as Schema from "effect/Schema" +import * as Stream from "effect/Stream" +import * as HttpApiMiddleware from "effect/unstable/httpapi/HttpApiMiddleware" +import * as HttpClient from "effect/unstable/http/HttpClient" +import * as HttpClientError from "effect/unstable/http/HttpClientError" +import * as HttpIncomingMessage from "effect/unstable/http/HttpIncomingMessage" +import * as HttpClientRequest from "effect/unstable/http/HttpClientRequest" +import * as HttpClientResponse from "effect/unstable/http/HttpClientResponse" +import * as HttpBody from "effect/unstable/http/HttpBody" +import * as Headers from "effect/unstable/http/Headers" + +import { + ApiKeySecurityMiddleware, + BridgeApi, + PostCustomersByCustomerIDCardAccountsByCardAccountIDEphemeralKeysRequestJson, + PostCustomersByCustomerIDCardAccountsByCardAccountIDFreezeRequestJson, + PostCustomersByCustomerIDCardAccountsByCardAccountIDUnfreezeRequestJson, + PostCustomersByCustomerIDCardAccountsByCardAccountIDCreateMobileWalletProvisioningRequestRequestJson +} from "../generated/BridgeApi.js" +import { + BridgeHttpError, + BridgeSchemaError, + BridgeTimeoutError, + BridgeTransportError, + type BridgeClientError +} from "../Errors.js" + +const safeRequest = (request: HttpClientRequest.HttpClientRequest): HttpClientRequest.HttpClientRequest => + HttpClientRequest.make(request.method)("https://bridge.invalid/") + +const responseRequestId = (response: HttpClientResponse.HttpClientResponse): string | undefined => { + const id = response.headers["x-request-id"] ?? response.headers["request-id"] + return id === undefined ? undefined : id.slice(0, 128) +} + +const bridgeHttpErrorFromResponse = (response: HttpClientResponse.HttpClientResponse) => { + const id = responseRequestId(response) + return new BridgeHttpError({ + status: response.status, + method: response.request.method, + ...(id === undefined ? {} : { requestId: id }) + }) +} + +const isBridgeClientError = (error: unknown): error is BridgeClientError => + error instanceof BridgeHttpError || + error instanceof BridgeTransportError || + error instanceof BridgeSchemaError || + error instanceof BridgeTimeoutError + +const safeDeferredFailure = (error: unknown): BridgeClientError => { + const sanitized = sanitizeFailure(error, "response") + return isBridgeClientError(sanitized) ? sanitized : new BridgeTransportError({ kind: "Unknown" }) +} + +const inspectableResponse = ( + response: HttpClientResponse.HttpClientResponse, + redactedHeaderNames: ReadonlyArray +): HttpClientResponse.HttpClientResponse => { + const request = safeRequest(response.request) + const safeJson = () => ({ + _id: "HttpClientResponse", + request: request.toJSON(), + status: response.status, + headers: Headers.redact(response.headers, redactedHeaderNames) + }) + const safeEffect = (effect: Effect.Effect) => + Effect.mapError(effect, safeDeferredFailure) + + // Use a facade instead of a Proxy over the transport response. In particular, + // inspection and all deferred body readers must not retain its raw request, + // URL, headers, or decoding cause. + return { + [HttpIncomingMessage.TypeId]: HttpIncomingMessage.TypeId, + [HttpClientResponse.TypeId]: HttpClientResponse.TypeId, + request, + status: response.status, + get headers() { + return response.headers + }, + get cookies() { + return response.cookies + }, + get remoteAddress() { + return response.remoteAddress + }, + get json() { + return safeEffect(response.json) + }, + get text() { + return safeEffect(response.text) + }, + get urlParamsBody() { + return safeEffect(response.urlParamsBody) + }, + get arrayBuffer() { + return safeEffect(response.arrayBuffer) + }, + get formData() { + return safeEffect(response.formData) + }, + get stream() { + return Stream.mapError(response.stream, safeDeferredFailure) + }, + pipe() { + return Pipeable.pipeArguments(this, arguments) + }, + toJSON: safeJson, + [Inspectable.NodeInspectSymbol]: safeJson, + toString: () => "[HttpClientResponse]" + } as unknown as HttpClientResponse.HttpClientResponse +} + +const optionalCardMutationPath = /(?:^|\/)customers\/[^/?#]+\/card_accounts\/[^/?#]+\/(?:ephemeral_keys|freeze|unfreeze|create_mobile_wallet_provisioning_request)$/ + +/** Concrete request schemas for endpoints whose generated payload union also accepts NoContent. */ +const optionalCardPayloadSchemas: Readonly> = { + postCustomersByCustomerIDCardAccountsByCardAccountIDEphemeralKeys: PostCustomersByCustomerIDCardAccountsByCardAccountIDEphemeralKeysRequestJson, + postCustomersByCustomerIDCardAccountsByCardAccountIDFreeze: PostCustomersByCustomerIDCardAccountsByCardAccountIDFreezeRequestJson, + postCustomersByCustomerIDCardAccountsByCardAccountIDUnfreeze: PostCustomersByCustomerIDCardAccountsByCardAccountIDUnfreezeRequestJson, + postCustomersByCustomerIDCardAccountsByCardAccountIDCreateMobileWalletProvisioningRequest: PostCustomersByCustomerIDCardAccountsByCardAccountIDCreateMobileWalletProvisioningRequestRequestJson +} +const optionalCardPayloadOperations = new Set(Object.keys(optionalCardPayloadSchemas)) + +/** JSON-only request bodies from the generated API; FormData is only valid for multipart endpoints. */ +const jsonOnlyPayloadOperations = new Map>( + Object.entries(BridgeApi.groups).map(([groupName, group]) => [ + groupName, + new Set(Object.entries(group.endpoints) + .filter(([, endpoint]) => { + const encodings = Array.from(endpoint.payload.values(), ({ encoding }) => encoding._tag) + return encodings.includes("Json") && !encodings.includes("Multipart") + }) + .map(([operationName]) => operationName)) + ]) +) + +/** JSON payload schemas that can both validate and detach an execution-time snapshot. */ +const jsonPayloadSchemas = new Map>( + Object.entries(BridgeApi.groups).map(([groupName, group]) => { + const schemas = new Map() + for (const [operationName, endpoint] of Object.entries(group.endpoints)) { + const payloads = Array.from(endpoint.payload.values()) as ReadonlyArray<{ + readonly encoding: { readonly _tag: string } + readonly schemas: ReadonlyArray + }> + const payloadSchemas = payloads + .filter(({ encoding }) => encoding._tag === "Json") + .flatMap(({ schemas }) => schemas) + if (payloadSchemas.length !== 1) continue + const [schema] = payloadSchemas + if (schema !== undefined) schemas.set(operationName, schema) + } + return [groupName, schemas] as const + }) +) + +const isFormData = (value: unknown): value is FormData => + typeof FormData !== "undefined" && value instanceof FormData + +const snapshotRequestPart = (value: unknown): unknown => { + if (typeof value !== "object" || value === null) return value + return structuredClone(value) +} + +/** Call-local marker for optional card payloads explicitly absent at the API. */ +export const OptionalCardNoContent = Context.Reference("@misofm/bridge/internal/OptionalCardNoContent", { + defaultValue: () => false +}) + +/** + * The generated client encodes the `NoContent` member of optional payload + * unions as JSON `null`. Use the call-local marker instead of inspecting the + * encoded body, so an explicit JSON `null` payload remains distinguishable. + */ +const normalizeOptionalCardMutationBody = ( + request: HttpClientRequest.HttpClientRequest +): Effect.Effect => + Effect.map( + Effect.contextWith((context) => Effect.succeed(Context.get(context, OptionalCardNoContent))), + (noContent) => { + if (!noContent || request.method !== "POST") return request + const path = request.url.split(/[?#]/, 1)[0] ?? request.url + if (!optionalCardMutationPath.test(path)) return request + return HttpClientRequest.setBody(request, HttpBody.empty) + } + ) + +/** Replace the request attached to a raw response before it enters HttpApiClient. */ +export const sanitizeHttpClient = (client: HttpClient.HttpClient): HttpClient.HttpClient => + client.pipe( + HttpClient.mapRequestEffect(normalizeOptionalCardMutationBody), + HttpClient.transformResponse((response) => + Effect.flatMap(response, (received) => { + if (received.status < 200 || received.status >= 300) { + // Release streamed response resources without decoding or retaining + // the body, then report only its safe status metadata. + return Effect.flatMap( + Effect.ignore( + Stream.runDrain(Stream.mapError(received.stream, safeDeferredFailure)) + ), + () => Effect.fail(bridgeHttpErrorFromResponse(received)) + ) + } + return Effect.map( + Effect.contextWith((context) => + Effect.succeed(Context.get(context, Headers.CurrentRedactedNames)) + ), + (redactedHeaderNames) => inspectableResponse(received, redactedHeaderNames) + ) + }) + ) + ) as unknown as HttpClient.HttpClient + +export const apiKeyClientLayer = (apiKey: Redacted.Redacted) => + HttpApiMiddleware.layerClient(ApiKeySecurityMiddleware, ({ request, next }) => + next(HttpClientRequest.setHeader(request, "Api-Key", Redacted.value(apiKey))) + ) + +const requestId = (error: HttpClientError.HttpClientError): string | undefined => { + const response = error.response + if (response === undefined) return undefined + return responseRequestId(response) +} + +export const sanitizeFailure = ( + error: unknown, + phase: "request" | "response" = "request", + timeoutMs = 0 +): BridgeClientError | unknown => { + if (HttpClientError.isHttpClientError(error)) { + const reason = error.reason + if (reason._tag === "StatusCodeError") { + return bridgeHttpError(error, reason.response.status, reason.request.method) + } + if (reason._tag === "DecodeError" || reason._tag === "EmptyBodyError") { + const status = reason.response.status + if (status < 200 || status >= 300) return bridgeHttpError(error, status, reason.request.method) + const id = requestId(error) + return new BridgeSchemaError({ + phase: "response", + status, + method: reason.request.method, + ...(id === undefined ? {} : { requestId: id }) + }) + } + if (reason._tag === "TransportError" || reason._tag === "InvalidUrlError" || reason._tag === "EncodeError") { + return new BridgeTransportError({ kind: reason._tag, method: reason.request.method }) + } + return new BridgeTransportError({ kind: "Unknown" }) + } + if (Schema.isSchemaError(error)) return new BridgeSchemaError({ phase }) + if (typeof error === "object" && error !== null && "_tag" in error && error._tag === "TimeoutError") { + return new BridgeTimeoutError({ timeoutMs }) + } + return error +} + +const bridgeHttpError = (error: HttpClientError.HttpClientError, status: number, method: string) => { + const id = requestId(error) + return new BridgeHttpError({ + status, + method, + ...(id === undefined ? {} : { requestId: id }) + }) +} + +/** + * Apply the safe error boundary to every generated method without changing the + * generated request/response signatures. `mapError` leaves interruption alone. + */ +export const sanitizeClientErrors = >( + client: A, + options: { readonly timeoutMs?: number | undefined; readonly redactedHeaderNames: ReadonlyArray } +): A => { + const wrapEffect = (effect: Effect.Effect) => { + const withTimeout = options.timeoutMs === undefined ? effect : Effect.timeout(effect, options.timeoutMs) + return Effect.provideService( + Effect.provideService( + Effect.mapError(withTimeout, (error) => sanitizeFailure(error, "request", options.timeoutMs)), + // Effect's default HTTP client span records the full URL and query before + // header filtering. Disable it only while a Bridge method is running. + HttpClient.TracerDisabledWhen, + () => true + ), + Headers.CurrentRedactedNames, + options.redactedHeaderNames + ) + } + + const groups: Record = {} + for (const [groupName, group] of Object.entries(client)) { + if (typeof group !== "object" || group === null) continue + const operations: Record = {} + for (const [operationName, operation] of Object.entries(group)) { + if (typeof operation !== "function") continue + operations[operationName] = (...args: ReadonlyArray) => { + const effect = Effect.suspend(() => { + const request = args[0] + // A supplied request must be a data object. Callable objects can carry + // getters too, but the generated client reads them lazily; rejecting + // them here keeps those exceptions out of printable Effect defects. + if (request !== undefined && (typeof request !== "object" || request === null)) { + return Effect.fail(new BridgeSchemaError({ phase: "request" })) + } + const isOptionalCardPayloadOperation = groupName === "cards" && optionalCardPayloadOperations.has(operationName) + const isJsonOnlyPayloadOperation = jsonOnlyPayloadOperations.get(groupName)?.has(operationName) ?? false + let requestSnapshot: Record | undefined + let payload: unknown + let detachedPayload: unknown + let isJsonOnlyFormData = false + try { + requestSnapshot = typeof request === "object" && request !== null + ? { ...request } as Record + : undefined + if (requestSnapshot !== undefined) { + // Capture caller-owned request fields at execution time. Structured + // cloning also detaches nested values and confines throwing accessors + // or proxy traps to this request boundary. + for (const key of ["params", "headers", "query"] as const) { + requestSnapshot[key] = snapshotRequestPart(requestSnapshot[key]) + } + } + payload = requestSnapshot?.payload + isJsonOnlyFormData = isJsonOnlyPayloadOperation && isFormData(payload) + const schema = isOptionalCardPayloadOperation + ? optionalCardPayloadSchemas[operationName] + : isJsonOnlyPayloadOperation + ? jsonPayloadSchemas.get(groupName)?.get(operationName) + : undefined + // Decode a detached JSON value so Schema never evaluates caller-owned + // getters or proxy traps. Clone failures become a safe typed boundary + // error; the underlying exception is intentionally discarded. + detachedPayload = payload !== undefined && schema !== undefined && !isJsonOnlyFormData + ? structuredClone(payload) + : payload + } catch { + return Effect.fail(new BridgeSchemaError({ phase: "request" })) + } + const hasNoPayload = requestSnapshot !== undefined && payload === undefined + const invoke = (operationRequest: unknown = requestSnapshot ?? request) => { + const operationArgs = requestSnapshot === undefined ? args : [operationRequest, ...args.slice(1)] + return Reflect.apply(operation, group, operationArgs) as Effect.Effect + } + const invokeWithPayload = (payloadSnapshot: unknown) => + invoke({ ...requestSnapshot, payload: payloadSnapshot }) + const decodeRequestPayload = (schema: Schema.Constraint) => + Effect.flatMap( + Effect.catchDefect( + Effect.suspend(() => Schema.decodeUnknownEffect(schema)(detachedPayload)), + () => Effect.fail(new BridgeSchemaError({ phase: "request" })) + ), + invokeWithPayload + ) + let operationEffect: Effect.Effect + if (isOptionalCardPayloadOperation && payload === null) { + operationEffect = Effect.fail(new BridgeSchemaError({ phase: "request" })) + } else if (isJsonOnlyFormData) { + operationEffect = Effect.fail(new BridgeSchemaError({ phase: "request" })) + } else if (isOptionalCardPayloadOperation && requestSnapshot !== undefined && payload !== undefined) { + const schema = optionalCardPayloadSchemas[operationName] + operationEffect = schema === undefined + ? Effect.fail(new BridgeSchemaError({ phase: "request" })) + : decodeRequestPayload(schema) + } else if (isJsonOnlyPayloadOperation && requestSnapshot !== undefined && payload !== undefined) { + const schema = jsonPayloadSchemas.get(groupName)?.get(operationName) + operationEffect = schema === undefined + ? invoke() + : decodeRequestPayload(schema) + } else { + operationEffect = invoke() + } + return isOptionalCardPayloadOperation && hasNoPayload + ? Effect.provideService(operationEffect, OptionalCardNoContent, true) + : operationEffect + }) + return wrapEffect(effect) + } + } + groups[groupName] = operations + } + return groups as A +} + +export const defaultRedactedHeaderNames = (current: ReadonlyArray) => + current.includes("api-key") ? current : [...current, "api-key"] diff --git a/packages/bridge/tests/client-types.ts b/packages/bridge/tests/client-types.ts new file mode 100644 index 0000000..c8c4e8d --- /dev/null +++ b/packages/bridge/tests/client-types.ts @@ -0,0 +1,56 @@ +import type * as Effect from "effect/Effect" +import type { Redacted } from "effect/Redacted" + +import type { BridgeClient, BridgeHttpClientResponse } from "../src/Bridge.js" +import type { BridgeClientError } from "../src/Errors.js" +import type { BridgeConfig } from "../src/Config.js" +import type { + GetCustomers200, + PostCustomersByCustomerIDCardAccountsByCardAccountIDStatementsPeriodPdf200ApplicationPdf +} from "../src/generated/BridgeApi.js" + +declare const client: BridgeClient + +const customerList = client.customers.getCustomers({ query: {} }) +const customerListType: Effect.Effect = customerList + +const customerListWithResponse = client.customers.getCustomers({ + query: {}, + responseMode: "decoded-and-response" +}) +const customerListWithResponseType: Effect.Effect< +[GetCustomers200, BridgeHttpClientResponse], + BridgeClientError +> = customerListWithResponse + +const statementPdf = client.cards.postCustomersByCustomerIDCardAccountsByCardAccountIDStatementsPeriodPdf({ + params: { customerID: "cus_test", cardAccountID: "cca_test", period: "2026-09" } +}) +const statementPdfType: Effect.Effect< + PostCustomersByCustomerIDCardAccountsByCardAccountIDStatementsPeriodPdf200ApplicationPdf, + BridgeClientError +> = statementPdf + +client.bridgeWallets.postCustomersByCustomerIDWallets({ + params: { customerID: "cus_test" }, + headers: { "Idempotency-Key": "caller-owned-stable-key" }, + payload: { chain: "base" } +}) + +// @ts-expect-error Wallet creation requires the caller's declared idempotency header. +client.bridgeWallets.postCustomersByCustomerIDWallets({ params: { customerID: "cus_test" }, payload: { chain: "base" } }) + +// @ts-expect-error Bridge explicitly forbids Idempotency-Key on POST /api_keys. +client.apiKeys.postApiKeys({ payload: { scopes: ["customer:read"] }, headers: { "Idempotency-Key": "not-allowed" } }) + +// @ts-expect-error credentials must be redacted before entering Bridge configuration. +const unsafeConfig: BridgeConfig = { apiKey: "sk-live-never-in-source" } + +declare const apiKey: Redacted +const safeConfig: BridgeConfig = { apiKey, environment: "sandbox" } + +void customerListType +void customerListWithResponseType +void statementPdfType +void unsafeConfig +void safeConfig diff --git a/packages/bridge/tests/client.test.ts b/packages/bridge/tests/client.test.ts new file mode 100644 index 0000000..82d0f2a --- /dev/null +++ b/packages/bridge/tests/client.test.ts @@ -0,0 +1,952 @@ +import { describe, expect, test } from "bun:test" +import * as Cause from "effect/Cause" +import * as Effect from "effect/Effect" +import * as Exit from "effect/Exit" +import * as Fiber from "effect/Fiber" +import * as Inspectable from "effect/Inspectable" +import * as Layer from "effect/Layer" +import * as Option from "effect/Option" +import * as Redacted from "effect/Redacted" +import * as HttpClient from "effect/unstable/http/HttpClient" +import * as HttpClientError from "effect/unstable/http/HttpClientError" +import * as HttpClientRequest from "effect/unstable/http/HttpClientRequest" +import * as HttpClientResponse from "effect/unstable/http/HttpClientResponse" +import * as FetchHttpClient from "effect/unstable/http/FetchHttpClient" +import * as Stream from "effect/Stream" +import * as Tracer from "effect/Tracer" + +import { Bridge, bridgeFetchLayer, bridgeLayer, type BridgeClient } from "../src/Bridge.js" +import { BridgeConfigurationError, BridgeHttpError, BridgeSchemaError, BridgeTimeoutError, BridgeTransportError } from "../src/Errors.js" +import type { BridgeConfig } from "../src/Config.js" + +interface RecordedCall { + readonly request: HttpClientRequest.HttpClientRequest + readonly url: URL + readonly signal: AbortSignal +} + +const apiKey = Redacted.make("sk-test-bridge-secret") + +const config = (overrides: Partial = {}): BridgeConfig => ({ + apiKey, + baseUrl: "https://bridge.test/v0", + ...overrides +}) + +const mockHttpClient = ( + calls: Array, + options: { readonly status?: number; readonly body?: string | Uint8Array | null; readonly headers?: Record } = {} +): HttpClient.HttpClient => + HttpClient.make((request, url, signal) => { + calls.push({ request, url, signal }) + return Effect.succeed(HttpClientResponse.fromWeb( + request, + new Response(options.body ?? null, { + status: options.status ?? 200, + ...(options.headers === undefined ? {} : { headers: options.headers }) + }) + )) + }) + +const withBridge = ( + effect: Effect.Effect, + client: HttpClient.HttpClient, + clientConfig: BridgeConfig = config() +): Effect.Effect => + Effect.provide( + effect, + bridgeLayer(clientConfig).pipe(Layer.provide(Layer.succeed(HttpClient.HttpClient, client))) + ) + +const customerList = () => + Effect.gen(function*() { + const bridge = yield* Bridge + return yield* bridge.customers.getCustomers({ query: {} }) + }) + +describe("Bridge authenticated Effect client", () => { + test("uses the configured base URL and Api-Key header with generated group methods", async () => { + const calls: Array = [] + const client = mockHttpClient(calls, { body: JSON.stringify({ count: 0, data: [] }) }) + const customers = await Effect.runPromise(withBridge(customerList(), client)) + + expect(customers).toEqual({ count: 0, data: [] }) + expect(calls).toHaveLength(1) + expect(calls[0]?.url.href).toBe("https://bridge.test/v0/customers") + expect(calls[0]?.request.headers["api-key"]).toBe("sk-test-bridge-secret") + }) + + test("suppresses Bridge HTTP URL attributes and propagation within the caller span", async () => { + const calls: Array = [] + const client = mockHttpClient(calls, { body: JSON.stringify({ count: 0, data: [] }) }) + const spans: Array = [] + const tracer = Tracer.make({ + span: (options) => { + const span = new Tracer.NativeSpan(options) + spans.push(span) + return span + } + }) + const email = "private-query@example.invalid" + const call = Effect.withSpan(Effect.gen(function*() { + yield* withBridge(Effect.gen(function*() { + const bridge = yield* Bridge + return yield* bridge.customers.getCustomers({ query: { email } }) + }), client) + const outsideClient = yield* HttpClient.HttpClient + return yield* outsideClient.get("https://outside.test/ping") + }), "caller.bridge-operation") + + await Effect.runPromise(Effect.provideService( + Effect.provideService(call, Tracer.Tracer, tracer), + HttpClient.HttpClient, + client + )) + + const spanAttributes = JSON.stringify(spans.map((span) => Array.from(span.attributes.entries()))) + expect(spans.map((span) => span.name)).toContain("caller.bridge-operation") + expect(spans.filter((span) => span.kind === "client")).toHaveLength(1) + expect(spanAttributes).not.toContain(email) + expect(spanAttributes.toLowerCase()).not.toContain("api-key") + expect(calls).toHaveLength(2) + expect(calls[0]?.request.headers["api-key"]).toBe("sk-test-bridge-secret") + expect(calls[0]?.request.headers["traceparent"]).toBeUndefined() + expect(calls[0]?.request.headers["tracestate"]).toBeUndefined() + expect(calls[1]?.url.href).toBe("https://outside.test/ping") + expect(calls[1]?.request.headers["traceparent"]).toBeDefined() + }) + + test("rejects invalid request data before HTTP and scrubs schema input", async () => { + const calls: Array = [] + const client = mockHttpClient(calls, { body: JSON.stringify({ count: 0, data: [] }) }) + const effect = Effect.gen(function*() { + const bridge = yield* Bridge + const postCustomer = bridge.customers.postCustomers as unknown as ( + request: unknown + ) => Effect.Effect + return yield* Effect.flip(postCustomer({ + headers: { "Idempotency-Key": "caller-key" }, + payload: { type: "individual", first_name: "Sensitive KYC name", last_name: 42 } + })) + }) + + const failure = await Effect.runPromise(withBridge(effect, client)) + expect(failure).toBeInstanceOf(BridgeSchemaError) + expect(JSON.stringify(failure)).not.toContain("Sensitive KYC name") + expect(String(failure)).not.toContain("Sensitive KYC name") + expect(calls).toHaveLength(0) + }) + + test("keeps caller idempotency stable and does not retry a mutation", async () => { + const calls: Array = [] + const client = mockHttpClient(calls, { status: 201, body: JSON.stringify({ chain: "base" }) }) + const result = await Effect.runPromise(withBridge(Effect.gen(function*() { + const bridge = yield* Bridge + return yield* bridge.bridgeWallets.postCustomersByCustomerIDWallets({ + params: { customerID: "cus_test_123" }, + headers: { "Idempotency-Key": "caller-stable-idempotency-key" }, + payload: { chain: "base" } + }) + }), client)) + + expect(result).toMatchObject({ chain: "base" }) + expect(calls).toHaveLength(1) + expect(calls[0]?.request.headers["idempotency-key"]).toBe("caller-stable-idempotency-key") + }) + + test("does not add Idempotency-Key to POST /api_keys", async () => { + const calls: Array = [] + const client = mockHttpClient(calls, { + status: 401, + body: JSON.stringify({ code: "unauthorized", message: "not authorized" }) + }) + const error = await Effect.runPromise(withBridge(Effect.gen(function*() { + const bridge = yield* Bridge + return yield* Effect.flip(bridge.apiKeys.postApiKeys({ payload: { scopes: ["customer:read"] } })) + }), client)) + + expect(error).toBeInstanceOf(BridgeHttpError) + expect(error).toMatchObject({ status: 401, method: "POST" }) + expect(calls).toHaveLength(1) + expect(calls[0]?.request.headers["api-key"]).toBe("sk-test-bridge-secret") + expect(calls[0]?.request.headers["idempotency-key"]).toBeUndefined() + }) + + test("distinguishes absent from supplied optional card POST payloads", async () => { + const calls: Array = [] + const client = mockHttpClient(calls) + const exercise = Effect.flatMap(Bridge, (bridge) => { + const params = { customerID: "cus_test", cardAccountID: "cca_test" } + const headers = { "Idempotency-Key": "caller-stable-card-key" } + return Effect.all([ + Effect.ignore(bridge.cards.postCustomersByCustomerIDCardAccountsByCardAccountIDFreeze({ params, headers, payload: undefined })), + Effect.ignore(bridge.cards.postCustomersByCustomerIDCardAccountsByCardAccountIDUnfreeze({ params, headers, payload: undefined })), + Effect.ignore(bridge.cards.postCustomersByCustomerIDCardAccountsByCardAccountIDCreateMobileWalletProvisioningRequest({ params, headers, payload: undefined })), + Effect.ignore(bridge.cards.postCustomersByCustomerIDCardAccountsByCardAccountIDEphemeralKeys({ params, headers, payload: undefined })), + Effect.ignore(bridge.cards.postCustomersByCustomerIDCardAccountsByCardAccountIDFreeze({ + params, + headers, + payload: { initiator: "developer", reason: "other" } + })), + Effect.ignore(bridge.cards.postCustomersByCustomerIDCardAccountsByCardAccountIDUnfreeze({ + params, + headers, + payload: { initiator: "developer" } + })), + Effect.ignore(bridge.cards.postCustomersByCustomerIDCardAccountsByCardAccountIDCreateMobileWalletProvisioningRequest({ + params, + headers, + payload: { initiator: "developer" } + })), + Effect.ignore(bridge.cards.postCustomersByCustomerIDCardAccountsByCardAccountIDEphemeralKeys({ + params, + headers, + payload: { client_nonce: "nonce-test" } + })) + ], { concurrency: 1 }) + }) + await Effect.runPromise(withBridge(exercise, client)) + + expect(calls).toHaveLength(8) + const emptyBodyCalls = calls.filter((call) => call.request.body._tag === "Empty") + expect(emptyBodyCalls).toHaveLength(4) + expect(emptyBodyCalls.map((call) => call.url.pathname).sort()).toEqual([ + "/v0/customers/cus_test/card_accounts/cca_test/create_mobile_wallet_provisioning_request", + "/v0/customers/cus_test/card_accounts/cca_test/ephemeral_keys", + "/v0/customers/cus_test/card_accounts/cca_test/freeze", + "/v0/customers/cus_test/card_accounts/cca_test/unfreeze" + ]) + for (const call of emptyBodyCalls) { + expect(call.request.method).toBe("POST") + expect(call.request.headers["content-type"]).toBeUndefined() + expect(call.request.headers["content-length"]).toBeUndefined() + expect(call.request.headers["api-key"]).toBe("sk-test-bridge-secret") + expect(call.request.headers["idempotency-key"]).toBe("caller-stable-card-key") + } + const expectedPayloadByPath = new Map([ + ["/v0/customers/cus_test/card_accounts/cca_test/freeze", '{"initiator":"developer","reason":"other"}'], + ["/v0/customers/cus_test/card_accounts/cca_test/unfreeze", '{"initiator":"developer"}'], + ["/v0/customers/cus_test/card_accounts/cca_test/create_mobile_wallet_provisioning_request", '{"initiator":"developer"}'], + ["/v0/customers/cus_test/card_accounts/cca_test/ephemeral_keys", '{"client_nonce":"nonce-test"}'] + ]) + const jsonBodyCalls = calls.filter((call) => call.request.body._tag !== "Empty") + expect(jsonBodyCalls).toHaveLength(4) + for (const call of jsonBodyCalls) { + expect(call.request.body._tag).toBe("Uint8Array") + if (call.request.body._tag === "Uint8Array") { + const expectedPayload = expectedPayloadByPath.get(call.url.pathname) + expect(expectedPayload).toBeDefined() + if (expectedPayload !== undefined) { + expect(new TextDecoder().decode(call.request.body.body)).toBe(expectedPayload) + } + } + expect(call.request.headers["content-type"]).toBe("application/json") + expect(call.request.headers["idempotency-key"]).toBe("caller-stable-card-key") + } + }) + + test("validates supplied optional card POST payloads before HTTP", async () => { + const calls: Array = [] + const client = mockHttpClient(calls) + const failures = await Effect.runPromise(withBridge(Effect.flatMap(Bridge, (bridge) => { + const params = { customerID: "cus_test", cardAccountID: "cca_test" } + const headers = { "Idempotency-Key": "caller-stable-card-key" } + const callWithPayload = (method: unknown, payload: unknown) => { + const operation = method as (request: unknown) => Effect.Effect + return Effect.flip(operation({ params, headers, payload })) + } + const malformedValues = [1, true, "primitive", [], {}] + const cases: ReadonlyArray]> = [ + [ + bridge.cards.postCustomersByCustomerIDCardAccountsByCardAccountIDFreeze, + [...malformedValues, { initiator: "admin", reason: "other" }, { initiator: "developer", reason: "fraud" }] + ], + [ + bridge.cards.postCustomersByCustomerIDCardAccountsByCardAccountIDUnfreeze, + [...malformedValues, { initiator: "admin" }] + ], + [ + bridge.cards.postCustomersByCustomerIDCardAccountsByCardAccountIDCreateMobileWalletProvisioningRequest, + [ + ...malformedValues, + { initiator: "developer", wallet_provider: "samsung_pay" }, + { + initiator: "developer", + wallet_provider: "google_pay", + google_pay: { client_wallet_account_id: "wallet_test" } + } + ] + ], + [ + bridge.cards.postCustomersByCustomerIDCardAccountsByCardAccountIDEphemeralKeys, + [...malformedValues, { client_nonce: 42 }] + ] + ] + return Effect.all( + cases.flatMap(([method, payloads]) => payloads.map((payload) => callWithPayload(method, payload))), + { concurrency: 1 } + ) + }), client)) + + expect(failures).toHaveLength(26) + for (const failure of failures) { + expect(failure).toBeInstanceOf(BridgeSchemaError) + expect(failure).toMatchObject({ phase: "request" }) + expect(JSON.stringify(failure)).not.toContain("wallet_test") + } + expect(calls).toHaveLength(0) + }) + + test("rejects explicit null payloads on optional card POSTs before HTTP", async () => { + const calls: Array = [] + const client = mockHttpClient(calls) + const errors = await Effect.runPromise(withBridge(Effect.flatMap(Bridge, (bridge) => { + const request = { + params: { customerID: "cus_test", cardAccountID: "cca_test" }, + headers: { "Idempotency-Key": "caller-stable-card-key" }, + payload: null + } + const callWithNull = (method: unknown) => { + const operation = method as (request: unknown) => Effect.Effect + return Effect.flip(operation(request)) + } + return Effect.all([ + callWithNull(bridge.cards.postCustomersByCustomerIDCardAccountsByCardAccountIDFreeze), + callWithNull(bridge.cards.postCustomersByCustomerIDCardAccountsByCardAccountIDUnfreeze), + callWithNull(bridge.cards.postCustomersByCustomerIDCardAccountsByCardAccountIDCreateMobileWalletProvisioningRequest), + callWithNull(bridge.cards.postCustomersByCustomerIDCardAccountsByCardAccountIDEphemeralKeys) + ]) + }), client)) + + expect(errors).toHaveLength(4) + for (const error of errors) { + expect(error).toBeInstanceOf(BridgeSchemaError) + expect(error).toMatchObject({ phase: "request" }) + } + expect(calls).toHaveLength(0) + }) + + test("rejects FormData for JSON-only request payloads before HTTP", async () => { + const calls: Array = [] + const client = mockHttpClient(calls) + const error = await Effect.runPromise(withBridge(Effect.flatMap(Bridge, (bridge) => { + const postTransfers = bridge.transfers.postTransfers as unknown as ( + request: unknown + ) => Effect.Effect + return Effect.flip(postTransfers({ + headers: { "Idempotency-Key": "caller-transfer-key" }, + payload: new FormData() + })) + }), client)) + + expect(error).toBeInstanceOf(BridgeSchemaError) + expect(error).toMatchObject({ phase: "request" }) + expect(calls).toHaveLength(0) + }) + + test("evaluates payload guards against an execution-time request snapshot", async () => { + const calls: Array = [] + const client = mockHttpClient(calls) + const postFreeze = (bridge: BridgeClient) => bridge.cards.postCustomersByCustomerIDCardAccountsByCardAccountIDFreeze as unknown as ( + request: unknown + ) => Effect.Effect + const postTransfers = (bridge: BridgeClient) => bridge.transfers.postTransfers as unknown as ( + request: unknown + ) => Effect.Effect + + const invalidCardPayload = await Effect.runPromise(withBridge(Effect.gen(function*() { + const bridge = yield* Bridge + const request: Record = { + params: { customerID: "cus_test", cardAccountID: "cca_test" }, + payload: { initiator: "developer", reason: "other" } + } + const pending = postFreeze(bridge)(request) + request.payload = {} + return yield* Effect.flip(pending) + }), client)) + expect(invalidCardPayload).toBeInstanceOf(BridgeSchemaError) + + const cardFormData = await Effect.runPromise(withBridge(Effect.gen(function*() { + const bridge = yield* Bridge + const request: Record = { + params: { customerID: "cus_test", cardAccountID: "cca_test" }, + payload: { initiator: "developer", reason: "other" } + } + const pending = postFreeze(bridge)(request) + request.payload = new FormData() + return yield* Effect.flip(pending) + }), client)) + expect(cardFormData).toBeInstanceOf(BridgeSchemaError) + + const transferFormData = await Effect.runPromise(withBridge(Effect.gen(function*() { + const bridge = yield* Bridge + const request: Record = { + payload: { + on_behalf_of: "cus_test", + source: { currency: "usd", payment_rail: "ach" }, + destination: { currency: "usd", payment_rail: "ach", external_account_id: "ea_test" } + } + } + const pending = postTransfers(bridge)(request) + request.payload = new FormData() + return yield* Effect.flip(pending) + }), client)) + expect(transferFormData).toBeInstanceOf(BridgeSchemaError) + expect(calls).toHaveLength(0) + + await Effect.runPromise(withBridge(Effect.gen(function*() { + const bridge = yield* Bridge + const request: Record = { + params: { customerID: "cus_before" }, + headers: { "Idempotency-Key": "before-execution" }, + payload: undefined, + responseMode: "response-only" + } + const pending = postFreeze(bridge)(request) + request.params = { customerID: "cus_at_execution", cardAccountID: "cca_at_execution" } + request.headers = { "Idempotency-Key": "at-execution" } + request.payload = { initiator: "developer", reason: "other" } + return yield* Effect.ignore(pending) + }), client)) + + expect(calls).toHaveLength(1) + expect(calls[0]?.url.pathname).toBe("/v0/customers/cus_at_execution/card_accounts/cca_at_execution/freeze") + expect(calls[0]?.request.headers["idempotency-key"]).toBe("at-execution") + expect(calls[0]?.request.body._tag).toBe("Uint8Array") + if (calls[0]?.request.body._tag === "Uint8Array") { + expect(new TextDecoder().decode(calls[0].request.body.body)).toBe(JSON.stringify({ initiator: "developer", reason: "other" })) + } + }) + + test("maps throwing request and payload getters or proxies to a redacted request error", async () => { + const calls: Array = [] + const client = mockHttpClient(calls) + const validPayload = { initiator: "developer", reason: "other" } + const throwingProperty = (target: object, key: string, marker: string) => + Object.defineProperty(target, key, { + configurable: true, + enumerable: true, + get: () => { + throw new Error(marker) + } + }) + const requestWithPayloadGetter = {} + throwingProperty(requestWithPayloadGetter, "payload", "request-payload-getter-marker") + const requestWithSpreadGetter: Record = { + params: { customerID: "cus_test", cardAccountID: "cca_test" }, + payload: validPayload + } + throwingProperty(requestWithSpreadGetter, "unused", "request-spread-getter-marker") + const params = { cardAccountID: "cca_test" } + throwingProperty(params, "customerID", "params-getter-marker") + const headers = {} + throwingProperty(headers, "Idempotency-Key", "headers-getter-marker") + const query = {} + throwingProperty(query, "email", "query-getter-marker") + const payloadWithGetter = { initiator: "developer" } + throwingProperty(payloadWithGetter, "reason", "payload-decode-getter-marker") + const requestProxy = new Proxy({ + params: { customerID: "cus_test", cardAccountID: "cca_test" }, + payload: validPayload + }, { + ownKeys: () => { + throw new Error("request-proxy-marker") + } + }) + const payloadProxy = new Proxy(validPayload, { + ownKeys: () => { + throw new Error("payload-proxy-marker") + } + }) + const callableRequest = Object.assign(() => undefined, { payload: validPayload }) + throwingProperty(callableRequest, "params", "callable-getter-marker") + const callableProxy = new Proxy(Object.assign(() => undefined, { payload: validPayload }), { + get: () => { + throw new Error("callable-proxy-marker") + } + }) + const requests: ReadonlyArray = [ + ["request payload getter", requestWithPayloadGetter, "request-payload-getter-marker"], + ["request spread getter", requestWithSpreadGetter, "request-spread-getter-marker"], + ["params getter", { params, payload: validPayload }, "params-getter-marker"], + ["headers getter", { headers, payload: validPayload }, "headers-getter-marker"], + ["query getter", { query, payload: validPayload }, "query-getter-marker"], + ["payload getter during decode", { payload: payloadWithGetter }, "payload-decode-getter-marker"], + ["request proxy", requestProxy, "request-proxy-marker"], + ["payload proxy", { payload: payloadProxy }, "payload-proxy-marker"], + ["callable request", callableRequest, "callable-getter-marker"], + ["callable proxy", callableProxy, "callable-proxy-marker"], + ["null request", null, "null-request-marker"], + ["primitive request", 42, "primitive-request-marker"] + ] + const postFreeze = (bridge: BridgeClient) => + bridge.cards.postCustomersByCustomerIDCardAccountsByCardAccountIDFreeze as unknown as ( + request: unknown + ) => Effect.Effect + + for (const [label, request, marker] of requests) { + const exit = await Effect.runPromiseExit(withBridge(Effect.gen(function*() { + const bridge = yield* Bridge + return yield* postFreeze(bridge)(request) + }), client)) + expect(Exit.isFailure(exit), label).toBe(true) + if (Exit.isFailure(exit)) { + const failure = Cause.findErrorOption(exit.cause) + expect(Cause.hasDies(exit.cause), label).toBe(false) + expect(Option.isSome(failure) && failure.value instanceof BridgeSchemaError, label).toBe(true) + if (Option.isSome(failure)) { + expect(failure.value, label).toMatchObject({ phase: "request" }) + } + const printedCause = `${Cause.pretty(exit.cause)} ${JSON.stringify(exit.cause)}` + expect(printedCause, label).not.toContain(marker) + } + } + expect(calls).toHaveLength(0) + }) + + test("encodes the decoded payload snapshot if its source changes during validation", async () => { + const calls: Array = [] + const client = mockHttpClient(calls) + let reason = "other" + let reasonReads = 0 + const payload = { initiator: "developer" } as Record + Object.defineProperty(payload, "reason", { + enumerable: true, + get: () => { + reasonReads += 1 + const currentReason = reason + reason = "fraud" + return currentReason + } + }) + + await Effect.runPromise(withBridge(Effect.gen(function*() { + const bridge = yield* Bridge + const postFreeze = bridge.cards.postCustomersByCustomerIDCardAccountsByCardAccountIDFreeze as unknown as ( + request: unknown + ) => Effect.Effect + return yield* postFreeze({ + params: { customerID: "cus_test", cardAccountID: "cca_test" }, + headers: { "Idempotency-Key": "caller-stable-race-key" }, + payload, + responseMode: "response-only" + }) + }), client)) + + expect(reasonReads).toBeGreaterThan(0) + expect(reason).toBe("fraud") + expect(calls).toHaveLength(1) + const body = calls[0]?.request.body + expect(body?._tag).toBe("Uint8Array") + if (body?._tag === "Uint8Array") { + expect(new TextDecoder().decode(body.body)).toBe(JSON.stringify({ initiator: "developer", reason: "other" })) + } + }) + + test("keeps valid POST /transfers payloads on the JSON encoder", async () => { + const calls: Array = [] + const client = mockHttpClient(calls) + const payload = { + on_behalf_of: "cus_test", + source: { currency: "usd", payment_rail: "ach" }, + destination: { currency: "usd", payment_rail: "ach", external_account_id: "ea_test" } + } as const + await Effect.runPromise(withBridge(Effect.flatMap(Bridge, (bridge) => + Effect.ignore(bridge.transfers.postTransfers({ + headers: { "Idempotency-Key": "caller-transfer-key" }, + payload + })) + ), client)) + + expect(calls).toHaveLength(1) + const body = calls[0]?.request.body + expect(body?._tag).toBe("Uint8Array") + if (body?._tag === "Uint8Array") { + expect(new TextDecoder().decode(body.body)).toBe(JSON.stringify(payload)) + } + }) + + test("sanitizes transport errors rather than exposing request, KYC data, or causes", async () => { + const calls: Array = [] + const client = HttpClient.make((request, url, signal) => { + calls.push({ request, url, signal }) + return Effect.fail(new HttpClientError.HttpClientError({ + reason: new HttpClientError.TransportError({ + request, + cause: new Error("failed while sending KYC details: sensitive-account-number") + }) + })) + }) + const effect = Effect.gen(function*() { + const bridge = yield* Bridge + return yield* Effect.flip(bridge.bridgeWallets.postCustomersByCustomerIDWallets({ + params: { customerID: "cus_sensitive_identifier" }, + headers: { "Idempotency-Key": "caller-key" }, + payload: { chain: "base", account_number: "sensitive-account-number" } + })) + }) + const error = await Effect.runPromise(withBridge(effect, client)) + const printable = [JSON.stringify(error), String(error)].join(" ") + + expect(error).toBeInstanceOf(BridgeTransportError) + for (const secret of ["sk-test-bridge-secret", "sensitive-account-number", "cus_sensitive_identifier", "KYC details"]) { + expect(printable).not.toContain(secret) + } + }) + + test("maps invalid response schemas without retaining response values", async () => { + const calls: Array = [] + const client = mockHttpClient(calls, { + body: JSON.stringify({ count: "private-response-value", data: [] }) + }) + const error = await Effect.runPromise(withBridge(Effect.flip(customerList()), client)) + + expect(error).toBeInstanceOf(BridgeSchemaError) + expect(JSON.stringify(error)).not.toContain("private-response-value") + }) + + test("does not decode declared transfer 400 bodies into public errors", async () => { + const calls: Array = [] + const client = mockHttpClient(calls, { + status: 400, + body: JSON.stringify({ + code: "invalid_transfer", + message: "Sensitive KYC response name was rejected", + kyc_fields: { + full_name: "Sensitive KYC response name", + document_number: "private-response-document-number" + } + }), + headers: { "content-type": "application/json", "x-request-id": "bridge-transfer-400" } + }) + const error = await Effect.runPromise(withBridge(Effect.gen(function*() { + const bridge = yield* Bridge + return yield* Effect.flip(bridge.transfers.postTransfers({ + headers: { "Idempotency-Key": "caller-stable-transfer-key" }, + payload: { + on_behalf_of: "cus_sensitive_identifier", + source: { currency: "usd", payment_rail: "ach" }, + destination: { currency: "usd", payment_rail: "ach", external_account_id: "acct_sensitive_identifier" }, + travel_rule_data: { + originator: { + name: "Sensitive KYC request name", + identifying_information: [{ type: "passport", issuing_country: "US", number: "private-request-document-number" }] + } + } + } + })) + }), client)) + const printable = [JSON.stringify(error), String(error)].join(" ") + + expect(error).toBeInstanceOf(BridgeHttpError) + expect(error).toMatchObject({ status: 400, method: "POST", requestId: "bridge-transfer-400" }) + for (const secret of [ + "sk-test-bridge-secret", + "Sensitive KYC response name", + "private-response-document-number", + "Sensitive KYC request name", + "private-request-document-number", + "cus_sensitive_identifier", + "acct_sensitive_identifier" + ]) { + expect(printable).not.toContain(secret) + } + expect(calls).toHaveLength(1) + }) + + test("response-only calls fail non-2xx statuses with safe BridgeHttpError metadata", async () => { + const calls: Array = [] + const client = mockHttpClient(calls, { + status: 401, + body: JSON.stringify({ code: "unauthorized", message: "private response detail" }), + headers: { "content-type": "application/json", "x-request-id": "bridge-response-only-401" } + }) + const error = await Effect.runPromise(withBridge(Effect.gen(function*() { + const bridge = yield* Bridge + return yield* Effect.flip(bridge.customers.getCustomers({ + query: { email: "private-query@example.invalid" }, + responseMode: "response-only" + })) + }), client)) + const printable = [JSON.stringify(error), String(error)].join(" ") + + expect(error).toBeInstanceOf(BridgeHttpError) + expect(error).toMatchObject({ status: 401, method: "GET", requestId: "bridge-response-only-401" }) + expect(printable).not.toContain("private response detail") + expect(printable).not.toContain("private-query@example.invalid") + expect(printable).not.toContain("sk-test-bridge-secret") + expect(calls).toHaveLength(1) + }) + + test("drains non-2xx bodies without decoding them before reporting status", async () => { + let fullyDrained = false + let pulls = 0 + const body = new ReadableStream({ + pull(controller) { + pulls += 1 + if (pulls === 1) { + controller.enqueue(new TextEncoder().encode("not a generated Bridge error")) + } else { + fullyDrained = true + controller.close() + } + } + }) + const client = HttpClient.make((request) => Effect.succeed(HttpClientResponse.fromWeb( + request, + new Response(body, { status: 400, headers: { "content-type": "application/json" } }) + ))) + const error = await Effect.runPromise(withBridge(Effect.gen(function*() { + const bridge = yield* Bridge + return yield* Effect.flip(bridge.customers.getCustomers({ query: {} })) + }), client)) + + expect(error).toBeInstanceOf(BridgeHttpError) + expect(error).toMatchObject({ status: 400, method: "GET" }) + expect(fullyDrained).toBe(true) + }) + + test("sanitizes every deferred response body accessor and facade inspection", async () => { + const accessors = ["json", "text", "urlParamsBody", "arrayBuffer", "formData", "stream"] as const + for (const accessor of accessors) { + const calls: Array = [] + const client = HttpClient.make((request, url, signal) => { + calls.push({ request, url, signal }) + const body = accessor === "json" + ? "malformed JSON containing private-response-body-marker" + : new ReadableStream({ + start(controller) { + controller.error(new Error("private deferred response cause marker")) + } + }) + return Effect.succeed(HttpClientResponse.fromWeb( + request, + new Response(body, { + status: 200, + headers: { + "content-type": "application/json", + "x-request-id": "bridge-deferred-200", + "api-key": "private-response-header-key" + } + }) + )) + }) + const response = await Effect.runPromise(withBridge(Effect.gen(function*() { + const bridge = yield* Bridge + return yield* bridge.customers.getCustomers({ + query: { email: "private-query@example.invalid" }, + responseMode: "response-only" + }) + }), client)) + const deferred = accessor === "stream" + ? Stream.runDrain(response.stream) + : response[accessor] + const error = await Effect.runPromise(Effect.flip(deferred)) + const printedResponse = [ + JSON.stringify(response), + String(response), + JSON.stringify(response[Inspectable.NodeInspectSymbol]()), + JSON.stringify(response.request), + JSON.stringify(Reflect.ownKeys(response)) + ].join(" ") + const printedError = [ + JSON.stringify(error), + String(error), + JSON.stringify(error[Inspectable.NodeInspectSymbol]()) + ].join(" ") + + expect(error).toBeInstanceOf(BridgeSchemaError) + expect(response.status).toBe(200) + expect(response.headers["x-request-id"]).toBe("bridge-deferred-200") + expect(response.headers["api-key"]).toBe("private-response-header-key") + expect(response.request.headers["api-key"]).toBeUndefined() + expect(response.request.url).not.toContain("/customers") + for (const secret of [ + "sk-test-bridge-secret", + "private-query@example.invalid", + "private deferred response cause marker", + "private-response-body-marker", + "private-response-header-key", + "/customers" + ]) { + expect(printedResponse).not.toContain(secret) + expect(printedError).not.toContain(secret) + } + expect(calls).toHaveLength(1) + } + }) + + test("preserves cancellation through a deferred response body stream", async () => { + let canceled = false + let pulls = 0 + let markWaiting: (() => void) | undefined + const waiting = new Promise((resolve) => { + markWaiting = resolve + }) + const body = new ReadableStream({ + pull(controller) { + pulls += 1 + if (pulls === 1) { + controller.enqueue(new Uint8Array([1])) + } else { + markWaiting?.() + } + }, + cancel() { + canceled = true + } + }) + const client = HttpClient.make((request) => Effect.succeed(HttpClientResponse.fromWeb( + request, + new Response(body, { status: 200, headers: { "content-type": "application/pdf" } }) + ))) + const response = await Effect.runPromise(withBridge(Effect.gen(function*() { + const bridge = yield* Bridge + return yield* bridge.customers.getCustomers({ query: {}, responseMode: "response-only" }) + }), client)) + + await Effect.runPromise(Effect.gen(function*() { + const fiber = yield* Effect.forkChild(Stream.runDrain(response.stream)) + yield* Effect.promise(() => waiting) + yield* Fiber.interrupt(fiber) + })) + expect(canceled).toBe(true) + }) + + test("maps non-JSON unrecognized HTTP failures to safe status metadata", async () => { + const calls: Array = [] + const client = mockHttpClient(calls, { + status: 503, + body: "upstream private response text", + headers: { "content-type": "text/plain", "x-request-id": "bridge-request-123" } + }) + const error = await Effect.runPromise(withBridge(Effect.flip(customerList()), client)) + + expect(error).toBeInstanceOf(BridgeHttpError) + expect(error).toMatchObject({ status: 503, method: "GET", requestId: "bridge-request-123" }) + expect(JSON.stringify(error)).not.toContain("upstream private response text") + }) + + test("decodes binary PDFs and bodyless success responses", async () => { + const pdfBytes = Uint8Array.from([37, 80, 68, 70, 45, 49, 46, 55]) + const pdfCalls: Array = [] + const pdfClient = mockHttpClient(pdfCalls, { body: pdfBytes, headers: { "content-type": "application/pdf" } }) + const pdf = await Effect.runPromise(withBridge(Effect.gen(function*() { + const bridge = yield* Bridge + return yield* bridge.cards.postCustomersByCustomerIDCardAccountsByCardAccountIDStatementsPeriodPdf({ + params: { customerID: "cus_test", cardAccountID: "cca_test", period: "2026-09" } + }) + }), pdfClient)) + expect(Array.from(pdf)).toEqual(Array.from(pdfBytes)) + + const emptyCalls: Array = [] + const emptyClient = mockHttpClient(emptyCalls, { status: 200, body: null }) + const result = await Effect.runPromise(withBridge(Effect.gen(function*() { + const bridge = yield* Bridge + return yield* bridge.transfers.deleteTransfersByTransferID({ params: { transferID: "tr_test" } }) + }), emptyClient)) + expect(result).toBeUndefined() + }) + + test("returns response metadata with a request stripped of credentials and body", async () => { + const calls: Array = [] + const client = mockHttpClient(calls, { + body: JSON.stringify({ count: 0, data: [] }), + headers: { "content-type": "application/json", "x-request-id": "bridge-request-456" } + }) + const [, response] = await Effect.runPromise(withBridge(Effect.gen(function*() { + const bridge = yield* Bridge + return yield* bridge.customers.getCustomers({ query: {}, responseMode: "decoded-and-response" }) + }), client)) + const printed = [ + JSON.stringify(response), + String(response), + JSON.stringify(response[Inspectable.NodeInspectSymbol]()), + JSON.stringify(response.request) + ].join(" ") + + expect(response.status).toBe(200) + expect(response.headers["x-request-id"]).toBe("bridge-request-456") + expect(response.request.headers["api-key"]).toBeUndefined() + expect(printed).not.toContain("sk-test-bridge-secret") + expect(printed).not.toContain("/customers") + }) + + test("uses manual redirects in the Fetch layer", async () => { + let callCount = 0 + let redirectMode: string | undefined + const fetch = async (_input: unknown, init?: RequestInit): Promise => { + callCount += 1 + redirectMode = init?.redirect + return new Response(null, { status: 302, headers: { location: "https://attacker.invalid/collect" } }) + } + const layer = bridgeFetchLayer(config()).pipe( + Layer.provideMerge(Layer.succeed(FetchHttpClient.Fetch, fetch as unknown as typeof globalThis.fetch)) + ) + const error = await Effect.runPromise(Effect.gen(function*() { + const bridge = yield* Bridge + return yield* Effect.flip(bridge.customers.getCustomers({ query: {} })) + }).pipe(Effect.provide(layer))) + + expect(error).toBeInstanceOf(BridgeHttpError) + expect(redirectMode).toBe("manual") + expect(callCount).toBe(1) + }) + + test("turns configured timeouts into typed failures and aborts the request", async () => { + let aborted = false + const client = HttpClient.make((_request, _url, signal) => { + signal.addEventListener("abort", () => { + aborted = true + }) + return Effect.never + }) + const exit = await Effect.runPromiseExit(withBridge(customerList(), client, config({ timeoutMs: 1 }))) + + expect(Exit.isFailure(exit)).toBe(true) + if (Exit.isFailure(exit)) expect(Cause.squash(exit.cause)).toBeInstanceOf(BridgeTimeoutError) + expect(aborted).toBe(true) + }) + + test("preserves interruption as cancellation and aborts the in-flight request", async () => { + let aborted = false + let markStarted: (() => void) | undefined + const started = new Promise((resolve) => { + markStarted = resolve + }) + const client = HttpClient.make((_request, _url, signal) => { + signal.addEventListener("abort", () => { + aborted = true + }) + markStarted?.() + return Effect.never + }) + const call = withBridge(customerList(), client) + const exit = await Effect.runPromise(Effect.gen(function*() { + const fiber = yield* Effect.forkChild(call) + yield* Effect.promise(() => started) + yield* Fiber.interrupt(fiber) + return yield* Fiber.await(fiber) + })) + + expect(Exit.isFailure(exit)).toBe(true) + if (Exit.isFailure(exit)) expect(Cause.hasInterrupts(exit.cause)).toBe(true) + expect(aborted).toBe(true) + }) + + test("supports sandbox and custom URLs, and rejects userinfo without echoing it", async () => { + const calls: Array = [] + const client = mockHttpClient(calls, { body: JSON.stringify({ count: 0, data: [] }) }) + await Effect.runPromise(withBridge(customerList(), client, { apiKey, environment: "sandbox" })) + await Effect.runPromise(withBridge(customerList(), client, config({ baseUrl: "https://custom.bridge.test/v0/" }))) + expect(calls.map((call) => call.url.origin)).toEqual(["https://api.sandbox.bridge.xyz", "https://custom.bridge.test"]) + expect(calls[1]?.url.pathname).toBe("/v0/customers") + + const failure = await Effect.runPromise(Effect.flip(Effect.provideService( + Bridge.make(config({ baseUrl: "https://user:secret@bridge.test/v0" })), + HttpClient.HttpClient, + client + ))) + expect(JSON.stringify(failure)).not.toContain("secret") + }) +}) diff --git a/packages/bridge/tests/consumer/consumer.ts b/packages/bridge/tests/consumer/consumer.ts new file mode 100644 index 0000000..7750d88 --- /dev/null +++ b/packages/bridge/tests/consumer/consumer.ts @@ -0,0 +1,64 @@ +import * as Effect from "effect/Effect" +import * as Redacted from "effect/Redacted" +import * as Stream from "effect/Stream" + +import { + Bridge, + BridgeConfigurationError, + BridgeHttpError, + bridgeFetchLayer, + type BridgeClient, + type BridgeConfig +} from "@misofm/bridge" +import { Bridge as BridgeSubpath } from "@misofm/bridge/bridge" +import { BridgeApi, Customer } from "@misofm/bridge/generated" +import { BridgeConfigurationError as ConfigurationErrorSubpath } from "@misofm/bridge/errors" +import { paginateBridge } from "@misofm/bridge/pagination" +import { verifyWebhookSignature, type WebhookEventEnvelope } from "@misofm/bridge/webhooks" + +const config: BridgeConfig = { + apiKey: Redacted.make("example-only-key"), + environment: "sandbox" +} +const layer = bridgeFetchLayer(config) +declare const api: BridgeClient +const customers = api.customers.getCustomers({ query: {} }) +const model = Customer +const contract = BridgeApi +const clientConstructor = Bridge +const alternateClientConstructor = BridgeSubpath +const configFailure = new BridgeConfigurationError({ field: "apiKey" }) +const configFailureFromSubpath = new ConfigurationErrorSubpath({ field: "apiKey" }) +const httpFailure = new BridgeHttpError({ status: 503, method: "GET" }) +const pages = paginateBridge<{ status: string }, { id: string }, never, never>( + { limit: 10, status: "active" }, + () => Effect.succeed({ data: [{ id: "cus_example" }], has_more: false }), + { getId: (customer) => customer.id } +) +const customerPageExample = Effect.gen(function*() { + const bridge = yield* Bridge + const allCustomers = paginateBridge( + { limit: 100 }, + (query) => bridge.customers.getCustomers({ query }), + { + getId: (customer) => + typeof customer === "object" && customer !== null && "id" in customer && + typeof customer.id === "string" + ? customer.id + : undefined + } + ) + return yield* Stream.runCollect(Stream.take(allCustomers, 10)) +}).pipe(Effect.provide(bridgeFetchLayer(config))) +const webhook: WebhookEventEnvelope = { + api_version: "v0", + event_id: "evt_example", + event_category: "future.category", + event_type: "future.event", + event_object: {}, + event_created_at: "2026-09-24T00:00:00Z" +} +const verifier = verifyWebhookSignature + +void [layer, customers, model, contract, clientConstructor, alternateClientConstructor, configFailure, + configFailureFromSubpath, httpFailure, pages, customerPageExample, webhook, verifier] diff --git a/packages/bridge/tests/consumer/package.json b/packages/bridge/tests/consumer/package.json new file mode 100644 index 0000000..ce10314 --- /dev/null +++ b/packages/bridge/tests/consumer/package.json @@ -0,0 +1,16 @@ +{ + "name": "@misofm/bridge-isolated-consumer", + "private": true, + "type": "module", + "scripts": { + "check": "tsc --noEmit -p tsconfig.json && node runtime.mjs", + "check:worker": "tsc -p tsconfig.worker.json && node worker-smoke.mjs" + }, + "dependencies": { + "@misofm/bridge": "file:./bridge.tgz", + "effect": "4.0.0-rc.112" + }, + "devDependencies": { + "typescript": "^7.0.2" + } +} diff --git a/packages/bridge/tests/consumer/runtime.mjs b/packages/bridge/tests/consumer/runtime.mjs new file mode 100644 index 0000000..c5efae8 --- /dev/null +++ b/packages/bridge/tests/consumer/runtime.mjs @@ -0,0 +1,47 @@ +import assert from "node:assert/strict" + +import * as Effect from "effect/Effect" +import * as Layer from "effect/Layer" +import * as Redacted from "effect/Redacted" +import * as HttpClient from "effect/unstable/http/HttpClient" +import * as HttpClientResponse from "effect/unstable/http/HttpClientResponse" + +import { Bridge, bridgeLayer } from "@misofm/bridge" +import { Bridge as BridgeSubpath } from "@misofm/bridge/bridge" +import { BridgeApi } from "@misofm/bridge/generated" +import { BridgeTransportError } from "@misofm/bridge/errors" +import { BridgePaginationLimitError } from "@misofm/bridge/pagination" +import { WebhookError } from "@misofm/bridge/webhooks" + +const calls = [] +const http = HttpClient.make((request, url, signal) => { + calls.push({ request, url, signal }) + return Effect.succeed(HttpClientResponse.fromWeb( + request, + new Response(JSON.stringify({ count: 0, data: [] }), { + status: 200, + headers: { "content-type": "application/json" } + }) + )) +}) +const layer = bridgeLayer({ + apiKey: Redacted.make("node-consumer-test-key"), + baseUrl: "https://bridge.test/v0" +}).pipe(Layer.provide(Layer.succeed(HttpClient.HttpClient, http))) +const result = await Effect.runPromise(Effect.gen(function*() { + const bridge = yield* Bridge + return yield* bridge.customers.getCustomers({ query: {} }) +}).pipe(Effect.provide(layer))) + +assert.equal(result.count, 0) +assert.equal(result.data.length, 0) +assert.equal(calls.length, 1) +assert.equal(calls[0].url.href, "https://bridge.test/v0/customers") +assert.equal(calls[0].request.headers["api-key"], "node-consumer-test-key") +assert.equal(typeof BridgeApi, "function") +assert.equal(BridgeSubpath, Bridge) +assert.equal(BridgeTransportError.name, "BridgeTransportError") +assert.equal(BridgePaginationLimitError.name, "BridgePaginationLimitError") +assert.equal(WebhookError.name, "WebhookError") + +console.log("Bridge packed Node ESM consumer: OK") diff --git a/packages/bridge/tests/consumer/tsconfig.json b/packages/bridge/tests/consumer/tsconfig.json new file mode 100644 index 0000000..cd65c7a --- /dev/null +++ b/packages/bridge/tests/consumer/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "target": "ES2022", + "lib": ["ES2022", "DOM"], + "module": "NodeNext", + "moduleResolution": "NodeNext", + "strict": true, + "skipLibCheck": true, + "exactOptionalPropertyTypes": true, + "noEmit": true + }, + "include": ["consumer.ts"] +} diff --git a/packages/bridge/tests/consumer/tsconfig.worker.json b/packages/bridge/tests/consumer/tsconfig.worker.json new file mode 100644 index 0000000..14e95eb --- /dev/null +++ b/packages/bridge/tests/consumer/tsconfig.worker.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2022", + "lib": ["ES2022", "DOM"], + "module": "NodeNext", + "moduleResolution": "NodeNext", + "strict": true, + "skipLibCheck": true, + "exactOptionalPropertyTypes": true, + "outDir": "worker-build", + "rootDir": ".", + "types": [] + }, + "include": ["worker.ts"] +} diff --git a/packages/bridge/tests/consumer/worker-smoke.mjs b/packages/bridge/tests/consumer/worker-smoke.mjs new file mode 100644 index 0000000..3b7c6ff --- /dev/null +++ b/packages/bridge/tests/consumer/worker-smoke.mjs @@ -0,0 +1,31 @@ +import assert from "node:assert/strict" + +import worker from "./worker-build/worker.js" + +const originalFetch = globalThis.fetch +let observed +globalThis.fetch = async (input, init) => { + observed = { input: String(input), init } + return new Response(JSON.stringify({ count: 1, data: [{ id: "cus_worker_test" }] }), { + status: 200, + headers: { "content-type": "application/json" } + }) +} + +try { + const request = new Request("https://worker.test/customers") + const response = await worker.fetch(request, { + BRIDGE_API_KEY: "worker-invocation-test-key", + BRIDGE_ENVIRONMENT: "sandbox" + }) + assert.equal(response.status, 200) + assert.deepEqual(await response.json(), { count: 1, data: [{ id: "cus_worker_test" }] }) + assert.equal(observed.input, "https://api.sandbox.bridge.xyz/v0/customers") + assert.equal(new Headers(observed.init?.headers).get("api-key"), "worker-invocation-test-key") + assert.equal((await worker.fetch(new Request("https://worker.test/other"), { + BRIDGE_API_KEY: "unused" + })).status, 404) + console.log("Bridge Cloudflare Worker mocked smoke: OK") +} finally { + globalThis.fetch = originalFetch +} diff --git a/packages/bridge/tests/contract-types.ts b/packages/bridge/tests/contract-types.ts new file mode 100644 index 0000000..7afff62 --- /dev/null +++ b/packages/bridge/tests/contract-types.ts @@ -0,0 +1,89 @@ +// Compile-only examples: these calls are never run and have no live credentials. +import type { BridgeClient } from "../src/Bridge" + +export const typecheckRepresentativeFlow = (client: BridgeClient): void => { + client.customers.postCustomers({ + headers: { "Idempotency-Key": "fixture-customer-create" }, + payload: { + type: "individual", + first_name: "Miso", + last_name: "Fixture", + email: "miso.fixture@example.invalid" + } + }) + client.kycLinks.postKycLinks({ + headers: { "Idempotency-Key": "fixture-kyc-link" }, + payload: { + type: "individual", + full_name: "Miso Fixture", + email: "miso.fixture@example.invalid" + } + }) + client.bridgeWallets.postCustomersByCustomerIDWallets({ + params: { customerID: "custfixture01" }, + headers: { "Idempotency-Key": "fixture-wallet-create" }, + payload: { chain: "ethereum" } + }) + client.transfers.postTransfers({ + headers: { "Idempotency-Key": "fixture-transfer-create" }, + payload: { + on_behalf_of: "custfixture01", + amount: "12.34", + source: { currency: "usdc", payment_rail: "ethereum", bridge_wallet_id: "walletfixture01" }, + destination: { currency: "usd", payment_rail: "ach", external_account_id: "acctfixture01" } + } + }) + client.cards.postCustomersByCustomerIDCardAccountsByCardAccountIDEphemeralKeys({ + params: { customerID: "custfixture01", cardAccountID: "cardfixture01" }, + headers: { "Idempotency-Key": "fixture-ephemeral-key" }, + payload: undefined + }) + client.cards.postCustomersByCustomerIDCardAccountsByCardAccountIDFreeze({ + params: { customerID: "custfixture01", cardAccountID: "cardfixture01" }, + headers: { "Idempotency-Key": "fixture-card-freeze" }, + payload: undefined + }) + client.cards.postCustomersByCustomerIDCardAccountsByCardAccountIDUnfreeze({ + params: { customerID: "custfixture01", cardAccountID: "cardfixture01" }, + headers: { "Idempotency-Key": "fixture-card-unfreeze" }, + payload: undefined + }) + client.cards.postCustomersByCustomerIDCardAccountsByCardAccountIDCreateMobileWalletProvisioningRequest({ + params: { customerID: "custfixture01", cardAccountID: "cardfixture01" }, + headers: { "Idempotency-Key": "fixture-wallet-provisioning" }, + payload: undefined + }) + client.liquidationAddresses.postCustomersByCustomerIDLiquidationAddresses({ + params: { customerID: "custfixture01" }, + headers: { "Idempotency-Key": "fixture-liquidation-address" }, + payload: { + currency: "usdc", + chain: "ethereum", + external_account_id: "acctfixture01", + destination_payment_rail: "ach", + destination_currency: "usd" + } + }) +} + +export const typecheckRejectedWireShapes = (client: BridgeClient): void => { + client.transfers.postTransfers({ + headers: { "Idempotency-Key": "fixture-invalid-decimal" }, + payload: { + on_behalf_of: "custfixture01", + // @ts-expect-error Bridge decimal wire amounts are strings, never JavaScript numbers. + amount: 12.34, + source: { currency: "usdc", payment_rail: "ethereum", bridge_wallet_id: "walletfixture01" }, + destination: { currency: "usd", payment_rail: "ach", external_account_id: "acctfixture01" } + } + }) + client.cards.postCustomersByCustomerIDCardAccounts({ + params: { customerID: "custfixture01" }, + headers: { "Idempotency-Key": "fixture-invalid-card-currency" }, + payload: { + // @ts-expect-error Card account currency is constrained by the upstream literal union. + currency: "usd", + chain: "ethereum" + } + }) +} diff --git a/packages/bridge/tests/contracts.test.ts b/packages/bridge/tests/contracts.test.ts new file mode 100644 index 0000000..b5a86ba --- /dev/null +++ b/packages/bridge/tests/contracts.test.ts @@ -0,0 +1,577 @@ +import { describe, expect, test } from "bun:test" +import * as Effect from "effect/Effect" +import * as Layer from "effect/Layer" +import * as Redacted from "effect/Redacted" +import * as Schema from "effect/Schema" +import * as HttpClient from "effect/unstable/http/HttpClient" +import { Bridge } from "../src/Bridge.js" +import * as BridgeSchemas from "../src/generated/BridgeApi" +import { controlledHttpClient, requestJson } from "./support/controlled-http" +import { + isRecord, + listOperations +} from "./support/openapi" + +type FormerNeverModelName = + | "ExternalAccountResponse" + | "CreateExternalAccountInput" + | "CreateLiquidationAddressResponse" + | "FeeExternalAccount" + | "CreateFeeExternalAccountInput" + | "CardAccount" + +interface ContractFixtures { + readonly customer: unknown + readonly kycLink: unknown + readonly wallet: unknown + readonly externalAccount: unknown + readonly transfer: unknown + readonly webhook: unknown + readonly responses: Readonly> +} + +interface MajorFamilyFixtures { + readonly liquidationAddressRequest: unknown + readonly liquidationAddressResponse: unknown + readonly cardAccountRequest: unknown + readonly cardAccountResponse: unknown + readonly cardFreezeResponse: unknown + readonly prefundedAccount: unknown + readonly webhooks: unknown + readonly developerFees: unknown + readonly countries: unknown +} + +interface NestedResponseFixtures { + readonly endorsement: unknown + readonly virtualAccountInstructions: Readonly> + readonly cardProgramSummary: unknown + readonly deactivateResponse: unknown +} + +const flow = JSON.parse( + await Bun.file(new URL("./fixtures/contracts/representative-flow.json", import.meta.url)).text() +) as ContractFixtures +const formerNeverModelFixtures = JSON.parse( + await Bun.file(new URL("./fixtures/contracts/never-models.json", import.meta.url)).text() +) as Record +const familyFixtures = JSON.parse( + await Bun.file(new URL("./fixtures/contracts/major-families.json", import.meta.url)).text() +) as MajorFamilyFixtures +const nestedResponseFixtures = JSON.parse( + await Bun.file(new URL("./fixtures/nested-response-schemas.json", import.meta.url)).text() +) as NestedResponseFixtures +const rawSpec = JSON.parse( + await Bun.file(new URL("../openapi/bridge-2026-09-23.json", import.meta.url)).text() +) as unknown + +const componentExampleValue = (name: string): unknown => { + const components = isRecord(rawSpec) && isRecord(rawSpec.components) ? rawSpec.components : {} + const examples = isRecord(components.examples) ? components.examples : {} + const example = examples[name] + if (!isRecord(example) || !("value" in example)) { + throw new Error(`Expected pinned OpenAPI component example ${name}`) + } + return example.value +} + +const responseExampleValue = (path: string, method: string, status: string, name: string): unknown => { + const paths = isRecord(rawSpec) && isRecord(rawSpec.paths) ? rawSpec.paths : {} + const pathItem = isRecord(paths[path]) ? paths[path] : {} + const operation = isRecord(pathItem[method]) ? pathItem[method] : {} + const responses = isRecord(operation.responses) ? operation.responses : {} + const response = isRecord(responses[status]) ? responses[status] : {} + const content = isRecord(response.content) ? response.content : {} + const json = isRecord(content["application/json"]) ? content["application/json"] : {} + const examples = isRecord(json.examples) ? json.examples : {} + const example = examples[name] + if (!isRecord(example) || !("value" in example)) { + throw new Error(`Expected pinned OpenAPI response example ${method.toUpperCase()} ${path} ${status} ${name}`) + } + return example.value +} + +const schemaReferences = (value: unknown, into = new Set()): Set => { + if (Array.isArray(value)) { + for (const item of value) schemaReferences(item, into) + } else if (isRecord(value)) { + if (typeof value.$ref === "string" && value.$ref.startsWith("#/components/schemas/")) { + into.add(value.$ref.slice("#/components/schemas/".length)) + } + for (const nested of Object.values(value)) schemaReferences(nested, into) + } + return into +} + +const keyOf = (method: string, path: string): string => `${method} ${path}` + +const fixtureBridgeLayer = (client: HttpClient.HttpClient) => + Bridge.layer({ + apiKey: Redacted.make("sk-test-bridge-contract-fixture"), + baseUrl: "https://bridge.fixture/v0" + }).pipe(Layer.provide(Layer.succeed(HttpClient.HttpClient, client))) + +const requireStringField = (value: unknown, key: string): string => { + if (!isRecord(value) || typeof value[key] !== "string") throw new Error(`Expected fixture field ${key} to be a string`) + return value[key] +} + +type UsAchExternalAccountInput = Extract< + BridgeSchemas.CreateExternalAccountInput, + { readonly currency: "usd"; readonly account_type: "us" } +> + +const isUsAchExternalAccountInput = ( + value: BridgeSchemas.CreateExternalAccountInput +): value is UsAchExternalAccountInput => + isRecord(value) && value.currency === "usd" && value.account_type === "us" + +const repairedModelCases: ReadonlyArray<{ + readonly name: FormerNeverModelName + readonly schema: Schema.Constraint + readonly operations: ReadonlyArray +}> = [ + { + name: "ExternalAccountResponse", + schema: BridgeSchemas.ExternalAccountResponse, + operations: [ + "delete /customers/{customerID}/external_accounts/{externalAccountID}", + "get /customers/{customerID}/external_accounts", + "get /customers/{customerID}/external_accounts/{externalAccountID}", + "get /external_accounts", + "post /customers/{customerID}/external_accounts", + "post /customers/{customerID}/external_accounts/{externalAccountID}/deactivate", + "post /customers/{customerID}/external_accounts/{externalAccountID}/reactivate", + "put /customers/{customerID}/external_accounts/{externalAccountID}" + ] + }, + { + name: "CreateExternalAccountInput", + schema: BridgeSchemas.CreateExternalAccountInput, + operations: ["post /customers/{customerID}/external_accounts"] + }, + { + name: "CreateLiquidationAddressResponse", + schema: BridgeSchemas.CreateLiquidationAddressResponse, + operations: ["post /customers/{customerID}/liquidation_addresses"] + }, + { + name: "FeeExternalAccount", + schema: BridgeSchemas.FeeExternalAccount, + operations: ["get /developer/fee_external_account", "post /developer/fee_external_account"] + }, + { + name: "CreateFeeExternalAccountInput", + schema: BridgeSchemas.CreateFeeExternalAccountInput, + operations: ["post /developer/fee_external_account"] + }, + { + name: "CardAccount", + schema: BridgeSchemas.CardAccount, + operations: [ + "get /customers/{customerID}/card_accounts", + "get /customers/{customerID}/card_accounts/{cardAccountID}", + "post /customers/{customerID}/card_accounts", + "put /customers/{customerID}/card_accounts/{cardAccountID}" + ] + } +] + +const expectedRepairedModelUses: Record> = { + ExternalAccountResponse: [ + "delete /customers/{customerID}/external_accounts/{externalAccountID}", + "get /customers/{customerID}/external_accounts", + "get /customers/{customerID}/external_accounts/{externalAccountID}", + "get /external_accounts", + "post /customers/{customerID}/external_accounts", + "post /customers/{customerID}/external_accounts/{externalAccountID}/deactivate", + "post /customers/{customerID}/external_accounts/{externalAccountID}/reactivate", + "put /customers/{customerID}/external_accounts/{externalAccountID}" + ], + CreateExternalAccountInput: ["post /customers/{customerID}/external_accounts"], + CreateLiquidationAddressResponse: ["post /customers/{customerID}/liquidation_addresses"], + FeeExternalAccount: ["get /developer/fee_external_account", "post /developer/fee_external_account"], + CreateFeeExternalAccountInput: ["post /developer/fee_external_account"], + CardAccount: [ + "get /customers/{customerID}/card_accounts", + "get /customers/{customerID}/card_accounts/{cardAccountID}", + "post /customers/{customerID}/card_accounts", + "put /customers/{customerID}/card_accounts/{cardAccountID}" + ] +} + +describe("Bridge contract fixtures", () => { + test("the Miso customer → KYC → wallet → transfer request shapes decode from generated schemas", () => { + expect(Schema.is(BridgeSchemas.PostCustomersRequestJson)(flow.customer)).toBe(true) + expect(Schema.is(BridgeSchemas.PostKycLinksRequestJson)(flow.kycLink)).toBe(true) + expect(Schema.is(BridgeSchemas.PostCustomersByCustomerIDWalletsRequestJson)(flow.wallet)).toBe(true) + expect(Schema.is(BridgeSchemas.PostTransfersRequestJson)(flow.transfer)).toBe(true) + }) + + test("the webhook example accepts a populated event object and changes map", () => { + expect(Schema.is(BridgeSchemas.WebhookEvent)(flow.webhook)).toBe(true) + if (isRecord(flow.webhook)) { + expect(Schema.is(BridgeSchemas.WebhookEvent)({ ...flow.webhook, event_type: "customer.created" })).toBe(false) + } + if (isRecord(flow.transfer)) { + expect(Schema.is(BridgeSchemas.PostTransfersRequestJson)({ ...flow.transfer, amount: 12.34 })).toBe(false) + } + expect(Schema.is(BridgeSchemas.PostCustomersByCustomerIDCardAccountsRequestJson)({ + currency: "usd", + chain: "ethereum" + })).toBe(false) + }) + + test("published customer examples decode while unresolved response examples remain rejected", () => { + const businessCustomer = componentExampleValue("SuccessfulCustomerResponse2") + expect(Schema.is(BridgeSchemas.Customer)(businessCustomer)).toBe(true) + if (isRecord(businessCustomer)) { + // The output-only overlay admits the exact published nullable surname and + // structured completed requirement, while the create request remains strict. + expect(businessCustomer.last_name).toBeNull() + } + if (isRecord(flow.customer)) { + expect(Schema.is(BridgeSchemas.PostCustomersRequestJson)({ ...flow.customer, last_name: null })).toBe(false) + } + + const noCustomers = responseExampleValue("/customers", "get", "200", "NoCustomersFound") + expect(Schema.is(BridgeSchemas.GetCustomers200)(noCustomers)).toBe(true) + const customersFound = responseExampleValue("/customers", "get", "200", "CustomersFound") + expect(Schema.is(BridgeSchemas.GetCustomers200)(customersFound)).toBe(true) + + const transfer = componentExampleValue("AchOfframpTransferResponse") + expect(Schema.is(BridgeSchemas.PostTransfers201)(transfer)).toBe(false) + if (isRecord(transfer)) { + // The documented sample otherwise matches TransferResponse; its missing required currency is the conflict. + expect(Schema.is(BridgeSchemas.PostTransfers201)({ ...transfer, currency: "usd" })).toBe(true) + } + + const pendingVerification = responseExampleValue( + "/customers/{customerID}/external_accounts/{externalAccountID}/verify", + "post", + "200", + "PendingIbanVerification" + ) + expect(Schema.is(BridgeSchemas.PostCustomersByCustomerIDExternalAccountsByExternalAccountIDVerify200)(pendingVerification)).toBe(false) + + const virtualAccount = responseExampleValue("/customers/{customerID}/virtual_accounts", "post", "200", "us") + expect(Schema.is(BridgeSchemas.PostCustomersByCustomerIDVirtualAccounts200)(virtualAccount)).toBe(false) + + const kycLink = componentExampleValue("SuccessfulKycLinkCreateResponse") + expect(Schema.is(BridgeSchemas.PostKycLinks200)(kycLink)).toBe(true) + if (isRecord(kycLink)) expect(kycLink.kyc_status).toBe("not_started") + + const createdWallet = componentExampleValue("SuccessfulBridgeWalletCreateResponse") + expect(Schema.is(BridgeSchemas.PostCustomersByCustomerIDWallets201)(createdWallet)).toBe(true) + const walletList = componentExampleValue("SuccessfulBridgeWalletListResponse") + expect(Schema.is(BridgeSchemas.GetCustomersByCustomerIDWallets200)(walletList)).toBe(true) + const wallet = componentExampleValue("SuccessfulBridgeWalletGetResponse") + expect(Schema.is(BridgeSchemas.GetCustomersByCustomerIDWalletsByBridgeWalletID200)(wallet)).toBe(true) + }) + + test("T1b nested response fixtures decode through the public generated schemas", () => { + expect(Schema.is(BridgeSchemas.Customer)({ endorsements: [nestedResponseFixtures.endorsement] })).toBe(true) + if (isRecord(nestedResponseFixtures.endorsement)) { + const requirements = isRecord(nestedResponseFixtures.endorsement.requirements) + ? nestedResponseFixtures.endorsement.requirements + : {} + expect(Schema.is(BridgeSchemas.Customer)({ + endorsements: [{ + ...nestedResponseFixtures.endorsement, + requirements: { ...requirements, missing: null } + }] + })).toBe(true) + expect(Schema.is(BridgeSchemas.Customer)({ + endorsements: [{ + ...nestedResponseFixtures.endorsement, + requirements: { ...requirements, issues: [{ id_front_photo: 404 }] } + }] + })).toBe(false) + } + + const railNames = ["us", "eu", "mx", "br", "gb", "co"] + expect(Object.keys(nestedResponseFixtures.virtualAccountInstructions).sort()).toEqual(railNames.sort()) + for (const instructions of Object.values(nestedResponseFixtures.virtualAccountInstructions)) { + expect(Schema.is(BridgeSchemas.VirtualAccountResponse)({ source_deposit_instructions: instructions })).toBe(true) + } + + expect(Schema.is(BridgeSchemas.CardProgramSummary)(nestedResponseFixtures.cardProgramSummary)).toBe(true) + if (isRecord(nestedResponseFixtures.cardProgramSummary)) { + expect(Schema.is(BridgeSchemas.CardProgramSummary)({ + ...nestedResponseFixtures.cardProgramSummary, + provisioned_cards_by_country: { USA: "123" } + })).toBe(false) + expect(Schema.is(BridgeSchemas.CardProgramSummary)({ + ...nestedResponseFixtures.cardProgramSummary, + transaction_volume_by_country: { USA: 7.04 } + })).toBe(false) + } + expect(Schema.is(BridgeSchemas.PostCustomersByCustomerIDVirtualAccountsByVirtualAccountIDDeactivate200)( + nestedResponseFixtures.deactivateResponse + )).toBe(true) + }) + + test("the generated client carries the Miso customer → KYC → wallet/external account → transfer → webhook path", async () => { + const responseFixtures = [ + { method: "POST", path: "/v0/customers", status: 201, body: flow.responses.customer }, + { method: "POST", path: "/v0/kyc_links", status: 200, body: flow.responses.kycLink }, + { method: "POST", path: "/v0/customers/custfixture01/wallets", status: 201, body: flow.responses.wallet }, + { + method: "POST", + path: "/v0/customers/custfixture01/external_accounts", + status: 201, + body: formerNeverModelFixtures.ExternalAccountResponse + }, + { method: "POST", path: "/v0/transfers", status: 201, body: flow.responses.transfer }, + { + method: "GET", + path: "/v0/webhooks/wep_c0ffee1234/events", + body: { data: [flow.webhook] } + } + ] as const + const fake = controlledHttpClient(responseFixtures) + const customerPayload = Schema.decodeUnknownSync(BridgeSchemas.PostCustomersRequestJson)(flow.customer) + if (customerPayload.type !== "individual") { + throw new Error("The Miso workflow fixture must be the individual-customer request variant") + } + const kycPayload = Schema.decodeUnknownSync(BridgeSchemas.PostKycLinksRequestJson)(flow.kycLink) + const walletPayload = Schema.decodeUnknownSync(BridgeSchemas.PostCustomersByCustomerIDWalletsRequestJson)(flow.wallet) + const decodedExternalAccountPayload = Schema.decodeUnknownSync(BridgeSchemas.CreateExternalAccountInput)(flow.externalAccount) + if (!isUsAchExternalAccountInput(decodedExternalAccountPayload)) { + throw new Error("The Miso workflow fixture must be the ACH external-account request variant") + } + const transferAmount = requireStringField(flow.transfer, "amount") + const webhookEvent = Schema.decodeUnknownSync(BridgeSchemas.WebhookEvent)(flow.webhook) + + const outcome = await Effect.runPromise(Effect.gen(function*() { + const bridge = yield* Bridge + const customer = yield* bridge.customers.postCustomers({ + headers: { "Idempotency-Key": "miso-fixture-customer" }, + payload: customerPayload + }) + const customerID = requireStringField(customer, "id") + const kycLink = yield* bridge.kycLinks.postKycLinks({ + headers: { "Idempotency-Key": "miso-fixture-kyc" }, + payload: kycPayload + }) + const wallet = yield* bridge.bridgeWallets.postCustomersByCustomerIDWallets({ + params: { customerID }, + headers: { "Idempotency-Key": "miso-fixture-wallet" }, + payload: walletPayload + }) + const walletID = requireStringField(wallet, "id") + const externalAccount = yield* bridge.externalAccounts.postCustomersByCustomerIDExternalAccounts({ + params: { customerID }, + headers: { "Idempotency-Key": "miso-fixture-external-account" }, + payload: decodedExternalAccountPayload + }) + const externalAccountID = requireStringField(externalAccount, "id") + const transfer = yield* bridge.transfers.postTransfers({ + headers: { "Idempotency-Key": "miso-fixture-transfer" }, + payload: { + on_behalf_of: customerID, + amount: transferAmount, + source: { currency: "usdc", payment_rail: "ethereum", bridge_wallet_id: walletID }, + destination: { currency: "usd", payment_rail: "ach", external_account_id: externalAccountID } + } satisfies BridgeSchemas.TransferRequest + }) + const events = yield* bridge.webhooks.getWebhooksByWebhookIDEvents({ + params: { webhookID: "wep_c0ffee1234" } + }) + return { customer, kycLink, wallet, externalAccount, transfer, events } + }).pipe(Effect.provide(fixtureBridgeLayer(fake.client)))) + + expect(outcome.customer).toMatchObject({ id: "custfixture01", type: "individual" }) + expect(outcome.kycLink).toMatchObject({ customer_id: "custfixture01", kyc_status: "not_started" }) + expect(outcome.wallet).toMatchObject({ id: "walletfixture01", chain: "ethereum" }) + expect(outcome.externalAccount).toMatchObject({ id: "acctfixture01", active: true }) + expect(outcome.transfer).toMatchObject({ id: "transferfixture01", amount: "12.34", state: "awaiting_funds" }) + expect(outcome.events).toEqual({ data: [webhookEvent] }) + expect(fake.calls.map(({ request, url }) => [request.method, url.pathname])).toEqual([ + ["POST", "/v0/customers"], + ["POST", "/v0/kyc_links"], + ["POST", "/v0/customers/custfixture01/wallets"], + ["POST", "/v0/customers/custfixture01/external_accounts"], + ["POST", "/v0/transfers"], + ["GET", "/v0/webhooks/wep_c0ffee1234/events"] + ]) + for (const call of fake.calls.slice(0, 5)) { + expect(call.request.headers["api-key"]).toBe("sk-test-bridge-contract-fixture") + expect(call.request.headers["idempotency-key"]).toBeTruthy() + } + expect(requestJson(fake.calls[0]!.request)).toEqual(flow.customer) + expect(requestJson(fake.calls[1]!.request)).toEqual(flow.kycLink) + expect(requestJson(fake.calls[2]!.request)).toEqual(flow.wallet) + expect(requestJson(fake.calls[3]!.request)).toEqual(flow.externalAccount) + expect(requestJson(fake.calls[4]!.request)).toMatchObject({ + on_behalf_of: "custfixture01", + source: { bridge_wallet_id: "walletfixture01" }, + destination: { external_account_id: "acctfixture01" }, + amount: "12.34" + }) + }) + + test("strict fake fixtures exercise prefund, collection, cards, webhooks, developer admin, and supporting information", async () => { + const fake = controlledHttpClient([ + { + method: "GET", + path: "/v0/prefunded_accounts/f15972de-4cdd-460c-9da3-34f7321bfa3f", + body: familyFixtures.prefundedAccount + }, + { + method: "POST", + path: "/v0/customers/custfixture01/liquidation_addresses", + status: 201, + body: familyFixtures.liquidationAddressResponse + }, + { + method: "POST", + path: "/v0/customers/custfixture01/card_accounts", + status: 201, + body: familyFixtures.cardAccountResponse + }, + { + method: "POST", + path: "/v0/customers/custfixture01/card_accounts/cardfixture01/freeze", + body: familyFixtures.cardFreezeResponse + }, + { method: "GET", path: "/v0/webhooks", body: familyFixtures.webhooks }, + { method: "GET", path: "/v0/developer/fees", body: familyFixtures.developerFees }, + { method: "GET", path: "/v0/lists/countries", body: familyFixtures.countries } + ]) + const liquidationAddressPayload = Schema.decodeUnknownSync(BridgeSchemas.PostCustomersByCustomerIDLiquidationAddressesRequestJson)( + familyFixtures.liquidationAddressRequest + ) + const cardAccountPayload = Schema.decodeUnknownSync(BridgeSchemas.PostCustomersByCustomerIDCardAccountsRequestJson)( + familyFixtures.cardAccountRequest + ) + const expectedWebhooks = Schema.decodeUnknownSync(BridgeSchemas.GetWebhooks200)(familyFixtures.webhooks) + const expectedDeveloperFees = Schema.decodeUnknownSync(BridgeSchemas.DeveloperFees)(familyFixtures.developerFees) + const expectedCountries = Schema.decodeUnknownSync(BridgeSchemas.GetListsCountries200)(familyFixtures.countries) + const results = await Effect.runPromise(Effect.gen(function*() { + const bridge = yield* Bridge + const prefundedAccount = yield* bridge.prefundedAccounts.getPrefundedAccountsByPrefundedAccountID({ + params: { prefundedAccountID: "f15972de-4cdd-460c-9da3-34f7321bfa3f" } + }) + const liquidationAddress = yield* bridge.liquidationAddresses.postCustomersByCustomerIDLiquidationAddresses({ + params: { customerID: "custfixture01" }, + headers: { "Idempotency-Key": "miso-fixture-liquidation-address" }, + payload: liquidationAddressPayload + }) + const cardAccount = yield* bridge.cards.postCustomersByCustomerIDCardAccounts({ + params: { customerID: "custfixture01" }, + headers: { "Idempotency-Key": "miso-fixture-card-account" }, + payload: cardAccountPayload + }) + const cardFreeze = yield* bridge.cards.postCustomersByCustomerIDCardAccountsByCardAccountIDFreeze({ + params: { customerID: "custfixture01", cardAccountID: "cardfixture01" }, + headers: { "Idempotency-Key": "miso-fixture-card-freeze" }, + payload: undefined + }) + const webhooks = yield* bridge.webhooks.getWebhooks({}) + const developerFees = yield* bridge.developers.getDeveloperFees({}) + const countries = yield* bridge.lists.getListsCountries({}) + return { prefundedAccount, liquidationAddress, cardAccount, cardFreeze, webhooks, developerFees, countries } + }).pipe(Effect.provide(fixtureBridgeLayer(fake.client)))) + + expect(results.prefundedAccount).toMatchObject({ id: "f15972de-4cdd-460c-9da3-34f7321bfa3f", available_balance: "134.12" }) + expect(results.liquidationAddress).toMatchObject({ id: "lafixture01", destination_currency: "usd" }) + expect(results.cardAccount).toMatchObject({ id: "cardfixture01", status: "active" }) + expect(results.cardFreeze).toMatchObject({ status: "freeze_created", card_account_id: "cardfixture01" }) + expect(results.webhooks).toEqual(expectedWebhooks) + expect(results.developerFees).toEqual(expectedDeveloperFees) + expect(results.countries).toEqual(expectedCountries) + expect(fake.calls.map(({ request, url }) => [request.method, url.pathname])).toEqual([ + ["GET", "/v0/prefunded_accounts/f15972de-4cdd-460c-9da3-34f7321bfa3f"], + ["POST", "/v0/customers/custfixture01/liquidation_addresses"], + ["POST", "/v0/customers/custfixture01/card_accounts"], + ["POST", "/v0/customers/custfixture01/card_accounts/cardfixture01/freeze"], + ["GET", "/v0/webhooks"], + ["GET", "/v0/developer/fees"], + ["GET", "/v0/lists/countries"] + ]) + expect(requestJson(fake.calls[1]!.request)).toEqual(familyFixtures.liquidationAddressRequest) + expect(requestJson(fake.calls[2]!.request)).toEqual(familyFixtures.cardAccountRequest) + for (const call of [fake.calls[1], fake.calls[2], fake.calls[3]]) { + expect(call?.request.headers["api-key"]).toBe("sk-test-bridge-contract-fixture") + expect(call?.request.headers["idempotency-key"]).toBeTruthy() + } + expect(fake.calls[3]!.request.body._tag).toBe("Empty") + expect(fake.calls[3]!.request.headers["content-type"]).toBeUndefined() + }) + + test("documented external-account rail examples decode in their request and response directions", () => { + const components = isRecord(rawSpec) && isRecord(rawSpec.components) ? rawSpec.components : {} + const examples = isRecord(components.examples) ? components.examples : {} + const requestExamples = [ + "CreateAchExternalAccountRequest", + "CreateIbanExternalAccountRequest", + "CreateClabeExternalAccountRequest", + "CreatePixExternalAccountRequest", + "CreateBrCodeExternalAccountRequest", + "CreateBreBExternalAccountRequest", + "CreateCoBankTransferExternalAccountRequest" + ] + const responseExamples = [ + "SuccessfulExternalAccountResponse", + "SuccessfulFeeExternalAccountResponse", + "SuccessfulIbanExternalAccountResponse", + "SuccessfulPixKeyExternalAccountResponse", + "SuccessfulBrCodeExternalAccountResponse", + "SuccessfulBreBExternalAccountResponse", + "SuccessfulCoBankTransferExternalAccountResponse", + "SuccessfulClabeExternalAccountResponse" + ] + + for (const name of requestExamples) { + const example = examples[name] + expect(isRecord(example) && "value" in example).toBe(true) + if (isRecord(example)) expect(Schema.is(BridgeSchemas.CreateExternalAccountInput)(example.value)).toBe(true) + } + for (const name of responseExamples) { + const example = examples[name] + expect(isRecord(example) && "value" in example).toBe(true) + if (isRecord(example)) { + const schema = name === "SuccessfulFeeExternalAccountResponse" + ? BridgeSchemas.FeeExternalAccount + : BridgeSchemas.ExternalAccountResponse + expect(Schema.is(schema)(example.value)).toBe(true) + } + } + }) + + test("the documented SEPA liquidation-address response example decodes", () => { + const components = isRecord(rawSpec) && isRecord(rawSpec.components) ? rawSpec.components : {} + const examples = isRecord(components.examples) ? components.examples : {} + const example = examples.SuccessfulSepaLiquidationAddressCreateResponse + expect(isRecord(example) && "value" in example).toBe(true) + if (isRecord(example)) { + expect(Schema.is(BridgeSchemas.CreateLiquidationAddressResponse)(example.value)).toBe(true) + } + }) + + test("the original top-level Schema.Never cases map to the exact repaired operation sites", () => { + const actualUses = new Map>() + for (const { method, path, operation } of listOperations(rawSpec)) { + const refs = schemaReferences(operation) + for (const { name } of repairedModelCases) { + if (refs.has(name)) { + const uses = actualUses.get(name) ?? [] + uses.push(keyOf(method, path)) + actualUses.set(name, uses) + } + } + } + + for (const { name } of repairedModelCases) { + expect((actualUses.get(name) ?? []).sort()).toEqual([...expectedRepairedModelUses[name]]) + } + }) + + for (const { name, schema, operations } of repairedModelCases) { + test(`${name} accepts its documented non-empty fixture (${operations.join(", ")})`, () => { + const fixture = name === "CreateExternalAccountInput" ? flow.externalAccount : formerNeverModelFixtures[name] + expect(Schema.is(schema)(fixture)).toBe(true) + }) + } +}) diff --git a/packages/bridge/tests/coverage.test.ts b/packages/bridge/tests/coverage.test.ts new file mode 100644 index 0000000..85a88f3 --- /dev/null +++ b/packages/bridge/tests/coverage.test.ts @@ -0,0 +1,131 @@ +import { describe, expect, test } from "bun:test" +import { OpenApi } from "effect/unstable/httpapi" +import { BridgeApi } from "../src/generated/BridgeApi" +import { + asArray, + asRecord, + getParameters, + listOperations, + responseMediaTypes, + resolveLocalRef +} from "./support/openapi" + +const rawSpec = JSON.parse(await Bun.file(new URL("../openapi/bridge-2026-09-23.json", import.meta.url)).text()) as unknown +const manifest = JSON.parse(await Bun.file(new URL("../openapi/operation-manifest.json", import.meta.url)).text()) as unknown +const generated = OpenApi.fromApi(BridgeApi) as unknown +const generatedSource = await Bun.file(new URL("../src/generated/BridgeApi.ts", import.meta.url)).text() + +const manifestRecord = asRecord(manifest) +const sourceOperations = listOperations(rawSpec) +const manifestOperations = asArray(manifestRecord.operations).map(asRecord) +const generatedPaths = asRecord(asRecord(generated).paths) +const manifestByKey = new Map( + manifestOperations.map((entry) => [`${entry.method} ${entry.path}`, entry] as const) +) + +type OperationKey = `${string} ${string}` + +const keyOf = (method: unknown, path: unknown): OperationKey => `${String(method)} ${String(path)}` + +const requestMediaTypes = (root: unknown, value: unknown): ReadonlyArray => { + const body = value === undefined ? undefined : asRecord(resolveLocalRef(root, value)) + return body?.content === undefined ? [] : Object.keys(asRecord(body.content)).sort() +} + +const openApiRefObject = (value: unknown): Record => { + const resolved = resolveLocalRef(rawSpec, value) + return resolved === undefined ? {} : asRecord(resolved) +} + +const optionalRequestBodyKeys = sourceOperations.flatMap(({ method, path, operation }) => { + const body = openApiRefObject(operation.requestBody) + return Object.keys(body).length > 0 && body.required !== true ? [keyOf(method, path)] : [] +}).sort() + +describe("Bridge operation coverage", () => { + test("the pinned source and stable manifest cover the complete upstream operation set", () => { + const rawPaths = asRecord(asRecord(rawSpec).paths) + const expectedKeys = sourceOperations.map(({ method, path }) => keyOf(method, path)).sort() + const actualKeys = manifestOperations.map((entry) => keyOf(entry.method, entry.path)).sort() + const operationIds = manifestOperations.map((entry) => entry.operationId) + + expect(Object.keys(rawPaths)).toHaveLength(100) + expect(sourceOperations).toHaveLength(134) + expect(manifestByKey.size).toBe(134) + expect(actualKeys).toEqual(expectedKeys) + expect(new Set(operationIds).size).toBe(134) + expect(manifestRecord.sourceSha256).toBe("e8aee6cee1b5518d81f384c8b718dd9d9154dd9eb55345ff73d8b8dbe88327f2") + }) + + test("the generated HttpApi exposes every operation with matching parameters, body media, statuses, and response media", () => { + for (const { method, path, pathItem, operation } of sourceOperations) { + const key = keyOf(method, path) + const manifestEntry = manifestByKey.get(key) + expect(manifestEntry).toBeDefined() + if (manifestEntry === undefined) continue + + const generatedPath = asRecord(generatedPaths[path]) + const generatedOperation = asRecord(generatedPath[method]) + expect(generatedOperation.operationId).toBe(manifestEntry.operationId) + expect(asArray(generatedOperation.tags)).toContain(manifestEntry.group) + expect(getParameters(rawSpec, pathItem, operation)).toEqual( + getParameters(generated, {}, generatedOperation) + ) + + const sourceBodyMedia = requestMediaTypes(rawSpec, operation.requestBody) + const generatedBodyMedia = requestMediaTypes(generated, generatedOperation.requestBody) + expect(generatedBodyMedia).toEqual(sourceBodyMedia) + + const sourceResponses = asRecord(operation.responses) + const generatedResponses = asRecord(generatedOperation.responses) + const statuses = Object.keys(sourceResponses).sort() + expect(Object.keys(generatedResponses).sort()).toEqual(statuses) + for (const status of statuses) { + expect(responseMediaTypes(rawSpec, sourceResponses[status])).toEqual( + responseMediaTypes(generated, asRecord(generatedResponses)[status]) + ) + } + } + }) + + test("the generated schema source contains no Never placeholders", () => { + expect([...generatedSource.matchAll(/Schema\.Never/g)]).toHaveLength(0) + }) + + test("optional card bodies stay explicitly bounded to the four upstream operations", () => { + expect(optionalRequestBodyKeys).toEqual([ + "post /customers/{customerID}/card_accounts/{cardAccountID}/create_mobile_wallet_provisioning_request", + "post /customers/{customerID}/card_accounts/{cardAccountID}/ephemeral_keys", + "post /customers/{customerID}/card_accounts/{cardAccountID}/freeze", + "post /customers/{customerID}/card_accounts/{cardAccountID}/unfreeze" + ]) + for (const key of optionalRequestBodyKeys) { + const operation = sourceOperations.find((entry) => keyOf(entry.method, entry.path) === key) + expect(operation?.method).toBe("post") + expect(operation?.operation.requestBody).toBeDefined() + expect(operation?.path).toContain("/customers/") + } + }) + + test("hidden and deprecated operations remain in the generated surface", () => { + const hidden: Array = [] + const deprecated: Array = [] + for (const { method, path, operation } of sourceOperations) { + if (operation["x-hidden"] === true) hidden.push(keyOf(method, path)) + if (operation.deprecated === true) deprecated.push(keyOf(method, path)) + } + + expect(hidden.sort()).toEqual([ + "get /fees/configurations", + "get /fees/configurations/{developerFeeConfigID}", + "post /fees/configurations", + "put /fees/configurations/{developerFeeConfigID}" + ]) + expect(deprecated.sort()).toEqual([ + "get /customers/{customerID}/liquidation_addresses/{liquidationAddressID}/balances", + "post /customers/{customerID}/batch_settlement_schedules", + "post /customers/{customerID}/card_accounts" + ]) + for (const key of [...hidden, ...deprecated]) expect(manifestByKey.has(key)).toBe(true) + }) +}) diff --git a/packages/bridge/tests/fixtures/contracts/major-families.json b/packages/bridge/tests/fixtures/contracts/major-families.json new file mode 100644 index 0000000..19f1725 --- /dev/null +++ b/packages/bridge/tests/fixtures/contracts/major-families.json @@ -0,0 +1,79 @@ +{ + "liquidationAddressRequest": { + "currency": "usdc", + "chain": "ethereum", + "external_account_id": "acctfixture01", + "destination_payment_rail": "ach", + "destination_currency": "usd" + }, + "liquidationAddressResponse": { + "id": "lafixture01", + "chain": "ethereum", + "customer_id": "custfixture01", + "external_account_id": "acctfixture01", + "address": "0x0000000000000000000000000000000000000001", + "currency": "usdc", + "destination_payment_rail": "ach", + "destination_currency": "usd", + "supported_currencies": { + "ethereum": ["usdc"] + }, + "state": "active", + "created_at": "2026-09-23T12:00:00.000Z", + "updated_at": "2026-09-23T12:00:00.000Z" + }, + "cardAccountRequest": { + "currency": "usdc", + "chain": "ethereum" + }, + "cardAccountResponse": { + "id": "cardfixture01", + "customer_id": "custfixture01", + "status": "active", + "balances": { + "available": {"amount": "10.00", "currency": "usdc"}, + "hold": {"amount": "0.00", "currency": "usdc"} + }, + "freezes": [] + }, + "cardFreezeResponse": { + "status": "freeze_created", + "card_account_id": "cardfixture01", + "initiator": "developer", + "reason": "planned_inactivity", + "created_at": "2026-09-23T12:00:00.000Z" + }, + "prefundedAccount": { + "id": "f15972de-4cdd-460c-9da3-34f7321bfa3f", + "currency": "usd", + "available_balance": "134.12", + "name": "miso_fixture_account", + "created_at": "2020-01-01T00:00:00.000Z", + "updated_at": "2020-01-02T00:00:00.000Z" + }, + "webhooks": { + "data": [ + { + "id": "wep_c0ffee1234", + "url": "https://example.invalid/bridge-events", + "status": "active", + "public_key": "-----BEGIN PUBLIC KEY-----\nfixture-key-not-for-verification\n-----END PUBLIC KEY-----", + "event_categories": ["customer"] + } + ] + }, + "developerFees": { + "default_liquidation_address_fee_percent": "1.3" + }, + "countries": { + "count": 1, + "data": [ + { + "name": "United States", + "alpha3": "USA", + "postal_code_format": "^\\d{5}(-\\d{4})?$", + "subdivisions": [] + } + ] + } +} diff --git a/packages/bridge/tests/fixtures/contracts/never-models.json b/packages/bridge/tests/fixtures/contracts/never-models.json new file mode 100644 index 0000000..4a29f56 --- /dev/null +++ b/packages/bridge/tests/fixtures/contracts/never-models.json @@ -0,0 +1,89 @@ +{ + "ExternalAccountResponse": { + "id": "acctfixture01", + "customer_id": "custfixture01", + "created_at": "2026-09-23T12:00:00.000Z", + "updated_at": "2026-09-23T12:00:00.000Z", + "account_owner_name": "Miso Fixture", + "currency": "usd", + "account_type": "us", + "active": true, + "bank_name": "Fixture Bank", + "account": { + "account_number": "000000000000", + "routing_number": "000000000", + "last_4": "0000", + "checking_or_savings": "checking" + } + }, + "CreateExternalAccountInput": { + "currency": "usd", + "account_owner_name": "Miso Fixture", + "account_type": "us", + "account": { + "account_number": "000000000000", + "routing_number": "000000000", + "checking_or_savings": "checking" + }, + "address": { + "street_line_1": "123 Fixture Street", + "city": "Example City", + "state": "CA", + "postal_code": "90000", + "country": "USA" + } + }, + "CreateLiquidationAddressResponse": { + "id": "lafixture01", + "customer_id": "custfixture01", + "external_account_id": "acctfixture01", + "currency": "usdc", + "chain": "ethereum", + "address": "0x0000000000000000000000000000000000000001", + "destination_payment_rail": "ach", + "destination_currency": "usd", + "state": "active", + "created_at": "2026-09-23T12:00:00.000Z", + "updated_at": "2026-09-23T12:00:00.000Z", + "supported_currencies": { + "ethereum": ["usdc"] + } + }, + "FeeExternalAccount": { + "id": "feafixture01", + "customer_id": "devfixture01", + "created_at": "2026-09-23T12:00:00.000Z", + "updated_at": "2026-09-23T12:00:00.000Z", + "account_owner_name": "Miso Fixture", + "account_name": "Fixture Fee Account", + "currency": "usd", + "account_type": "us", + "active": true, + "account": { + "account_number": "000000000000", + "routing_number": "000000000", + "last_4": "0000", + "checking_or_savings": "checking" + } + }, + "CreateFeeExternalAccountInput": { + "currency": "usd", + "account_owner_name": "Miso Fixture", + "account_type": "us", + "account": { + "account_number": "000000000000", + "routing_number": "000000000", + "checking_or_savings": "checking" + } + }, + "CardAccount": { + "id": "cardfixture01", + "customer_id": "custfixture01", + "status": "active", + "balances": { + "available": {"amount": "10.00", "currency": "usdc"}, + "hold": {"amount": "0.00", "currency": "usdc"} + }, + "freezes": [] + } +} diff --git a/packages/bridge/tests/fixtures/contracts/representative-flow.json b/packages/bridge/tests/fixtures/contracts/representative-flow.json new file mode 100644 index 0000000..9ca0bba --- /dev/null +++ b/packages/bridge/tests/fixtures/contracts/representative-flow.json @@ -0,0 +1,117 @@ +{ + "customer": { + "type": "individual", + "first_name": "Miso", + "last_name": "Fixture", + "email": "miso.fixture@example.invalid" + }, + "kycLink": { + "type": "individual", + "full_name": "Miso Fixture", + "email": "miso.fixture@example.invalid", + "redirect_uri": "https://example.invalid/kyc-complete" + }, + "wallet": { + "chain": "ethereum" + }, + "externalAccount": { + "currency": "usd", + "account_owner_name": "Miso Fixture", + "account_type": "us", + "account": { + "account_number": "000000000000", + "routing_number": "000000000", + "checking_or_savings": "checking" + }, + "address": { + "street_line_1": "123 Fixture Street", + "city": "Example City", + "state": "CA", + "postal_code": "90000", + "country": "USA" + } + }, + "transfer": { + "on_behalf_of": "custfixture01", + "amount": "12.34", + "source": { + "currency": "usdc", + "payment_rail": "ethereum", + "bridge_wallet_id": "walletfixture01" + }, + "destination": { + "currency": "usd", + "payment_rail": "ach", + "external_account_id": "acctfixture01" + } + }, + "webhook": { + "api_version": "2026-09-23", + "event_id": "evtfixture01", + "event_developer_id": "devfixture01", + "event_category": "customer", + "event_type": "created", + "event_object_id": "custfixture01", + "event_object_status": "active", + "event_object": { + "id": "custfixture01", + "type": "individual" + }, + "event_object_changes": { + "status": "active" + }, + "event_created_at": "2026-09-23T12:00:00.000Z" + }, + "responses": { + "customer": { + "id": "custfixture01", + "type": "individual", + "first_name": "Miso", + "last_name": "Fixture", + "email": "miso.fixture@example.invalid", + "status": "active" + }, + "kycLink": { + "id": "kycfixture01", + "full_name": "Miso Fixture", + "email": "miso.fixture@example.invalid", + "type": "individual", + "kyc_link": "https://example.invalid/kyc/fixture", + "tos_link": "https://example.invalid/tos/fixture", + "kyc_status": "not_started", + "tos_status": "pending", + "customer_id": "custfixture01" + }, + "wallet": { + "id": "walletfixture01", + "chain": "ethereum", + "address": "0x0000000000000000000000000000000000000001" + }, + "transfer": { + "id": "transferfixture01", + "amount": "12.34", + "developer_fee": "0.00", + "currency": "usd", + "on_behalf_of": "custfixture01", + "source": { + "currency": "usdc", + "payment_rail": "ethereum", + "bridge_wallet_id": "walletfixture01" + }, + "destination": { + "currency": "usd", + "payment_rail": "ach", + "external_account_id": "acctfixture01" + }, + "state": "awaiting_funds", + "receipt": { + "initial_amount": "12.34", + "developer_fee": "0.00", + "exchange_fee": "0.00", + "subtotal_amount": "12.34" + }, + "created_at": "2026-09-23T12:00:00.000Z", + "updated_at": "2026-09-23T12:00:00.000Z" + } + } +} diff --git a/packages/bridge/tests/fixtures/nested-response-schemas.json b/packages/bridge/tests/fixtures/nested-response-schemas.json new file mode 100644 index 0000000..03b689a --- /dev/null +++ b/packages/bridge/tests/fixtures/nested-response-schemas.json @@ -0,0 +1,124 @@ +{ + "endorsement": { + "name": "base", + "status": "incomplete", + "requirements": { + "complete": ["first_name", "last_name"], + "pending": ["tax_identification_number"], + "missing": { + "all_of": ["tax_identification_number", "source_of_funds_questionnaire"] + }, + "issues": [ + "endorsement_not_available_in_customers_region", + { "id_front_photo": "id_expired" } + ] + }, + "future_requirements": [ + { + "effective_date": "2026-10-01", + "verification_stage": "manual_review", + "pending": ["proof_of_address"], + "missing": { "any_of": ["proof_of_address", "bank_statement"] }, + "issues": [{ "proof_of_address": "document_expired" }] + } + ] + }, + "virtualAccountInstructions": { + "us": { + "currency": "usd", + "payment_rails": ["ach_push", "fednow", "wire"], + "bank_name": "Lead Bank", + "bank_address": "1801 Main St., Kansas City, MO 64108", + "bank_beneficiary_name": "Customer Name", + "bank_beneficiary_address": "1234 Main St., Kansas City, MO 64108", + "bank_account_number": "123456789", + "bank_routing_number": "87654321" + }, + "eu": { + "iban": "DE89370400440532013000", + "bic": "COBADEFFXXX", + "account_holder_name": "Customer Name", + "bank_beneficiary_name": "Customer Name", + "bank_beneficiary_address": "10 Example Street, Berlin", + "currency": "eur", + "payment_rails": "sepa", + "bank_name": "Example Bank", + "bank_address": "10 Example Street, Berlin" + }, + "mx": { + "clabe": "012345678901234567", + "account_holder_name": "Customer Name", + "currency": "mxn", + "payment_rails": ["spei"], + "bank_name": "Example Bank", + "bank_address": "Av. Reforma 100, Ciudad de Mexico" + }, + "br": { + "br_code": "00020101021226890014br.gov.bcb.pix", + "account_holder_name": "Customer Name", + "currency": "brl", + "payment_rails": ["pix"], + "bank_name": "Example Bank", + "bank_address": "Av. Paulista 1000, Sao Paulo" + }, + "gb": { + "account_number": "12345678", + "sort_code": "123456", + "account_holder_name": "Customer Name", + "bank_beneficiary_name": "Customer Name", + "bank_beneficiary_address": "10 Example Street, London", + "currency": "gbp", + "payment_rails": "faster_payments", + "bank_name": "Example Bank", + "bank_address": "10 Example Street, London" + }, + "co": { + "bre_b_key": "customer@example.co", + "account_holder_name": "Customer Name", + "deposit_message": "Customer reference 123", + "currency": "cop", + "payment_rails": ["bre_b"], + "bank_name": "Example Bank", + "bank_address": "Carrera 7 # 71-21, Bogota" + } + }, + "cardProgramSummary": { + "period": "month", + "period_starting": "2026-09-01", + "cards_provisioned_count": 168, + "card_transactions_count": 241, + "provisioned_cards_by_country": { "USA": 123, "MEX": 45 }, + "transaction_volume": "-100.0", + "transacting_card_accounts_count": 112, + "card_transactions_count_by_country": { "USA": 74, "MEX": 55 }, + "transaction_volume_by_country": { "USA": "7.04", "MEX": "5.0" }, + "transacting_cards_by_country": { "USA": 123, "MEX": 41 } + }, + "deactivateResponse": { + "id": "va123456", + "status": "deactivated", + "developer_fee_percent": "0.1", + "fee_config": { + "source": { + "default": { "fee_percent": "0.5", "minimum_fee": "1.00" } + } + }, + "customer_id": "cus123456", + "created_at": "2026-09-24T12:00:00Z", + "source_deposit_instructions": { + "currency": "usd", + "payment_rails": ["ach_push", "fednow", "wire"], + "bank_name": "Lead Bank", + "bank_address": "1801 Main St., Kansas City, MO 64108", + "bank_beneficiary_name": "Customer Name", + "bank_beneficiary_address": "1234 Main St., Kansas City, MO 64108", + "bank_account_number": "123456789", + "bank_routing_number": "87654321" + }, + "destination": { + "currency": "usdc", + "payment_rail": "base", + "address": "0x1234567890abcdef" + } + } +} diff --git a/packages/bridge/tests/fixtures/webhooks/vectors.ts b/packages/bridge/tests/fixtures/webhooks/vectors.ts new file mode 100644 index 0000000..b55d7a5 --- /dev/null +++ b/packages/bridge/tests/fixtures/webhooks/vectors.ts @@ -0,0 +1,33 @@ +// Copyright (c) Miso Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +/** + * Fixed RSA/SHA-256 vector generated independently with OpenSSL 3.0.13. The + * command hashes `${timestamp}.${rawBody}` once, then applies SHA-256 again as + * the message hash used by RSASSA-PKCS1-v1_5, matching Bridge's documented + * double-hash verification behavior. The ephemeral signing key was not kept. + */ +export const VECTOR_TIMESTAMP = 1_790_164_800_000; + +export const VECTOR_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4l2axQeHdGUkGj7d7Gwo +o1yH6gaN045ZrDRA4uNQ8IyVWeZm7E/ewLDlC9eKgwA8e65ydhEsFN6WZq+Bcg/x +SiYvZGHILGWSWWunF0NS93b6HYtxN4+ksEMWp73ygdulENUDyinqreVbmggvOE8R +xu50eKz1xi8qxLtAJ4vHcY+UNCeC2Pzp0ee6H4MDyM33NjM04VqPJPJG1rvHE9qc +4qkJ5sIqZwGWy62IrA+rCezVCeoy+3F35JUGwtJ1gz/MnAWY9MDRgeA6j1FQV+53 +9Ln56lIqBbGb3XZ3otKpUDer1KYBlvUjCkuKi8S903Q6Q3/XMGWkjGB9CVzm4/OE +NQIDAQAB +-----END PUBLIC KEY-----`; + +/** Exact compact UTF-8 JSON bytes covered by `VECTOR_SIGNATURE_HEADER`. */ +export const VECTOR_RAW_BODY = new TextEncoder().encode( + '{"api_version":"v0","event_id":"wh_vector_01","event_category":"future.category","event_type":"future.action","event_object_id":"obj_01","event_object":{"id":"obj_01","amount":"1.00"},"event_object_changes":{},"event_created_at":"2026-09-23T12:00:00.000Z"}', +); + +export const VECTOR_SIGNATURE_HEADER = + "t=1790164800000,v0=f05VS1XsuXo58+egI8TvaX3rkMVXYw/R3HTsCtp2N67/948K80u1uatt65q5sS40tExwpR07BraZKexdu8j3gCJ+5KTW4HfjM20+xDdtP8RM3CyDOOevVtVbtBCymLpOC+Z5Xk7jl+zjZX6XIYXxTCkflG3j5Tx3QPEK14LVtMHHz1jMveNz3UOcK+Vikq6KMuGS4z8jcsrx8Y5cNwHFGKp8oqkIBEgiMyq2Xdf2UoU4TMXm9HKLXjq+SPxOkPu6AKbuCgHl93sOqJWPl2dIoMSoAjxsWIwRIJA0PprQYN21a6717YMx7w8YNMgmKyl9i/NKymHfAWBFoqPjxatDrw=="; + +/** A second independently signed body proves signature-before-JSON ordering. */ +export const INVALID_JSON_RAW_BODY = new TextEncoder().encode("not-json"); +export const INVALID_JSON_SIGNATURE_HEADER = + "t=1790164800000,v0=jv54upM4TaTn5IJdjWStDL9bsPGARVi+IP3yrdabZc/qwRCF7qzdWxRwi5X/fyiLQBOTgqPAMrFSryGyksxJ088CgvAXXLV7voTmBvEXnOcavpqwRfwjv4rcgpohzeRJIAhXskomWv3mUjC0qUYatn0BMaa1v/Vhl+j6r5y3zU5feywWS1+8A/7XI5BKKD+YDtv+e3SteR+9LfdM+n656uuaUsJDhPSHNFMBAu871Rd99yRn54ELe9XOfDKU2o2e4M982EueVYsCSh+2RQNgcEEfI9X0TAY+1N9f2a44wLwXX2KnufMISts/dOYku2emyqJycpeZpx8iHxFQm4/IOw=="; diff --git a/packages/bridge/tests/generation.test.ts b/packages/bridge/tests/generation.test.ts new file mode 100644 index 0000000..07a0032 --- /dev/null +++ b/packages/bridge/tests/generation.test.ts @@ -0,0 +1,260 @@ +import { beforeAll, describe, expect, test } from "bun:test" +import * as Schema from "effect/Schema" +import * as HttpApiSchema from "effect/unstable/httpapi/HttpApiSchema" +import { readFile } from "node:fs/promises" +import { resolve } from "node:path" +import { + CardProgramSummary, + CreateBusinessCustomerPayload, + CreateIndividualCustomerPayload, + Customer, + GetCustomers200, + PostCustomersByCustomerIDCardAccountsByCardAccountIDEphemeralKeysRequestJson, + PostCustomersByCustomerIDCardAccountsByCardAccountIDFreezeRequestJson, + PostCustomersByCustomerIDCardAccountsByCardAccountIDUnfreezeRequestJson, + PostCustomersByCustomerIDCardAccountsByCardAccountIDCreateMobileWalletProvisioningRequestRequestJson, + PostCustomersByCustomerIDVirtualAccountsByVirtualAccountIDDeactivate200, + UpdateBusinessCustomerPayload, + UpdateIndividualCustomerPayload, + VirtualAccountResponse +} from "../src/generated/BridgeApi" +import { + BRIDGE_OPERATION_COUNT, + BRIDGE_PATH_COUNT, + BRIDGE_SCHEMA_COUNT, + BRIDGE_SPEC_SHA256, + generateBridgeApi +} from "../scripts/generate.ts" + +interface Warning { + readonly code: string + readonly message: string + readonly path?: string + readonly method?: string + readonly operationId?: string +} + +interface WarningBaseline { + readonly items: ReadonlyArray + readonly review: Readonly> +} + +const packageRoot = resolve(import.meta.dir, "..") +const generatedPath = resolve(packageRoot, "src/generated/BridgeApi.ts") +const warningBaselinePath = resolve(packageRoot, "openapi/generator-warnings.json") +const nestedFixturePath = resolve(packageRoot, "tests/fixtures/nested-response-schemas.json") +const pinnedSpecPath = resolve(packageRoot, "openapi/bridge-2026-09-23.json") + +const isRecord = (value: unknown): value is Record => + typeof value === "object" && value !== null && !Array.isArray(value) + +const atPath = (value: unknown, path: ReadonlyArray): unknown => { + let current = value + for (const key of path) { + if (!isRecord(current) || !(key in current)) throw new Error(`Pinned Bridge snapshot is missing ${path.join(".")}`) + current = current[key] + } + return current +} + +const exampleValue = (value: unknown, name: string): unknown => { + if (!isRecord(value) || !("value" in value)) throw new Error(`Pinned Bridge snapshot is missing example ${name}`) + return value.value +} + +const warningKey = (warning: Warning): string => JSON.stringify({ + code: warning.code, + path: warning.path ?? null, + method: warning.method ?? null, + operationId: warning.operationId ?? null, + message: warning.message +}) + +describe("Bridge contract generation", () => { + let generated: Awaited> + + beforeAll(async () => { + generated = await generateBridgeApi() + }) + + test("pins and covers the complete official snapshot", () => { + expect(generated.sourceHash).toBe(BRIDGE_SPEC_SHA256) + expect(generated.pathCount).toBe(BRIDGE_PATH_COUNT) + expect(generated.schemaCount).toBe(BRIDGE_SCHEMA_COUNT) + expect(generated.operationCount).toBe(BRIDGE_OPERATION_COUNT) + expect(generated.generatedOperationCount).toBe(BRIDGE_OPERATION_COUNT) + }) + + test("keeps operation groups, hidden and deprecated metadata, and concrete schemas", () => { + expect(generated.output).toContain("export class BridgeApi extends HttpApi.make(\"BridgeApi\")") + expect(generated.output).toContain('HttpApiGroup.make("bridgeWallets")') + expect(generated.output).toContain('HttpApiGroup.make("developerFees")') + expect(generated.output.match(/\[Upstream x-hidden\]/g)).toHaveLength(4) + expect(generated.output.match(/\[Deprecated upstream\]/g)).toHaveLength(3) + expect(generated.output).toContain("export const Customer = Schema.") + expect(generated.output).toContain("export const DeveloperFeeConfig = Schema.") + expect(generated.output).not.toContain("Schema.Any") + expect(generated.output).not.toContain("Schema.Never") + }) + + test("decodes realistic non-empty fixtures for previously impossible nested response schemas", async () => { + const fixtures = JSON.parse(await readFile(nestedFixturePath, "utf8")) as { + readonly endorsement: unknown + readonly virtualAccountInstructions: Readonly> + readonly cardProgramSummary: Record + readonly deactivateResponse: unknown + } + + const customer = { id: "cus123456", endorsements: [fixtures.endorsement] } + expect(Schema.is(Customer)(customer)).toBe(true) + const endorsement = fixtures.endorsement as { + readonly name: string + readonly status: string + readonly requirements: { readonly issues: ReadonlyArray; readonly missing: unknown } + } + expect(Schema.is(Customer)({ + ...customer, + endorsements: [{ + ...endorsement, + requirements: { ...endorsement.requirements, missing: null } + }] + })).toBe(true) + expect(Schema.is(Customer)({ + ...customer, + endorsements: [{ + ...endorsement, + requirements: { ...endorsement.requirements, issues: [{ id_front_photo: 404 }] } + }] + })).toBe(false) + + const instructionNames = ["us", "eu", "mx", "br", "gb", "co"] + expect(Object.keys(fixtures.virtualAccountInstructions).sort()).toEqual(instructionNames.sort()) + for (const instructions of Object.values(fixtures.virtualAccountInstructions)) { + expect(Schema.is(VirtualAccountResponse)({ source_deposit_instructions: instructions })).toBe(true) + } + + expect(Schema.is(CardProgramSummary)(fixtures.cardProgramSummary)).toBe(true) + expect(Schema.is(CardProgramSummary)({ + ...fixtures.cardProgramSummary, + provisioned_cards_by_country: { USA: "123" } + })).toBe(false) + expect(Schema.is(CardProgramSummary)({ + ...fixtures.cardProgramSummary, + transaction_volume_by_country: { USA: 7.04 } + })).toBe(false) + + expect(Schema.is(PostCustomersByCustomerIDVirtualAccountsByVirtualAccountIDDeactivate200)( + fixtures.deactivateResponse + )).toBe(true) + expect(Schema.is(PostCustomersByCustomerIDVirtualAccountsByVirtualAccountIDDeactivate200)({ + ...(fixtures.deactivateResponse as Record), + status: "active" + })).toBe(false) + }) + + test("decodes published customer response examples while keeping request payloads strict", async () => { + const spec = JSON.parse(await readFile(pinnedSpecPath, "utf8")) as unknown + const businessCustomer = exampleValue( + atPath(spec, ["components", "examples", "SuccessfulCustomerResponse2"]), + "SuccessfulCustomerResponse2" + ) + const customerListExamples = atPath(spec, ["paths", "/customers", "get", "responses", "200", "content", "application/json", "examples"]) + const customersFound = exampleValue(atPath(customerListExamples, ["CustomersFound"]), "CustomersFound") + const noCustomersFound = exampleValue(atPath(customerListExamples, ["NoCustomersFound"]), "NoCustomersFound") + + const decodedBusinessCustomer = Schema.decodeUnknownSync(Customer)(businessCustomer) + expect(decodedBusinessCustomer.last_name).toBeNull() + const decodedCustomerList = Schema.decodeUnknownSync(GetCustomers200)(customersFound) + expect(decodedCustomerList.count).toBeUndefined() + expect(decodedCustomerList.data).toHaveLength(2) + expect(Schema.decodeUnknownSync(GetCustomers200)(noCustomersFound).data).toHaveLength(0) + + if (!isRecord(businessCustomer)) throw new Error("Published business customer example must be an object") + expect(Schema.is(Customer)({ ...businessCustomer, last_name: 42 })).toBe(false) + expect(Schema.is(GetCustomers200)({ data: [], count: "0" })).toBe(false) + expect(Schema.is(Customer)({ + endorsements: [{ + name: "base", + status: "approved", + requirements: { + complete: [{ associated_person: 123, items: ["first_name"] }], + pending: [], + missing: null, + issues: [] + } + }] + })).toBe(false) + expect(Schema.is(Customer)({ + endorsements: [{ + name: "base", + status: "approved", + requirements: { + complete: [{ associated_person: "person_123" }], + pending: [], + missing: null, + issues: [] + } + }] + })).toBe(false) + + expect(Schema.is(CreateIndividualCustomerPayload)({ type: "individual", last_name: null })).toBe(false) + expect(Schema.is(UpdateIndividualCustomerPayload)({ type: "individual", last_name: null })).toBe(false) + expect(Schema.is(CreateBusinessCustomerPayload)({ type: "business", business_legal_name: null })).toBe(false) + expect(Schema.is(UpdateBusinessCustomerPayload)({ type: "business", business_legal_name: null })).toBe(false) + }) + + test("preserves optional card request bodies and encodes absent or supplied payloads", () => { + const optionalPayloads = [ + { + operationId: "postCustomersByCustomerIDCardAccountsByCardAccountIDEphemeralKeys", + schemaName: "PostCustomersByCustomerIDCardAccountsByCardAccountIDEphemeralKeysRequestJson", + schema: PostCustomersByCustomerIDCardAccountsByCardAccountIDEphemeralKeysRequestJson, + body: { client_nonce: "nonce" } + }, + { + operationId: "postCustomersByCustomerIDCardAccountsByCardAccountIDFreeze", + schemaName: "PostCustomersByCustomerIDCardAccountsByCardAccountIDFreezeRequestJson", + schema: PostCustomersByCustomerIDCardAccountsByCardAccountIDFreezeRequestJson, + body: { initiator: "customer", reason: "other" } + }, + { + operationId: "postCustomersByCustomerIDCardAccountsByCardAccountIDUnfreeze", + schemaName: "PostCustomersByCustomerIDCardAccountsByCardAccountIDUnfreezeRequestJson", + schema: PostCustomersByCustomerIDCardAccountsByCardAccountIDUnfreezeRequestJson, + body: { initiator: "customer" } + }, + { + operationId: "postCustomersByCustomerIDCardAccountsByCardAccountIDCreateMobileWalletProvisioningRequest", + schemaName: "PostCustomersByCustomerIDCardAccountsByCardAccountIDCreateMobileWalletProvisioningRequestRequestJson", + schema: PostCustomersByCustomerIDCardAccountsByCardAccountIDCreateMobileWalletProvisioningRequestRequestJson, + body: { initiator: "customer" } + } + ] as const + + expect(generated.output.match(/payload: \[[A-Za-z0-9]+RequestJson, HttpApiSchema\.NoContent\]/g)).toHaveLength(4) + + for (const { operationId, schemaName, schema, body } of optionalPayloads) { + expect(generated.output).toContain(`HttpApiEndpoint.post("${operationId}"`) + expect(generated.output).toContain(`payload: [${schemaName}, HttpApiSchema.NoContent]`) + + const payload = Schema.Union([schema, HttpApiSchema.NoContent]) + expect(Schema.is(schema)(body)).toBe(true) + expect(Schema.is(schema)(null)).toBe(false) + expect(Schema.is(payload)(undefined)).toBe(true) + expect(Schema.is(payload)(body)).toBe(true) + expect(Schema.encodeUnknownSync(payload)(undefined)).toBeUndefined() + expect(Schema.encodeUnknownSync(payload)(body)).toEqual(body) + } + }) + + test("matches the reviewed warning baseline and checked-in output byte for byte", async () => { + const baseline = JSON.parse(await readFile(warningBaselinePath, "utf8")) as WarningBaseline + const actualWarnings = generated.warnings.map(warningKey).sort() + const expectedWarnings = baseline.items.map(warningKey).sort() + expect(actualWarnings).toEqual(expectedWarnings) + for (const code of new Set(generated.warnings.map(({ code }) => code))) { + expect(baseline.review[code]?.trim().length).toBeGreaterThan(0) + } + expect(await readFile(generatedPath, "utf8")).toBe(generated.output) + }) +}) diff --git a/packages/bridge/tests/object-schemas.test.ts b/packages/bridge/tests/object-schemas.test.ts new file mode 100644 index 0000000..085e737 --- /dev/null +++ b/packages/bridge/tests/object-schemas.test.ts @@ -0,0 +1,140 @@ +import { describe, expect, test } from "bun:test" +import * as Schema from "effect/Schema" +import * as GeneratedApi from "../src/generated/BridgeApi" +import { + CardAccount, + CreateBridgeWallet, + Customer, + DeveloperFees, + Error, + GetListsCountries200, + LiquidationAddress, + PostCardFreezeInput, + PostCustomersByCustomerIDCardAccountsRequestJson, + PostCustomersByCustomerIDLiquidationAddressesRequestJson, + PostCustomersByCustomerIDWalletsRequestJson, + PostKycLinksRequestJson, + PostCustomersRequestJson, + PostTransfersRequestJson, + PrefundedAccount, + TransferRequest, + TransferResponse, + WebhookEvent +} from "../src/generated/BridgeApi" + +interface FlowFixtures { + readonly customer: unknown + readonly kycLink: unknown + readonly wallet: unknown + readonly transfer: unknown + readonly webhook: unknown + readonly responses: Readonly> +} + +interface MajorFamilyFixtures { + readonly liquidationAddressRequest: unknown + readonly liquidationAddressResponse: unknown + readonly cardAccountRequest: unknown + readonly cardAccountResponse: unknown + readonly prefundedAccount: unknown + readonly developerFees: unknown + readonly countries: unknown +} + +interface NestedResponseFixtures { + readonly endorsement: unknown +} + +interface RawBridgeSpec { + readonly components: { + readonly schemas: Readonly> + } +} + +const isRecord = (value: unknown): value is Record => + typeof value === "object" && value !== null && !Array.isArray(value) + +const flow = JSON.parse( + await Bun.file(new URL("./fixtures/contracts/representative-flow.json", import.meta.url)).text() +) as FlowFixtures +const families = JSON.parse( + await Bun.file(new URL("./fixtures/contracts/major-families.json", import.meta.url)).text() +) as MajorFamilyFixtures +const nested = JSON.parse( + await Bun.file(new URL("./fixtures/nested-response-schemas.json", import.meta.url)).text() +) as NestedResponseFixtures +const rawSpec = JSON.parse( + await Bun.file(new URL("../openapi/bridge-2026-09-23.json", import.meta.url)).text() +) as RawBridgeSpec + +describe("Bridge generated object schemas", () => { + test("Miso flow and official family fixtures decode across request and response models", () => { + expect(Schema.is(PostCustomersRequestJson)(flow.customer)).toBe(true) + expect(Schema.is(PostKycLinksRequestJson)(flow.kycLink)).toBe(true) + expect(Schema.is(PostCustomersByCustomerIDWalletsRequestJson)(flow.wallet)).toBe(true) + expect(Schema.is(PostTransfersRequestJson)(flow.transfer)).toBe(true) + expect(Schema.is(Customer)(flow.responses.customer)).toBe(true) + expect(Schema.is(TransferResponse)(flow.responses.transfer)).toBe(true) + expect(Schema.is(WebhookEvent)(flow.webhook)).toBe(true) + + expect(Schema.is(PostCustomersByCustomerIDLiquidationAddressesRequestJson)(families.liquidationAddressRequest)).toBe(true) + expect(Schema.is(LiquidationAddress)(families.liquidationAddressResponse)).toBe(true) + expect(Schema.is(PostCustomersByCustomerIDCardAccountsRequestJson)(families.cardAccountRequest)).toBe(true) + expect(Schema.is(CardAccount)(families.cardAccountResponse)).toBe(true) + expect(Schema.is(PrefundedAccount)(families.prefundedAccount)).toBe(true) + expect(Schema.is(DeveloperFees)(families.developerFees)).toBe(true) + expect(Schema.is(GetListsCountries200)(families.countries)).toBe(true) + }) + + test("object-shaped requests and responses reject primitive JSON at the top level", () => { + for (const value of [null, "primitive", 1, true, []]) { + expect(Schema.is(Customer)(value)).toBe(false) + expect(Schema.is(TransferRequest)(value)).toBe(false) + expect(Schema.is(CreateBridgeWallet)(value)).toBe(false) + expect(Schema.is(Error)(value)).toBe(false) + expect(Schema.is(PostCardFreezeInput)(value)).toBe(false) + } + expect(Schema.is(CreateBridgeWallet)({ chain: "ethereum" })).toBe(true) + expect(Schema.is(CreateBridgeWallet)({ chain: "ethereum", upstream_addition: "accepted" })).toBe(true) + expect(Schema.is(CreateBridgeWallet)({})).toBe(false) + expect(Schema.is(PostCardFreezeInput)({ initiator: "customer", reason: "other" })).toBe(true) + expect(Schema.is(PostCardFreezeInput)({ initiator: "bridge", reason: "other" })).toBe(false) + }) + + test("every exported component object missing an upstream type rejects primitives", () => { + const generated = GeneratedApi as unknown as Readonly> + const primitiveValues = [null, "primitive", 1, true, []] + let checked = 0 + + for (const [name, rawSchema] of Object.entries(rawSpec.components.schemas)) { + if (!isRecord(rawSchema) || "type" in rawSchema || + !("properties" in rawSchema || Array.isArray(rawSchema.required))) continue + const schema = generated[name] + if (schema === undefined) continue + checked += 1 + const rejectedValues = primitiveValues.filter((value) => value !== null || rawSchema.nullable !== true) + for (const value of rejectedValues) { + expect(Schema.is(schema as Schema.Constraint)(value), `${name} should reject ${String(value)}`).toBe(false) + } + } + + expect(checked).toBeGreaterThan(50) + }) + + test("nested request and response object schemas reject primitive values", () => { + const endorsement = nested.endorsement as Record + const customer = { id: "custfixture01", endorsements: [endorsement] } + expect(Schema.is(Customer)(customer)).toBe(true) + expect(Schema.is(Customer)({ ...customer, endorsements: ["not-an-endorsement"] })).toBe(false) + expect(Schema.is(Customer)({ ...customer, middle_name: null })).toBe(true) + + expect(Schema.is(PostTransfersRequestJson)({ + ...(flow.transfer as Record), + source: "not-an-object" + })).toBe(false) + expect(Schema.is(TransferResponse)({ + ...(flow.responses.transfer as Record), + destination: "not-an-object" + })).toBe(false) + }) +}) diff --git a/packages/bridge/tests/pagination.test.ts b/packages/bridge/tests/pagination.test.ts new file mode 100644 index 0000000..4603a62 --- /dev/null +++ b/packages/bridge/tests/pagination.test.ts @@ -0,0 +1,330 @@ +import { describe, expect, test } from "bun:test" +import * as Effect from "effect/Effect" +import * as Fiber from "effect/Fiber" +import * as Stream from "effect/Stream" + +import type { BridgeClient } from "../src/Bridge.js" +import { + BridgePaginationCursorError, + BridgePaginationLimitError, + paginateBridge, + paginateBridgeEffect, + paginateBridgeRewards, + paginateBridgeRewardsEffect, + type BridgeCursorPage, + type BridgeCursorQuery, + type BridgeRewardsCursorPage, + type BridgeRewardsCursorQuery +} from "../src/Pagination.js" + +interface Item { + readonly id: string + readonly value: number +} + +interface Reward { + readonly date: string + readonly amount: string +} + +const customerId = (customer: unknown): string | undefined => { + if (typeof customer !== "object" || customer === null || !("id" in customer)) return undefined + return typeof customer.id === "string" ? customer.id : undefined +} + +const generatedCustomerPages = (bridge: BridgeClient) => + paginateBridge({}, (query) => bridge.customers.getCustomers({ query }), { getId: customerId }) + +const generatedRewardPages = (bridge: BridgeClient, currency: string) => + paginateBridgeRewards( + {}, + (query) => bridge.rewards.getRewardsByCurrencyHistory({ params: { currency }, query }), + {} + ) + +describe("Bridge pagination helpers", () => { + test("adapt generated customer and rewards client methods without narrowing their types", () => { + expect(generatedCustomerPages).toBeDefined() + expect(generatedRewardPages).toBeDefined() + }) + + test("streams standard pages with preserved filters, a single cursor, and a 100 item maximum", async () => { + const requests: Array = [] + const filters = { + customer_id: "cus_123", + status: "active", + limit: 5, + starting_after: "filter-start" + } as const + + const stream = paginateBridge( + filters, + (query): Effect.Effect> => { + requests.push(query) + if (query.starting_after === "explicit-start") { + return Effect.succeed({ + data: [{ id: "item_1", value: 1 }, { id: "item_2", value: 2 }], + has_more: true + }) + } + if (query.starting_after === "item_2") { + return Effect.succeed({ data: [{ id: "item_3", value: 3 }] }) + } + return Effect.succeed({ data: [], has_more: true }) + }, + { limit: 150, cursor: "explicit-start", getId: (item) => item.id } + ) + + const items = await Effect.runPromise(Stream.runCollect(stream)) + + expect(items).toEqual([ + { id: "item_1", value: 1 }, + { id: "item_2", value: 2 }, + { id: "item_3", value: 3 } + ]) + expect(requests).toEqual([ + { customer_id: "cus_123", status: "active", limit: 100, starting_after: "explicit-start" }, + { customer_id: "cus_123", status: "active", limit: 100, starting_after: "item_2" }, + { customer_id: "cus_123", status: "active", limit: 100, starting_after: "item_3" } + ]) + }) + + test("uses the first item ID for ending_before and sends no starting_after cursor", async () => { + const requests: Array = [] + const stream = paginateBridge( + { account_id: "acct_456", limit: 2, ending_before: "known" }, + (query): Effect.Effect> => { + requests.push(query) + return query.ending_before === "known" + ? Effect.succeed({ + data: [{ id: "newest", value: 2 }, { id: "older", value: 1 }], + has_more: true + }) + : Effect.succeed({ data: [] }) + }, + { direction: "ending_before", getId: (item) => item.id } + ) + + const items = await Effect.runPromise(Stream.runCollect(stream)) + + expect(items.map((item) => item.id)).toEqual(["newest", "older"]) + expect(requests).toEqual([ + { account_id: "acct_456", limit: 2, ending_before: "known" }, + { account_id: "acct_456", limit: 2, ending_before: "newest" } + ]) + }) + + test("rejects conflicting standard cursor directions before fetching", async () => { + let calls = 0 + const error = await Effect.runPromise(Effect.flip(Stream.runCollect(paginateBridge( + { starting_after: "older", ending_before: "newer" }, + (): Effect.Effect> => { + calls += 1 + return Effect.succeed({ data: [] }) + }, + { getId: (item) => item.id } + )))) + + expect(error).toBeInstanceOf(BridgePaginationCursorError) + expect(error).toMatchObject({ contract: "standard", kind: "conflicting_directions" }) + expect(calls).toBe(0) + }) + + test("rejects an explicit direction that conflicts with a query cursor", async () => { + const error = await Effect.runPromise(Effect.flip(Stream.runCollect(paginateBridge( + { ending_before: "newer" }, + (): Effect.Effect> => Effect.succeed({ data: [] }), + { direction: "starting_after", getId: (item) => item.id } + )))) + + expect(error).toMatchObject({ contract: "standard", kind: "conflicting_directions" }) + }) + + test("detects standard cursor cycles before another page is requested", async () => { + const requests: Array = [] + const error = await Effect.runPromise(Effect.flip(Stream.runCollect(paginateBridge( + {}, + (query): Effect.Effect> => { + requests.push(query) + if (query.starting_after === undefined) return Effect.succeed({ data: [{ id: "A", value: 1 }], has_more: true }) + if (query.starting_after === "A") return Effect.succeed({ data: [{ id: "B", value: 2 }], has_more: true }) + return Effect.succeed({ data: [{ id: "A", value: 3 }], has_more: true }) + }, + { getId: (item) => item.id } + )))) + + expect(error).toMatchObject({ contract: "standard", kind: "cursor_cycle", cursor: "A" }) + expect(requests).toHaveLength(3) + }) + + test("stops on an empty page even if has_more is true", async () => { + let calls = 0 + const stream = paginateBridge({}, (_query): Effect.Effect> => { + calls += 1 + return Effect.succeed({ data: [], has_more: true }) + }, { getId: (item) => item.id }) + + expect(await Effect.runPromise(Stream.runCollect(stream))).toEqual([]) + expect(calls).toBe(1) + }) + + test("stops after a non-empty page when has_more is false", async () => { + let calls = 0 + const stream = paginateBridge({}, (_query): Effect.Effect> => { + calls += 1 + return Effect.succeed({ data: [{ id: "only", value: 1 }], has_more: false }) + }, { getId: (item) => item.id }) + + expect(await Effect.runPromise(Stream.runCollect(stream))).toEqual([{ id: "only", value: 1 }]) + expect(calls).toBe(1) + }) + + test("keeps cursor tracking local to each stream subscription", async () => { + let calls = 0 + const stream = paginateBridge({}, (_query): Effect.Effect> => { + calls += 1 + return Effect.succeed({ data: [{ id: "one", value: 1 }], has_more: false }) + }, { getId: (item) => item.id }) + + const first = await Effect.runPromise(Stream.runCollect(stream)) + const second = await Effect.runPromise(Stream.runCollect(stream)) + + expect(first).toEqual([{ id: "one", value: 1 }]) + expect(second).toEqual([{ id: "one", value: 1 }]) + expect(calls).toBe(2) + }) + + test("collects standard pages through the Effect helper", async () => { + const items = await Effect.runPromise(paginateBridgeEffect( + {}, + (): Effect.Effect> => Effect.succeed({ data: [{ id: "one", value: 1 }], has_more: false }), + { getId: (item) => item.id } + )) + + expect(items).toEqual([{ id: "one", value: 1 }]) + }) + + test("streams reward cursors with preserved filters and a 90 item maximum", async () => { + const requests: Array = [] + const filters = { currency: "usdb", status: "distributed", limit: 3, cursor: "ignored" } as const + const stream = paginateBridgeRewards( + filters, + (query): Effect.Effect> => { + requests.push(query) + if (query.cursor === "ignored") { + return Effect.succeed({ + data: [{ date: "2026-09-01", amount: "1.25" }], + pagination: { has_more: true, next_cursor: "opaque-next" } + }) + } + return Effect.succeed({ + data: [{ date: "2026-09-02", amount: "1.50" }], + pagination: { has_more: false, next_cursor: null } + }) + }, + { limit: 120 } + ) + + const rewards = await Effect.runPromise(Stream.runCollect(stream)) + + expect(rewards).toEqual([ + { date: "2026-09-01", amount: "1.25" }, + { date: "2026-09-02", amount: "1.50" } + ]) + expect(requests).toEqual([ + { currency: "usdb", status: "distributed", limit: 90, cursor: "ignored" }, + { currency: "usdb", status: "distributed", limit: 90, cursor: "opaque-next" } + ]) + }) + + test("stops an empty reward page even if its metadata advertises another cursor", async () => { + let calls = 0 + const stream = paginateBridgeRewards({}, (_query): Effect.Effect> => { + calls += 1 + return Effect.succeed({ + data: [], + pagination: { has_more: true, next_cursor: "another-page" } + }) + }) + + expect(await Effect.runPromise(Stream.runCollect(stream))).toEqual([]) + expect(calls).toBe(1) + }) + + test("collects reward pages through the Effect helper", async () => { + const rewards = await Effect.runPromise(paginateBridgeRewardsEffect( + {}, + (): Effect.Effect> => Effect.succeed({ + data: [{ date: "2026-09-03", amount: "2.00" }], + pagination: { has_more: false } + }) + )) + + expect(rewards).toEqual([{ date: "2026-09-03", amount: "2.00" }]) + }) + + test("preserves fetch errors through the Effect helper", async () => { + const error = { _tag: "PageFetchFailure" as const } + const result = await Effect.runPromise(Effect.flip(paginateBridgeEffect( + {}, + (): Effect.Effect, typeof error> => Effect.fail(error), + { getId: (item) => item.id } + ))) + + expect(result).toBe(error) + }) + + test("fails on invalid lower limits before calling the endpoint", async () => { + let calls = 0 + const error = await Effect.runPromise(Effect.flip(Stream.runCollect(paginateBridge( + {}, + (): Effect.Effect> => { + calls += 1 + return Effect.succeed({ data: [] }) + }, + { limit: 0, getId: (item) => item.id } + )))) + + expect(error).toBeInstanceOf(BridgePaginationLimitError) + expect(calls).toBe(0) + }) + + test("does not fetch another page after an early take", async () => { + let calls = 0 + const stream = paginateBridge({}, (_query): Effect.Effect> => { + calls += 1 + return Effect.succeed({ + data: [{ id: "one", value: 1 }, { id: "two", value: 2 }], + has_more: true + }) + }, { getId: (item) => item.id }) + + expect(await Effect.runPromise(Stream.runCollect(Stream.take(stream, 1)))).toEqual([{ id: "one", value: 1 }]) + expect(calls).toBe(1) + }) + + test("interrupts an in-flight page fetch", async () => { + let signal: AbortSignal | undefined + let signalStarted: () => void = () => undefined + const started = new Promise((resolve) => { + signalStarted = resolve + }) + const stream = paginateBridge({}, (_query) => + Effect.tryPromise({ + try: (abortSignal) => { + signal = abortSignal + signalStarted() + return new Promise>(() => undefined) + }, + catch: (cause) => cause + }), + { getId: (item) => item.id } + ) + + const fiber = Effect.runFork(Stream.runDrain(stream)) + await started + await Effect.runPromise(Fiber.interrupt(fiber)) + + expect(signal?.aborted).toBe(true) + }) +}) diff --git a/packages/bridge/tests/support/controlled-http.ts b/packages/bridge/tests/support/controlled-http.ts new file mode 100644 index 0000000..278338c --- /dev/null +++ b/packages/bridge/tests/support/controlled-http.ts @@ -0,0 +1,60 @@ +import * as Effect from "effect/Effect" +import * as HttpClient from "effect/unstable/http/HttpClient" +import * as HttpClientRequest from "effect/unstable/http/HttpClientRequest" +import * as HttpClientResponse from "effect/unstable/http/HttpClientResponse" + +export interface HttpFixture { + readonly method: string + readonly path: string + readonly status?: number + readonly body: unknown + readonly headers?: Readonly> +} + +export interface RecordedRequest { + readonly request: HttpClientRequest.HttpClientRequest + readonly url: URL + readonly signal: AbortSignal +} + +const responseBody = (body: unknown) => { + if (body === null || body === undefined) return null + if (body instanceof Uint8Array) return body + return JSON.stringify(body) +} + +/** A strict local fake: any request without an explicit method/path fixture defects. */ +export const controlledHttpClient = (fixtures: ReadonlyArray) => { + const calls: Array = [] + const client = HttpClient.make((request, url, signal) => { + calls.push({ request, url, signal }) + const fixture = fixtures.find((candidate) => candidate.method === request.method && candidate.path === url.pathname) + if (fixture === undefined) { + return Effect.die(new Error(`Unexpected Bridge fixture request: ${request.method} ${url.pathname}`)) + } + const headers = new Headers(fixture.headers) + if (!headers.has("content-type") && !(fixture.body instanceof Uint8Array)) { + headers.set("content-type", "application/json") + } + return Effect.succeed(HttpClientResponse.fromWeb( + request, + new Response(responseBody(fixture.body), { + status: fixture.status ?? 200, + headers + }) + )) + }) + return { client, calls } as const +} + +/** Decode JSON serialized by the generated endpoint client for request assertions. */ +export const requestJson = (request: HttpClientRequest.HttpClientRequest): unknown => { + const body = request.body + if (body._tag === "Empty") return undefined + if (body._tag === "Uint8Array") return JSON.parse(new TextDecoder().decode(body.body)) as unknown + if (body._tag !== "Raw") throw new Error(`Expected JSON request body, received ${body._tag}`) + const value = body.body + if (typeof value === "string") return JSON.parse(value) as unknown + if (value instanceof Uint8Array) return JSON.parse(new TextDecoder().decode(value)) as unknown + throw new Error(`Expected a serialized JSON request body, received ${typeof value}`) +} diff --git a/packages/bridge/tests/support/openapi.ts b/packages/bridge/tests/support/openapi.ts new file mode 100644 index 0000000..a015ef7 --- /dev/null +++ b/packages/bridge/tests/support/openapi.ts @@ -0,0 +1,82 @@ +export type HttpMethod = "get" | "post" | "put" | "patch" | "delete" | "head" | "options" + +export type OpenApiRecord = Record + +export interface OperationEntry { + readonly method: HttpMethod + readonly path: string + readonly pathItem: OpenApiRecord + readonly operation: OpenApiRecord +} + +export interface ParameterEntry { + readonly location: string + readonly name: string + readonly required: boolean +} + +export const httpMethods: ReadonlyArray = ["get", "post", "put", "patch", "delete", "head", "options"] + +export const isRecord = (value: unknown): value is OpenApiRecord => + typeof value === "object" && value !== null && !Array.isArray(value) + +export const asRecord = (value: unknown): OpenApiRecord => { + if (!isRecord(value)) throw new Error("Expected an OpenAPI object") + return value +} + +export const asArray = (value: unknown): ReadonlyArray => { + if (!Array.isArray(value)) throw new Error("Expected an OpenAPI array") + return value +} + +export const resolveLocalRef = (root: unknown, value: unknown): unknown => { + let current = value + const seen = new Set() + while (isRecord(current) && typeof current.$ref === "string") { + const ref = current.$ref + if (!ref.startsWith("#/")) throw new Error(`Unexpected non-local OpenAPI reference: ${ref}`) + if (seen.has(ref)) throw new Error(`Circular OpenAPI reference: ${ref}`) + seen.add(ref) + const segments = ref.slice(2).split("/").map((segment) => segment.replace(/~1/g, "/").replace(/~0/g, "~")) + current = segments.reduce((cursor, segment) => isRecord(cursor) ? cursor[segment] : undefined, root) + } + return current +} + +export const listOperations = (spec: unknown): ReadonlyArray => { + const paths = asRecord(asRecord(spec).paths) + const operations: Array = [] + for (const [path, pathItemValue] of Object.entries(paths)) { + const pathItem = asRecord(pathItemValue) + for (const method of httpMethods) { + const operation = pathItem[method] + if (operation !== undefined) operations.push({ method, path, pathItem, operation: asRecord(operation) }) + } + } + return operations +} + +export const getParameters = (root: unknown, pathItem: OpenApiRecord, operation: OpenApiRecord): ReadonlyArray => { + const byIdentity = new Map() + for (const parameterValue of [...asArray(pathItem.parameters ?? []), ...asArray(operation.parameters ?? [])]) { + const parameter = asRecord(resolveLocalRef(root, parameterValue)) + const location = typeof parameter.in === "string" ? parameter.in : "" + const name = typeof parameter.name === "string" ? parameter.name : "" + if (location.length === 0 || name.length === 0) throw new Error("OpenAPI parameter needs a name and location") + byIdentity.set(`${location}:${name}`, { + location, + name, + required: parameter.required === true + }) + } + return [...byIdentity.values()].sort((left, right) => + left.location.localeCompare(right.location) || left.name.localeCompare(right.name) + ) +} + +export const responseMediaTypes = (root: unknown, value: unknown): ReadonlyArray => { + const response = asRecord(resolveLocalRef(root, value)) + if (response.content === undefined) return [] + return Object.keys(asRecord(response.content)).sort() +} diff --git a/packages/bridge/tests/webhooks.test.ts b/packages/bridge/tests/webhooks.test.ts new file mode 100644 index 0000000..92e196a --- /dev/null +++ b/packages/bridge/tests/webhooks.test.ts @@ -0,0 +1,246 @@ +// Copyright (c) Miso Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +import { describe, expect, test } from "bun:test"; +import { Clock, Effect, Schema } from "effect"; +import { + BRIDGE_WEBHOOK_EVENT_CATEGORIES, + WEBHOOK_MAX_AGE_MILLISECONDS, + WebhookError, + isKnownWebhookEventCategory, + type WebhookErrorCode, + verifyAndDecodeWebhookEvent, + verifyWebhookSignature, +} from "../src/Webhooks.ts"; +import { + INVALID_JSON_RAW_BODY, + INVALID_JSON_SIGNATURE_HEADER, + VECTOR_PUBLIC_KEY_PEM, + VECTOR_RAW_BODY, + VECTOR_SIGNATURE_HEADER, + VECTOR_TIMESTAMP, +} from "./fixtures/webhooks/vectors.ts"; + +function clockAt(nowMilliseconds: number): Clock.Clock { + const nowNanoseconds = BigInt(nowMilliseconds) * 1_000_000n; + return { + currentTimeMillisUnsafe: () => nowMilliseconds, + currentTimeMillis: Effect.succeed(nowMilliseconds), + monotonicTimeNanosUnsafe: () => nowNanoseconds, + monotonicTimeNanos: Effect.succeed(nowNanoseconds), + currentTimeNanosUnsafe: () => nowNanoseconds, + currentTimeNanos: Effect.succeed(nowNanoseconds), + sleep: () => Effect.void, + }; +} + +function runAt(effect: Effect.Effect, nowMilliseconds = VECTOR_TIMESTAMP): Promise { + return Effect.runPromise(Effect.provideService(effect, Clock.Clock, clockAt(nowMilliseconds))); +} + +function verify( + rawBody: Uint8Array = VECTOR_RAW_BODY, + signatureHeader = VECTOR_SIGNATURE_HEADER, + publicKey: string | CryptoKey = VECTOR_PUBLIC_KEY_PEM, +) { + return verifyWebhookSignature({ rawBody, signatureHeader, publicKey }); +} + +function bufferSubarrayForVector() { + const prefix = Buffer.from("request-body:"); + const backing = Buffer.concat([ + prefix, + Buffer.from(VECTOR_RAW_BODY), + Buffer.from(":end"), + ]); + const rawBody = backing.subarray(prefix.length, prefix.length + VECTOR_RAW_BODY.length); + const amountOffset = rawBody.indexOf(Buffer.from("1.00")); + if (amountOffset < 0) throw new Error("Webhook vector amount was not found"); + + return { + rawBody, + mutateAmount: () => rawBody.set(Buffer.from("9.99"), amountOffset), + }; +} + +async function failureOf(effect: Effect.Effect): Promise { + return runAt(Effect.flip(effect)); +} + +describe("Bridge webhooks", () => { + test("verifies the independently generated Bridge double-hash vector", async () => { + await expect(runAt(verify())).resolves.toBeUndefined(); + }); + + test("copies Buffer subarray bytes before awaiting the clock", async () => { + const { rawBody, mutateAmount } = bufferSubarrayForVector(); + let mutatedAtClock = false; + const clock = { + ...clockAt(VECTOR_TIMESTAMP), + currentTimeMillis: Effect.sync(() => { + mutateAmount(); + mutatedAtClock = true; + return VECTOR_TIMESTAMP; + }), + }; + + await expect(Effect.runPromise(Effect.provideService(verify(rawBody), Clock.Clock, clock))) + .resolves.toBeUndefined(); + expect(mutatedAtClock).toBe(true); + expect(rawBody.toString("utf8")).toContain('"amount":"9.99"'); + }); + + test("uses the exact body bytes and rejects body tampering", async () => { + const alteredBody = VECTOR_RAW_BODY.slice(); + alteredBody[alteredBody.length - 2] = alteredBody[alteredBody.length - 2]! ^ 1; + + const error = await failureOf(verify(alteredBody)); + expect(error.code).toBe("invalid_signature"); + }); + + test("accepts the exact max-age boundary and rejects older deliveries", async () => { + await expect(runAt(verify(), VECTOR_TIMESTAMP + WEBHOOK_MAX_AGE_MILLISECONDS)).resolves.toBeUndefined(); + + const expired = await failureOf(verify( + VECTOR_RAW_BODY, + `t=${VECTOR_TIMESTAMP - WEBHOOK_MAX_AGE_MILLISECONDS - 1},v0=${VECTOR_SIGNATURE_HEADER.split("v0=")[1]}`, + )); + expect(expired.code).toBe("timestamp_expired"); + }); + + test("rejects future timestamps unless an explicit skew allowance covers them", async () => { + const future = await runAt(Effect.flip(verify()), VECTOR_TIMESTAMP - 1); + expect(future.code).toBe("timestamp_in_future"); + + await expect(runAt( + verifyWebhookSignature({ + rawBody: VECTOR_RAW_BODY, + signatureHeader: VECTOR_SIGNATURE_HEADER, + publicKey: VECTOR_PUBLIC_KEY_PEM, + maxFutureSkewMilliseconds: 1, + }), + VECTOR_TIMESTAMP - 1, + )).resolves.toBeUndefined(); + }); + + test("strictly parses the signature header, timestamp, and base64", async () => { + const encodedSignature = VECTOR_SIGNATURE_HEADER.split("v0=")[1]!; + const invalidInputs: ReadonlyArray = [ + [`v0=${encodedSignature},t=${VECTOR_TIMESTAMP}`, "invalid_signature_header"], + [`t=${VECTOR_TIMESTAMP},v0=${encodedSignature},v0=${encodedSignature}`, "invalid_signature_header"], + [`t=${VECTOR_TIMESTAMP},v0=${encodedSignature} `, "invalid_base64"], + [`t=01790164800000,v0=${encodedSignature}`, "invalid_timestamp"], + [`t=1e3,v0=${encodedSignature}`, "invalid_timestamp"], + [`t=9007199254740992,v0=${encodedSignature}`, "invalid_timestamp"], + [`t=${VECTOR_TIMESTAMP},v0=AAA`, "invalid_base64"], + [`t=${VECTOR_TIMESTAMP},v0=AB==`, "invalid_base64"], + ]; + + for (const [header, expectedCode] of invalidInputs) { + const error = await failureOf(verify(VECTOR_RAW_BODY, header)); + expect(error.code).toBe(expectedCode); + } + }); + + test("rejects malformed public keys without exposing cryptographic details", async () => { + const error = await failureOf(verify(VECTOR_RAW_BODY, VECTOR_SIGNATURE_HEADER, "not a PEM key")); + expect(error.code).toBe("invalid_public_key"); + expect(error.message).not.toContain("not a PEM key"); + }); + + test("verifies before JSON and schema decoding, while preserving unknown categories", async () => { + let decodeCalls = 0; + const eventSchema = Schema.Struct({ + api_version: Schema.String, + event_id: Schema.String, + event_category: Schema.String, + event_type: Schema.String, + event_object_id: Schema.String, + event_object: Schema.Struct({ + id: Schema.String, + amount: Schema.String, + }), + event_object_changes: Schema.Unknown, + event_created_at: Schema.String, + }); + const decode = (input: unknown) => { + decodeCalls += 1; + return Schema.decodeUnknownEffect(eventSchema)(input); + }; + + const event = await runAt(verifyAndDecodeWebhookEvent({ + rawBody: VECTOR_RAW_BODY, + signatureHeader: VECTOR_SIGNATURE_HEADER, + publicKey: VECTOR_PUBLIC_KEY_PEM, + decode, + })); + + expect(decodeCalls).toBe(1); + expect(event.event_category).toBe("future.category"); + expect(isKnownWebhookEventCategory(event.event_category)).toBe(false); + expect(BRIDGE_WEBHOOK_EVENT_CATEGORIES).toContain("transfer"); + + const tamperedBody = VECTOR_RAW_BODY.slice(); + tamperedBody[0] = tamperedBody[0]! ^ 1; + const failed = await runAt(Effect.flip(verifyAndDecodeWebhookEvent({ + rawBody: tamperedBody, + signatureHeader: VECTOR_SIGNATURE_HEADER, + publicKey: VECTOR_PUBLIC_KEY_PEM, + decode, + }))); + expect(failed).toMatchObject({ _tag: "WebhookError", code: "invalid_signature" }); + expect(decodeCalls).toBe(1); + }); + + test("decodes the authenticated snapshot when a Buffer subarray changes during RSA verification", async () => { + const { rawBody, mutateAmount } = bufferSubarrayForVector(); + const subtle = globalThis.crypto.subtle; + const originalVerify = subtle.verify.bind(subtle); + const originalDescriptor = Object.getOwnPropertyDescriptor(subtle, "verify"); + let mutatedDuringVerify = false; + const verifyWithMutation: SubtleCrypto["verify"] = async (algorithm, key, signature, data) => { + mutateAmount(); + mutatedDuringVerify = true; + return originalVerify(algorithm, key, signature, data); + }; + + subtle.verify = verifyWithMutation; + try { + const event = await runAt(verifyAndDecodeWebhookEvent({ + rawBody, + signatureHeader: VECTOR_SIGNATURE_HEADER, + publicKey: VECTOR_PUBLIC_KEY_PEM, + decode: Schema.decodeUnknownEffect(Schema.Struct({ + event_object: Schema.Struct({ amount: Schema.String }), + })), + })); + + expect(mutatedDuringVerify).toBe(true); + expect(rawBody.toString("utf8")).toContain('"amount":"9.99"'); + expect(event.event_object.amount).toBe("1.00"); + } finally { + if (originalDescriptor) { + Object.defineProperty(subtle, "verify", originalDescriptor); + } else { + Reflect.deleteProperty(subtle, "verify"); + } + } + }); + + test("rejects validly signed malformed UTF-8 JSON before invoking the schema decoder", async () => { + let decodeCalls = 0; + const decoder = (input: unknown) => { + decodeCalls += 1; + return Effect.succeed(input); + }; + const error = await runAt(Effect.flip(verifyAndDecodeWebhookEvent({ + rawBody: INVALID_JSON_RAW_BODY, + signatureHeader: INVALID_JSON_SIGNATURE_HEADER, + publicKey: VECTOR_PUBLIC_KEY_PEM, + decode: decoder, + }))); + + expect(error).toMatchObject({ _tag: "WebhookError", code: "invalid_json" }); + expect(decodeCalls).toBe(0); + }); +}); diff --git a/packages/bridge/tsconfig.build.json b/packages/bridge/tsconfig.build.json new file mode 100644 index 0000000..8134752 --- /dev/null +++ b/packages/bridge/tsconfig.build.json @@ -0,0 +1,18 @@ +{ + "extends": "./tsconfig.json", + "include": ["src"], + "exclude": ["tests"], + "compilerOptions": { + "noEmit": false, + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "module": "nodenext", + "moduleResolution": "nodenext", + "rewriteRelativeImportExtensions": true, + "allowImportingTsExtensions": true, + "lib": ["ESNext"], + "rootDir": "src", + "outDir": "dist" + } +} diff --git a/packages/bridge/tsconfig.json b/packages/bridge/tsconfig.json new file mode 100644 index 0000000..b2899e2 --- /dev/null +++ b/packages/bridge/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["scripts", "src", "tests"], + "exclude": ["tests/consumer"], + "compilerOptions": { + "types": ["bun"], + "exactOptionalPropertyTypes": true, + "noEmit": true + } +}