@stridge/openapi 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -25,6 +25,10 @@
25
25
  "name": "UDA",
26
26
  "description": "Universal Deposit Addresses — allocate cross-chain deposit addresses, fetch indicative quotes, and track settlements.\n"
27
27
  },
28
+ {
29
+ "name": "Routing Policies",
30
+ "description": "Tenant-scoped, centrally-editable routing policies — ordered, first-match-wins rule sets that divert UDA settlements. Editing a policy applies to every UDA that references it (or inherits the tenant default) with no per-UDA changes. Read-only over the API; create and edit them from the dashboard. Routing policies apply to UDA settlements only — gateway flows ignore them.\n"
31
+ },
28
32
  {
29
33
  "name": "Payout",
30
34
  "description": "Non-custodial vaults and the payouts they fund. Inspect a vault's addresses, per-asset balances, and total value, then send funds from a vault to an external address — payouts are idempotent by reference, tracked through a lifecycle, and have native gas funded automatically.\n"
@@ -292,6 +296,11 @@
292
296
  }
293
297
  }
294
298
  }
299
+ },
300
+ "routing_policy_id": {
301
+ "type": "string",
302
+ "description": "The routing policy attached to this UDA, when set. Omitted for legacy UDAs that inherit the tenant default policy.\n",
303
+ "example": "rpol_2f8c1a9d4e5f6071"
295
304
  }
296
305
  }
297
306
  }
@@ -540,6 +549,11 @@
540
549
  ]
541
550
  },
542
551
  "description": "Optional; max 3. Specificity-wins precedence: a rule pinning both `source_network_id` and `source_asset_symbol` beats a network-only rule. When nothing matches, settlements use the default destination.\n"
552
+ },
553
+ "routing_policy_id": {
554
+ "type": "string",
555
+ "description": "Routing policy to attach to this UDA. Omit or send an empty string to attach the tenant's default policy. Per-UDA inline `routing_rules` still take precedence over the policy.\n",
556
+ "example": "rpol_2f8c1a9d4e5f6071"
543
557
  }
544
558
  },
545
559
  "required": [
@@ -734,6 +748,11 @@
734
748
  }
735
749
  }
736
750
  }
751
+ },
752
+ "routing_policy_id": {
753
+ "type": "string",
754
+ "description": "The routing policy attached to this UDA, when set. Omitted for legacy UDAs that inherit the tenant default policy.\n",
755
+ "example": "rpol_2f8c1a9d4e5f6071"
737
756
  }
738
757
  }
739
758
  }
@@ -911,6 +930,11 @@
911
930
  }
912
931
  }
913
932
  }
933
+ },
934
+ "routing_policy_id": {
935
+ "type": "string",
936
+ "description": "The routing policy attached to this UDA, when set. Omitted for legacy UDAs that inherit the tenant default policy.\n",
937
+ "example": "rpol_2f8c1a9d4e5f6071"
914
938
  }
915
939
  }
916
940
  }
@@ -5537,235 +5561,737 @@
5537
5561
  }
5538
5562
  }
5539
5563
  }
5540
- }
5541
- },
5542
- "components": {
5543
- "securitySchemes": {
5544
- "ApiKeyAuth": {
5545
- "type": "apiKey",
5546
- "in": "header",
5547
- "name": "X-API-Key",
5548
- "description": "Secret API key for programmatic access. Send it on every authenticated request. Keep it server-side; never ship it in a client bundle.\n"
5549
- }
5550
- },
5551
- "parameters": {
5552
- "LimitParam": {
5553
- "name": "limit",
5554
- "in": "query",
5555
- "description": "Page size (default 50, max 200).",
5556
- "schema": {
5557
- "type": "integer",
5558
- "default": 50,
5559
- "minimum": 1,
5560
- "maximum": 200
5561
- }
5562
- },
5563
- "OffsetParam": {
5564
- "name": "offset",
5565
- "in": "query",
5566
- "description": "Number of items to skip (default 0).",
5567
- "schema": {
5568
- "type": "integer",
5569
- "default": 0,
5570
- "minimum": 0
5571
- }
5572
- },
5573
- "VaultIdParam": {
5574
- "name": "vault_id",
5575
- "in": "path",
5576
- "required": true,
5577
- "description": "Vault id.",
5578
- "schema": {
5579
- "type": "string"
5580
- }
5581
- },
5582
- "PageParam": {
5583
- "name": "page",
5584
- "in": "query",
5585
- "description": "Page number (default 1).",
5586
- "schema": {
5587
- "type": "integer",
5588
- "default": 1,
5589
- "minimum": 1
5590
- }
5591
- },
5592
- "PageSizeParam": {
5593
- "name": "limit",
5594
- "in": "query",
5595
- "description": "Items per page (default 20, max 100).",
5596
- "schema": {
5597
- "type": "integer",
5598
- "default": 20,
5599
- "minimum": 1,
5600
- "maximum": 100
5601
- }
5602
- }
5603
5564
  },
5604
- "responses": {
5605
- "BadRequest": {
5606
- "description": "The request was malformed or failed validation.",
5607
- "content": {
5608
- "application/json": {
5609
- "schema": {
5610
- "type": "object",
5611
- "description": "Canonical error envelope returned by every endpoint on failure.",
5612
- "properties": {
5613
- "success": {
5614
- "type": "boolean",
5615
- "example": false
5616
- },
5617
- "code": {
5618
- "type": "integer",
5619
- "description": "HTTP status code echoed in the body.",
5620
- "example": 400
5621
- },
5622
- "error": {
5623
- "type": "string",
5624
- "description": "Human-readable error message.",
5625
- "example": "invalid request"
5626
- }
5627
- },
5628
- "required": [
5629
- "success",
5630
- "error"
5631
- ]
5632
- },
5633
- "example": {
5634
- "success": false,
5635
- "code": 400,
5636
- "error": "invalid request"
5637
- }
5638
- }
5639
- }
5640
- },
5641
- "Unauthorized": {
5642
- "description": "The `X-API-Key` header is missing or invalid.",
5643
- "content": {
5644
- "application/json": {
5645
- "schema": {
5646
- "type": "object",
5647
- "description": "Canonical error envelope returned by every endpoint on failure.",
5648
- "properties": {
5649
- "success": {
5650
- "type": "boolean",
5651
- "example": false
5652
- },
5653
- "code": {
5654
- "type": "integer",
5655
- "description": "HTTP status code echoed in the body.",
5656
- "example": 400
5657
- },
5658
- "error": {
5659
- "type": "string",
5660
- "description": "Human-readable error message.",
5661
- "example": "invalid request"
5662
- }
5663
- },
5664
- "required": [
5665
- "success",
5666
- "error"
5667
- ]
5668
- },
5669
- "example": {
5670
- "success": false,
5671
- "code": 401,
5672
- "error": "unauthenticated"
5673
- }
5565
+ "/routing-policies": {
5566
+ "get": {
5567
+ "operationId": "list-routing-policies",
5568
+ "tags": [
5569
+ "Routing Policies"
5570
+ ],
5571
+ "summary": "List routing policies",
5572
+ "description": "List the routing policies configured for your tenant, including the default policy. Read-only — create and edit policies from the dashboard.\n",
5573
+ "security": [
5574
+ {
5575
+ "ApiKeyAuth": []
5674
5576
  }
5675
- }
5676
- },
5677
- "NotFound": {
5678
- "description": "The requested resource does not exist.",
5679
- "content": {
5680
- "application/json": {
5577
+ ],
5578
+ "parameters": [
5579
+ {
5580
+ "name": "limit",
5581
+ "in": "query",
5582
+ "description": "Page size (default 50, max 200).",
5681
5583
  "schema": {
5682
- "type": "object",
5683
- "description": "Canonical error envelope returned by every endpoint on failure.",
5684
- "properties": {
5685
- "success": {
5686
- "type": "boolean",
5687
- "example": false
5688
- },
5689
- "code": {
5690
- "type": "integer",
5691
- "description": "HTTP status code echoed in the body.",
5692
- "example": 400
5693
- },
5694
- "error": {
5695
- "type": "string",
5696
- "description": "Human-readable error message.",
5697
- "example": "invalid request"
5698
- }
5699
- },
5700
- "required": [
5701
- "success",
5702
- "error"
5703
- ]
5704
- },
5705
- "example": {
5706
- "success": false,
5707
- "code": 404,
5708
- "error": "not found"
5584
+ "type": "integer",
5585
+ "default": 50,
5586
+ "minimum": 1,
5587
+ "maximum": 200
5709
5588
  }
5710
- }
5711
- }
5712
- },
5713
- "ServerError": {
5714
- "description": "An unexpected error occurred on the server.",
5715
- "content": {
5716
- "application/json": {
5589
+ },
5590
+ {
5591
+ "name": "offset",
5592
+ "in": "query",
5593
+ "description": "Number of items to skip (default 0).",
5717
5594
  "schema": {
5718
- "type": "object",
5719
- "description": "Canonical error envelope returned by every endpoint on failure.",
5720
- "properties": {
5721
- "success": {
5722
- "type": "boolean",
5723
- "example": false
5724
- },
5725
- "code": {
5726
- "type": "integer",
5727
- "description": "HTTP status code echoed in the body.",
5728
- "example": 400
5729
- },
5730
- "error": {
5731
- "type": "string",
5732
- "description": "Human-readable error message.",
5733
- "example": "invalid request"
5734
- }
5735
- },
5736
- "required": [
5737
- "success",
5738
- "error"
5739
- ]
5740
- },
5741
- "example": {
5742
- "success": false,
5743
- "code": 500,
5744
- "error": "internal server error"
5595
+ "type": "integer",
5596
+ "default": 0,
5597
+ "minimum": 0
5745
5598
  }
5746
5599
  }
5747
- }
5748
- }
5749
- },
5750
- "schemas": {
5751
- "Error": {
5752
- "type": "object",
5753
- "description": "Canonical error envelope returned by every endpoint on failure.",
5754
- "properties": {
5755
- "success": {
5756
- "type": "boolean",
5757
- "example": false
5758
- },
5759
- "code": {
5760
- "type": "integer",
5761
- "description": "HTTP status code echoed in the body.",
5762
- "example": 400
5763
- },
5764
- "error": {
5765
- "type": "string",
5766
- "description": "Human-readable error message.",
5767
- "example": "invalid request"
5768
- }
5600
+ ],
5601
+ "responses": {
5602
+ "200": {
5603
+ "description": "A page of routing policies.",
5604
+ "content": {
5605
+ "application/json": {
5606
+ "schema": {
5607
+ "type": "object",
5608
+ "properties": {
5609
+ "data": {
5610
+ "type": "array",
5611
+ "items": {
5612
+ "type": "object",
5613
+ "description": "A tenant-scoped, ordered routing-policy. Rules are evaluated first-match-wins; an empty rule set falls through to the UDA's default destination.\n",
5614
+ "properties": {
5615
+ "id": {
5616
+ "type": "string",
5617
+ "example": "rpol_2f8c1a9d4e5f6071"
5618
+ },
5619
+ "name": {
5620
+ "type": "string",
5621
+ "example": "vip_tier"
5622
+ },
5623
+ "is_default": {
5624
+ "type": "boolean",
5625
+ "description": "Whether this is the tenant's default policy (one per tenant).",
5626
+ "example": false
5627
+ },
5628
+ "rules": {
5629
+ "type": "array",
5630
+ "description": "Ordered, first-match-wins routing rules (dual form).",
5631
+ "items": {
5632
+ "type": "object",
5633
+ "description": "An echoed routing rule in dual form (symbol plus resolved contract address).",
5634
+ "properties": {
5635
+ "match": {
5636
+ "type": "object",
5637
+ "properties": {
5638
+ "source_network_id": {
5639
+ "type": "string",
5640
+ "example": "60"
5641
+ },
5642
+ "source_asset_symbol": {
5643
+ "type": "string",
5644
+ "example": "USDT"
5645
+ },
5646
+ "source_token_address": {
5647
+ "type": "string",
5648
+ "example": "0xdAC17F958D2ee523a2206206994597C13D831ec7"
5649
+ }
5650
+ }
5651
+ },
5652
+ "destination": {
5653
+ "type": "object",
5654
+ "properties": {
5655
+ "address": {
5656
+ "type": "string",
5657
+ "example": "0x3a1f8b2c9d4e5f60718293a4b5c6d7e8f9012345"
5658
+ },
5659
+ "network_id": {
5660
+ "type": "string",
5661
+ "example": "60"
5662
+ },
5663
+ "eip155_id": {
5664
+ "type": "string",
5665
+ "example": "1"
5666
+ },
5667
+ "network_name": {
5668
+ "type": "string",
5669
+ "example": "Ethereum"
5670
+ },
5671
+ "asset_symbol": {
5672
+ "type": "string",
5673
+ "example": "USDC"
5674
+ },
5675
+ "asset_address": {
5676
+ "type": "string",
5677
+ "example": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
5678
+ },
5679
+ "asset_decimals": {
5680
+ "type": "integer",
5681
+ "example": 6
5682
+ }
5683
+ }
5684
+ }
5685
+ }
5686
+ }
5687
+ },
5688
+ "created_at": {
5689
+ "type": "string",
5690
+ "format": "date-time",
5691
+ "example": "2026-05-20T14:03:12Z"
5692
+ },
5693
+ "updated_at": {
5694
+ "type": "string",
5695
+ "format": "date-time",
5696
+ "example": "2026-05-20T14:03:12Z"
5697
+ }
5698
+ }
5699
+ }
5700
+ },
5701
+ "pagination": {
5702
+ "type": "object",
5703
+ "properties": {
5704
+ "count": {
5705
+ "type": "integer",
5706
+ "description": "Number of items in this page.",
5707
+ "example": 20
5708
+ },
5709
+ "limit": {
5710
+ "type": "integer",
5711
+ "example": 50
5712
+ },
5713
+ "offset": {
5714
+ "type": "integer",
5715
+ "example": 0
5716
+ }
5717
+ }
5718
+ }
5719
+ }
5720
+ }
5721
+ }
5722
+ }
5723
+ },
5724
+ "400": {
5725
+ "description": "The request was malformed or failed validation.",
5726
+ "content": {
5727
+ "application/json": {
5728
+ "schema": {
5729
+ "type": "object",
5730
+ "description": "Canonical error envelope returned by every endpoint on failure.",
5731
+ "properties": {
5732
+ "success": {
5733
+ "type": "boolean",
5734
+ "example": false
5735
+ },
5736
+ "code": {
5737
+ "type": "integer",
5738
+ "description": "HTTP status code echoed in the body.",
5739
+ "example": 400
5740
+ },
5741
+ "error": {
5742
+ "type": "string",
5743
+ "description": "Human-readable error message.",
5744
+ "example": "invalid request"
5745
+ }
5746
+ },
5747
+ "required": [
5748
+ "success",
5749
+ "error"
5750
+ ]
5751
+ },
5752
+ "example": {
5753
+ "success": false,
5754
+ "code": 400,
5755
+ "error": "invalid request"
5756
+ }
5757
+ }
5758
+ }
5759
+ },
5760
+ "401": {
5761
+ "description": "The `X-API-Key` header is missing or invalid.",
5762
+ "content": {
5763
+ "application/json": {
5764
+ "schema": {
5765
+ "type": "object",
5766
+ "description": "Canonical error envelope returned by every endpoint on failure.",
5767
+ "properties": {
5768
+ "success": {
5769
+ "type": "boolean",
5770
+ "example": false
5771
+ },
5772
+ "code": {
5773
+ "type": "integer",
5774
+ "description": "HTTP status code echoed in the body.",
5775
+ "example": 400
5776
+ },
5777
+ "error": {
5778
+ "type": "string",
5779
+ "description": "Human-readable error message.",
5780
+ "example": "invalid request"
5781
+ }
5782
+ },
5783
+ "required": [
5784
+ "success",
5785
+ "error"
5786
+ ]
5787
+ },
5788
+ "example": {
5789
+ "success": false,
5790
+ "code": 401,
5791
+ "error": "unauthenticated"
5792
+ }
5793
+ }
5794
+ }
5795
+ },
5796
+ "500": {
5797
+ "description": "An unexpected error occurred on the server.",
5798
+ "content": {
5799
+ "application/json": {
5800
+ "schema": {
5801
+ "type": "object",
5802
+ "description": "Canonical error envelope returned by every endpoint on failure.",
5803
+ "properties": {
5804
+ "success": {
5805
+ "type": "boolean",
5806
+ "example": false
5807
+ },
5808
+ "code": {
5809
+ "type": "integer",
5810
+ "description": "HTTP status code echoed in the body.",
5811
+ "example": 400
5812
+ },
5813
+ "error": {
5814
+ "type": "string",
5815
+ "description": "Human-readable error message.",
5816
+ "example": "invalid request"
5817
+ }
5818
+ },
5819
+ "required": [
5820
+ "success",
5821
+ "error"
5822
+ ]
5823
+ },
5824
+ "example": {
5825
+ "success": false,
5826
+ "code": 500,
5827
+ "error": "internal server error"
5828
+ }
5829
+ }
5830
+ }
5831
+ }
5832
+ }
5833
+ }
5834
+ },
5835
+ "/routing-policies/{id}": {
5836
+ "get": {
5837
+ "operationId": "get-routing-policy",
5838
+ "tags": [
5839
+ "Routing Policies"
5840
+ ],
5841
+ "summary": "Get a routing policy",
5842
+ "description": "Fetch a single routing policy by id.",
5843
+ "security": [
5844
+ {
5845
+ "ApiKeyAuth": []
5846
+ }
5847
+ ],
5848
+ "parameters": [
5849
+ {
5850
+ "name": "id",
5851
+ "in": "path",
5852
+ "required": true,
5853
+ "description": "Routing policy id.",
5854
+ "schema": {
5855
+ "type": "string"
5856
+ }
5857
+ }
5858
+ ],
5859
+ "responses": {
5860
+ "200": {
5861
+ "description": "The routing policy.",
5862
+ "content": {
5863
+ "application/json": {
5864
+ "schema": {
5865
+ "type": "object",
5866
+ "description": "A tenant-scoped, ordered routing-policy. Rules are evaluated first-match-wins; an empty rule set falls through to the UDA's default destination.\n",
5867
+ "properties": {
5868
+ "id": {
5869
+ "type": "string",
5870
+ "example": "rpol_2f8c1a9d4e5f6071"
5871
+ },
5872
+ "name": {
5873
+ "type": "string",
5874
+ "example": "vip_tier"
5875
+ },
5876
+ "is_default": {
5877
+ "type": "boolean",
5878
+ "description": "Whether this is the tenant's default policy (one per tenant).",
5879
+ "example": false
5880
+ },
5881
+ "rules": {
5882
+ "type": "array",
5883
+ "description": "Ordered, first-match-wins routing rules (dual form).",
5884
+ "items": {
5885
+ "type": "object",
5886
+ "description": "An echoed routing rule in dual form (symbol plus resolved contract address).",
5887
+ "properties": {
5888
+ "match": {
5889
+ "type": "object",
5890
+ "properties": {
5891
+ "source_network_id": {
5892
+ "type": "string",
5893
+ "example": "60"
5894
+ },
5895
+ "source_asset_symbol": {
5896
+ "type": "string",
5897
+ "example": "USDT"
5898
+ },
5899
+ "source_token_address": {
5900
+ "type": "string",
5901
+ "example": "0xdAC17F958D2ee523a2206206994597C13D831ec7"
5902
+ }
5903
+ }
5904
+ },
5905
+ "destination": {
5906
+ "type": "object",
5907
+ "properties": {
5908
+ "address": {
5909
+ "type": "string",
5910
+ "example": "0x3a1f8b2c9d4e5f60718293a4b5c6d7e8f9012345"
5911
+ },
5912
+ "network_id": {
5913
+ "type": "string",
5914
+ "example": "60"
5915
+ },
5916
+ "eip155_id": {
5917
+ "type": "string",
5918
+ "example": "1"
5919
+ },
5920
+ "network_name": {
5921
+ "type": "string",
5922
+ "example": "Ethereum"
5923
+ },
5924
+ "asset_symbol": {
5925
+ "type": "string",
5926
+ "example": "USDC"
5927
+ },
5928
+ "asset_address": {
5929
+ "type": "string",
5930
+ "example": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
5931
+ },
5932
+ "asset_decimals": {
5933
+ "type": "integer",
5934
+ "example": 6
5935
+ }
5936
+ }
5937
+ }
5938
+ }
5939
+ }
5940
+ },
5941
+ "created_at": {
5942
+ "type": "string",
5943
+ "format": "date-time",
5944
+ "example": "2026-05-20T14:03:12Z"
5945
+ },
5946
+ "updated_at": {
5947
+ "type": "string",
5948
+ "format": "date-time",
5949
+ "example": "2026-05-20T14:03:12Z"
5950
+ }
5951
+ }
5952
+ }
5953
+ }
5954
+ }
5955
+ },
5956
+ "401": {
5957
+ "description": "The `X-API-Key` header is missing or invalid.",
5958
+ "content": {
5959
+ "application/json": {
5960
+ "schema": {
5961
+ "type": "object",
5962
+ "description": "Canonical error envelope returned by every endpoint on failure.",
5963
+ "properties": {
5964
+ "success": {
5965
+ "type": "boolean",
5966
+ "example": false
5967
+ },
5968
+ "code": {
5969
+ "type": "integer",
5970
+ "description": "HTTP status code echoed in the body.",
5971
+ "example": 400
5972
+ },
5973
+ "error": {
5974
+ "type": "string",
5975
+ "description": "Human-readable error message.",
5976
+ "example": "invalid request"
5977
+ }
5978
+ },
5979
+ "required": [
5980
+ "success",
5981
+ "error"
5982
+ ]
5983
+ },
5984
+ "example": {
5985
+ "success": false,
5986
+ "code": 401,
5987
+ "error": "unauthenticated"
5988
+ }
5989
+ }
5990
+ }
5991
+ },
5992
+ "404": {
5993
+ "description": "The requested resource does not exist.",
5994
+ "content": {
5995
+ "application/json": {
5996
+ "schema": {
5997
+ "type": "object",
5998
+ "description": "Canonical error envelope returned by every endpoint on failure.",
5999
+ "properties": {
6000
+ "success": {
6001
+ "type": "boolean",
6002
+ "example": false
6003
+ },
6004
+ "code": {
6005
+ "type": "integer",
6006
+ "description": "HTTP status code echoed in the body.",
6007
+ "example": 400
6008
+ },
6009
+ "error": {
6010
+ "type": "string",
6011
+ "description": "Human-readable error message.",
6012
+ "example": "invalid request"
6013
+ }
6014
+ },
6015
+ "required": [
6016
+ "success",
6017
+ "error"
6018
+ ]
6019
+ },
6020
+ "example": {
6021
+ "success": false,
6022
+ "code": 404,
6023
+ "error": "not found"
6024
+ }
6025
+ }
6026
+ }
6027
+ },
6028
+ "500": {
6029
+ "description": "An unexpected error occurred on the server.",
6030
+ "content": {
6031
+ "application/json": {
6032
+ "schema": {
6033
+ "type": "object",
6034
+ "description": "Canonical error envelope returned by every endpoint on failure.",
6035
+ "properties": {
6036
+ "success": {
6037
+ "type": "boolean",
6038
+ "example": false
6039
+ },
6040
+ "code": {
6041
+ "type": "integer",
6042
+ "description": "HTTP status code echoed in the body.",
6043
+ "example": 400
6044
+ },
6045
+ "error": {
6046
+ "type": "string",
6047
+ "description": "Human-readable error message.",
6048
+ "example": "invalid request"
6049
+ }
6050
+ },
6051
+ "required": [
6052
+ "success",
6053
+ "error"
6054
+ ]
6055
+ },
6056
+ "example": {
6057
+ "success": false,
6058
+ "code": 500,
6059
+ "error": "internal server error"
6060
+ }
6061
+ }
6062
+ }
6063
+ }
6064
+ }
6065
+ }
6066
+ }
6067
+ },
6068
+ "components": {
6069
+ "securitySchemes": {
6070
+ "ApiKeyAuth": {
6071
+ "type": "apiKey",
6072
+ "in": "header",
6073
+ "name": "X-API-Key",
6074
+ "description": "Secret API key for programmatic access. Send it on every authenticated request. Keep it server-side; never ship it in a client bundle.\n"
6075
+ }
6076
+ },
6077
+ "parameters": {
6078
+ "LimitParam": {
6079
+ "name": "limit",
6080
+ "in": "query",
6081
+ "description": "Page size (default 50, max 200).",
6082
+ "schema": {
6083
+ "type": "integer",
6084
+ "default": 50,
6085
+ "minimum": 1,
6086
+ "maximum": 200
6087
+ }
6088
+ },
6089
+ "OffsetParam": {
6090
+ "name": "offset",
6091
+ "in": "query",
6092
+ "description": "Number of items to skip (default 0).",
6093
+ "schema": {
6094
+ "type": "integer",
6095
+ "default": 0,
6096
+ "minimum": 0
6097
+ }
6098
+ },
6099
+ "VaultIdParam": {
6100
+ "name": "vault_id",
6101
+ "in": "path",
6102
+ "required": true,
6103
+ "description": "Vault id.",
6104
+ "schema": {
6105
+ "type": "string"
6106
+ }
6107
+ },
6108
+ "PageParam": {
6109
+ "name": "page",
6110
+ "in": "query",
6111
+ "description": "Page number (default 1).",
6112
+ "schema": {
6113
+ "type": "integer",
6114
+ "default": 1,
6115
+ "minimum": 1
6116
+ }
6117
+ },
6118
+ "PageSizeParam": {
6119
+ "name": "limit",
6120
+ "in": "query",
6121
+ "description": "Items per page (default 20, max 100).",
6122
+ "schema": {
6123
+ "type": "integer",
6124
+ "default": 20,
6125
+ "minimum": 1,
6126
+ "maximum": 100
6127
+ }
6128
+ }
6129
+ },
6130
+ "responses": {
6131
+ "BadRequest": {
6132
+ "description": "The request was malformed or failed validation.",
6133
+ "content": {
6134
+ "application/json": {
6135
+ "schema": {
6136
+ "type": "object",
6137
+ "description": "Canonical error envelope returned by every endpoint on failure.",
6138
+ "properties": {
6139
+ "success": {
6140
+ "type": "boolean",
6141
+ "example": false
6142
+ },
6143
+ "code": {
6144
+ "type": "integer",
6145
+ "description": "HTTP status code echoed in the body.",
6146
+ "example": 400
6147
+ },
6148
+ "error": {
6149
+ "type": "string",
6150
+ "description": "Human-readable error message.",
6151
+ "example": "invalid request"
6152
+ }
6153
+ },
6154
+ "required": [
6155
+ "success",
6156
+ "error"
6157
+ ]
6158
+ },
6159
+ "example": {
6160
+ "success": false,
6161
+ "code": 400,
6162
+ "error": "invalid request"
6163
+ }
6164
+ }
6165
+ }
6166
+ },
6167
+ "Unauthorized": {
6168
+ "description": "The `X-API-Key` header is missing or invalid.",
6169
+ "content": {
6170
+ "application/json": {
6171
+ "schema": {
6172
+ "type": "object",
6173
+ "description": "Canonical error envelope returned by every endpoint on failure.",
6174
+ "properties": {
6175
+ "success": {
6176
+ "type": "boolean",
6177
+ "example": false
6178
+ },
6179
+ "code": {
6180
+ "type": "integer",
6181
+ "description": "HTTP status code echoed in the body.",
6182
+ "example": 400
6183
+ },
6184
+ "error": {
6185
+ "type": "string",
6186
+ "description": "Human-readable error message.",
6187
+ "example": "invalid request"
6188
+ }
6189
+ },
6190
+ "required": [
6191
+ "success",
6192
+ "error"
6193
+ ]
6194
+ },
6195
+ "example": {
6196
+ "success": false,
6197
+ "code": 401,
6198
+ "error": "unauthenticated"
6199
+ }
6200
+ }
6201
+ }
6202
+ },
6203
+ "NotFound": {
6204
+ "description": "The requested resource does not exist.",
6205
+ "content": {
6206
+ "application/json": {
6207
+ "schema": {
6208
+ "type": "object",
6209
+ "description": "Canonical error envelope returned by every endpoint on failure.",
6210
+ "properties": {
6211
+ "success": {
6212
+ "type": "boolean",
6213
+ "example": false
6214
+ },
6215
+ "code": {
6216
+ "type": "integer",
6217
+ "description": "HTTP status code echoed in the body.",
6218
+ "example": 400
6219
+ },
6220
+ "error": {
6221
+ "type": "string",
6222
+ "description": "Human-readable error message.",
6223
+ "example": "invalid request"
6224
+ }
6225
+ },
6226
+ "required": [
6227
+ "success",
6228
+ "error"
6229
+ ]
6230
+ },
6231
+ "example": {
6232
+ "success": false,
6233
+ "code": 404,
6234
+ "error": "not found"
6235
+ }
6236
+ }
6237
+ }
6238
+ },
6239
+ "ServerError": {
6240
+ "description": "An unexpected error occurred on the server.",
6241
+ "content": {
6242
+ "application/json": {
6243
+ "schema": {
6244
+ "type": "object",
6245
+ "description": "Canonical error envelope returned by every endpoint on failure.",
6246
+ "properties": {
6247
+ "success": {
6248
+ "type": "boolean",
6249
+ "example": false
6250
+ },
6251
+ "code": {
6252
+ "type": "integer",
6253
+ "description": "HTTP status code echoed in the body.",
6254
+ "example": 400
6255
+ },
6256
+ "error": {
6257
+ "type": "string",
6258
+ "description": "Human-readable error message.",
6259
+ "example": "invalid request"
6260
+ }
6261
+ },
6262
+ "required": [
6263
+ "success",
6264
+ "error"
6265
+ ]
6266
+ },
6267
+ "example": {
6268
+ "success": false,
6269
+ "code": 500,
6270
+ "error": "internal server error"
6271
+ }
6272
+ }
6273
+ }
6274
+ }
6275
+ },
6276
+ "schemas": {
6277
+ "Error": {
6278
+ "type": "object",
6279
+ "description": "Canonical error envelope returned by every endpoint on failure.",
6280
+ "properties": {
6281
+ "success": {
6282
+ "type": "boolean",
6283
+ "example": false
6284
+ },
6285
+ "code": {
6286
+ "type": "integer",
6287
+ "description": "HTTP status code echoed in the body.",
6288
+ "example": 400
6289
+ },
6290
+ "error": {
6291
+ "type": "string",
6292
+ "description": "Human-readable error message.",
6293
+ "example": "invalid request"
6294
+ }
5769
6295
  },
5770
6296
  "required": [
5771
6297
  "success",
@@ -6011,6 +6537,11 @@
6011
6537
  ]
6012
6538
  },
6013
6539
  "description": "Optional; max 3. Specificity-wins precedence: a rule pinning both `source_network_id` and `source_asset_symbol` beats a network-only rule. When nothing matches, settlements use the default destination.\n"
6540
+ },
6541
+ "routing_policy_id": {
6542
+ "type": "string",
6543
+ "description": "Routing policy to attach to this UDA. Omit or send an empty string to attach the tenant's default policy. Per-UDA inline `routing_rules` still take precedence over the policy.\n",
6544
+ "example": "rpol_2f8c1a9d4e5f6071"
6014
6545
  }
6015
6546
  },
6016
6547
  "required": [
@@ -6406,6 +6937,215 @@
6406
6937
  }
6407
6938
  }
6408
6939
  }
6940
+ },
6941
+ "routing_policy_id": {
6942
+ "type": "string",
6943
+ "description": "The routing policy attached to this UDA, when set. Omitted for legacy UDAs that inherit the tenant default policy.\n",
6944
+ "example": "rpol_2f8c1a9d4e5f6071"
6945
+ }
6946
+ }
6947
+ },
6948
+ "RoutingPolicy": {
6949
+ "type": "object",
6950
+ "description": "A tenant-scoped, ordered routing-policy. Rules are evaluated first-match-wins; an empty rule set falls through to the UDA's default destination.\n",
6951
+ "properties": {
6952
+ "id": {
6953
+ "type": "string",
6954
+ "example": "rpol_2f8c1a9d4e5f6071"
6955
+ },
6956
+ "name": {
6957
+ "type": "string",
6958
+ "example": "vip_tier"
6959
+ },
6960
+ "is_default": {
6961
+ "type": "boolean",
6962
+ "description": "Whether this is the tenant's default policy (one per tenant).",
6963
+ "example": false
6964
+ },
6965
+ "rules": {
6966
+ "type": "array",
6967
+ "description": "Ordered, first-match-wins routing rules (dual form).",
6968
+ "items": {
6969
+ "type": "object",
6970
+ "description": "An echoed routing rule in dual form (symbol plus resolved contract address).",
6971
+ "properties": {
6972
+ "match": {
6973
+ "type": "object",
6974
+ "properties": {
6975
+ "source_network_id": {
6976
+ "type": "string",
6977
+ "example": "60"
6978
+ },
6979
+ "source_asset_symbol": {
6980
+ "type": "string",
6981
+ "example": "USDT"
6982
+ },
6983
+ "source_token_address": {
6984
+ "type": "string",
6985
+ "example": "0xdAC17F958D2ee523a2206206994597C13D831ec7"
6986
+ }
6987
+ }
6988
+ },
6989
+ "destination": {
6990
+ "type": "object",
6991
+ "properties": {
6992
+ "address": {
6993
+ "type": "string",
6994
+ "example": "0x3a1f8b2c9d4e5f60718293a4b5c6d7e8f9012345"
6995
+ },
6996
+ "network_id": {
6997
+ "type": "string",
6998
+ "example": "60"
6999
+ },
7000
+ "eip155_id": {
7001
+ "type": "string",
7002
+ "example": "1"
7003
+ },
7004
+ "network_name": {
7005
+ "type": "string",
7006
+ "example": "Ethereum"
7007
+ },
7008
+ "asset_symbol": {
7009
+ "type": "string",
7010
+ "example": "USDC"
7011
+ },
7012
+ "asset_address": {
7013
+ "type": "string",
7014
+ "example": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
7015
+ },
7016
+ "asset_decimals": {
7017
+ "type": "integer",
7018
+ "example": 6
7019
+ }
7020
+ }
7021
+ }
7022
+ }
7023
+ }
7024
+ },
7025
+ "created_at": {
7026
+ "type": "string",
7027
+ "format": "date-time",
7028
+ "example": "2026-05-20T14:03:12Z"
7029
+ },
7030
+ "updated_at": {
7031
+ "type": "string",
7032
+ "format": "date-time",
7033
+ "example": "2026-05-20T14:03:12Z"
7034
+ }
7035
+ }
7036
+ },
7037
+ "RoutingPolicyList": {
7038
+ "type": "object",
7039
+ "properties": {
7040
+ "data": {
7041
+ "type": "array",
7042
+ "items": {
7043
+ "type": "object",
7044
+ "description": "A tenant-scoped, ordered routing-policy. Rules are evaluated first-match-wins; an empty rule set falls through to the UDA's default destination.\n",
7045
+ "properties": {
7046
+ "id": {
7047
+ "type": "string",
7048
+ "example": "rpol_2f8c1a9d4e5f6071"
7049
+ },
7050
+ "name": {
7051
+ "type": "string",
7052
+ "example": "vip_tier"
7053
+ },
7054
+ "is_default": {
7055
+ "type": "boolean",
7056
+ "description": "Whether this is the tenant's default policy (one per tenant).",
7057
+ "example": false
7058
+ },
7059
+ "rules": {
7060
+ "type": "array",
7061
+ "description": "Ordered, first-match-wins routing rules (dual form).",
7062
+ "items": {
7063
+ "type": "object",
7064
+ "description": "An echoed routing rule in dual form (symbol plus resolved contract address).",
7065
+ "properties": {
7066
+ "match": {
7067
+ "type": "object",
7068
+ "properties": {
7069
+ "source_network_id": {
7070
+ "type": "string",
7071
+ "example": "60"
7072
+ },
7073
+ "source_asset_symbol": {
7074
+ "type": "string",
7075
+ "example": "USDT"
7076
+ },
7077
+ "source_token_address": {
7078
+ "type": "string",
7079
+ "example": "0xdAC17F958D2ee523a2206206994597C13D831ec7"
7080
+ }
7081
+ }
7082
+ },
7083
+ "destination": {
7084
+ "type": "object",
7085
+ "properties": {
7086
+ "address": {
7087
+ "type": "string",
7088
+ "example": "0x3a1f8b2c9d4e5f60718293a4b5c6d7e8f9012345"
7089
+ },
7090
+ "network_id": {
7091
+ "type": "string",
7092
+ "example": "60"
7093
+ },
7094
+ "eip155_id": {
7095
+ "type": "string",
7096
+ "example": "1"
7097
+ },
7098
+ "network_name": {
7099
+ "type": "string",
7100
+ "example": "Ethereum"
7101
+ },
7102
+ "asset_symbol": {
7103
+ "type": "string",
7104
+ "example": "USDC"
7105
+ },
7106
+ "asset_address": {
7107
+ "type": "string",
7108
+ "example": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
7109
+ },
7110
+ "asset_decimals": {
7111
+ "type": "integer",
7112
+ "example": 6
7113
+ }
7114
+ }
7115
+ }
7116
+ }
7117
+ }
7118
+ },
7119
+ "created_at": {
7120
+ "type": "string",
7121
+ "format": "date-time",
7122
+ "example": "2026-05-20T14:03:12Z"
7123
+ },
7124
+ "updated_at": {
7125
+ "type": "string",
7126
+ "format": "date-time",
7127
+ "example": "2026-05-20T14:03:12Z"
7128
+ }
7129
+ }
7130
+ }
7131
+ },
7132
+ "pagination": {
7133
+ "type": "object",
7134
+ "properties": {
7135
+ "count": {
7136
+ "type": "integer",
7137
+ "description": "Number of items in this page.",
7138
+ "example": 20
7139
+ },
7140
+ "limit": {
7141
+ "type": "integer",
7142
+ "example": 50
7143
+ },
7144
+ "offset": {
7145
+ "type": "integer",
7146
+ "example": 0
7147
+ }
7148
+ }
6409
7149
  }
6410
7150
  }
6411
7151
  },
@@ -6581,6 +7321,11 @@
6581
7321
  }
6582
7322
  }
6583
7323
  }
7324
+ },
7325
+ "routing_policy_id": {
7326
+ "type": "string",
7327
+ "description": "The routing policy attached to this UDA, when set. Omitted for legacy UDAs that inherit the tenant default policy.\n",
7328
+ "example": "rpol_2f8c1a9d4e5f6071"
6584
7329
  }
6585
7330
  }
6586
7331
  }