primcli 1.11.0 → 1.13.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.
Files changed (3) hide show
  1. package/README.md +11 -3
  2. package/dist/oclif/index.js +1494 -139
  3. package/package.json +4 -1
@@ -38,6 +38,7 @@ var sdk_gen_exports = /* @__PURE__ */ __exportAll({
38
38
  createFunctionSecret: () => createFunctionSecret,
39
39
  createOrgSecret: () => createOrgSecret,
40
40
  createRegistry: () => createRegistry,
41
+ createRoute: () => createRoute,
41
42
  decideRegistryRequest: () => decideRegistryRequest,
42
43
  defineAgent: () => defineAgent,
43
44
  deleteDomain: () => deleteDomain,
@@ -47,6 +48,7 @@ var sdk_gen_exports = /* @__PURE__ */ __exportAll({
47
48
  deleteFunction: () => deleteFunction,
48
49
  deleteFunctionSecret: () => deleteFunctionSecret,
49
50
  deleteOrgSecret: () => deleteOrgSecret,
51
+ deleteRoute: () => deleteRoute,
50
52
  discardEmailContent: () => discardEmailContent,
51
53
  downloadAttachments: () => downloadAttachments,
52
54
  downloadDomainZoneFile: () => downloadDomainZoneFile,
@@ -82,11 +84,13 @@ var sdk_gen_exports = /* @__PURE__ */ __exportAll({
82
84
  listRegistries: () => listRegistries,
83
85
  listRegistryAgents: () => listRegistryAgents,
84
86
  listRegistryRequests: () => listRegistryRequests,
87
+ listRoutes: () => listRoutes,
85
88
  listSentEmails: () => listSentEmails,
86
89
  payChallenge: () => payChallenge,
87
90
  pollCliLogin: () => pollCliLogin,
88
91
  publishAgent: () => publishAgent,
89
92
  registerPayoutAddress: () => registerPayoutAddress,
93
+ reorderRoutes: () => reorderRoutes,
90
94
  replayDelivery: () => replayDelivery,
91
95
  replayEmailWebhooks: () => replayEmailWebhooks,
92
96
  replyToEmail: () => replyToEmail,
@@ -100,6 +104,7 @@ var sdk_gen_exports = /* @__PURE__ */ __exportAll({
100
104
  setFunctionRoute: () => setFunctionRoute,
101
105
  setFunctionSecret: () => setFunctionSecret,
102
106
  setOrgSecret: () => setOrgSecret,
107
+ simulateRoute: () => simulateRoute,
103
108
  startAgentClaim: () => startAgentClaim,
104
109
  startAgentSignup: () => startAgentSignup,
105
110
  startCliLogin: () => startCliLogin,
@@ -114,6 +119,7 @@ var sdk_gen_exports = /* @__PURE__ */ __exportAll({
114
119
  updateFilter: () => updateFilter,
115
120
  updateFunction: () => updateFunction,
116
121
  updateRegistry: () => updateRegistry,
122
+ updateRoute: () => updateRoute,
117
123
  updateSpendPolicy: () => updateSpendPolicy,
118
124
  verifyAgentClaim: () => verifyAgentClaim,
119
125
  verifyAgentSignup: () => verifyAgentSignup,
@@ -981,6 +987,106 @@ const updateFilter = (options) => (options.client ?? client).patch({
981
987
  }
982
988
  });
983
989
  /**
990
+ * List recipient routes
991
+ *
992
+ * Returns the org's recipient routing rules in evaluation order. Each rule
993
+ * binds a recipient address pattern to one endpoint; inbound mail resolves
994
+ * to a single destination at delivery time.
995
+ *
996
+ */
997
+ const listRoutes = (options) => (options?.client ?? client).get({
998
+ security: [{
999
+ scheme: "bearer",
1000
+ type: "http"
1001
+ }],
1002
+ url: "/routes",
1003
+ ...options
1004
+ });
1005
+ /**
1006
+ * Create a recipient route
1007
+ *
1008
+ * Binds a recipient pattern to a destination. Provide exactly one of
1009
+ * `endpoint_id` (an existing endpoint) or `function_id`. With `function_id`,
1010
+ * a dedicated route-target endpoint is minted for that function in the same
1011
+ * transaction, enabling per-address function routing (e.g.
1012
+ * `alice@acme.com -> functionA`).
1013
+ *
1014
+ */
1015
+ const createRoute = (options) => (options.client ?? client).post({
1016
+ security: [{
1017
+ scheme: "bearer",
1018
+ type: "http"
1019
+ }],
1020
+ url: "/routes",
1021
+ ...options,
1022
+ headers: {
1023
+ ...options.body !== void 0 && { "Content-Type": "application/json" },
1024
+ ...options.headers
1025
+ }
1026
+ });
1027
+ /**
1028
+ * Reorder recipient routes
1029
+ *
1030
+ * Update the priority of one or more routes in a single call.
1031
+ */
1032
+ const reorderRoutes = (options) => (options.client ?? client).post({
1033
+ security: [{
1034
+ scheme: "bearer",
1035
+ type: "http"
1036
+ }],
1037
+ url: "/routes/reorder",
1038
+ ...options,
1039
+ headers: {
1040
+ ...options.body !== void 0 && { "Content-Type": "application/json" },
1041
+ ...options.headers
1042
+ }
1043
+ });
1044
+ /**
1045
+ * Simulate routing for a recipient
1046
+ *
1047
+ * Resolves where an inbound email to `recipient` would be delivered, with a
1048
+ * trace of every rule evaluated and why. Read-only; creates nothing.
1049
+ *
1050
+ */
1051
+ const simulateRoute = (options) => (options.client ?? client).post({
1052
+ security: [{
1053
+ scheme: "bearer",
1054
+ type: "http"
1055
+ }],
1056
+ url: "/routes/simulate",
1057
+ ...options,
1058
+ headers: {
1059
+ ...options.body !== void 0 && { "Content-Type": "application/json" },
1060
+ ...options.headers
1061
+ }
1062
+ });
1063
+ /**
1064
+ * Delete a recipient route
1065
+ */
1066
+ const deleteRoute = (options) => (options.client ?? client).delete({
1067
+ security: [{
1068
+ scheme: "bearer",
1069
+ type: "http"
1070
+ }],
1071
+ url: "/routes/{id}",
1072
+ ...options
1073
+ });
1074
+ /**
1075
+ * Update a recipient route
1076
+ */
1077
+ const updateRoute = (options) => (options.client ?? client).patch({
1078
+ security: [{
1079
+ scheme: "bearer",
1080
+ type: "http"
1081
+ }],
1082
+ url: "/routes/{id}",
1083
+ ...options,
1084
+ headers: {
1085
+ ...options.body !== void 0 && { "Content-Type": "application/json" },
1086
+ ...options.headers
1087
+ }
1088
+ });
1089
+ /**
984
1090
  * List webhook deliveries
985
1091
  *
986
1092
  * Returns a paginated list of webhook delivery attempts. Each delivery
@@ -2043,6 +2149,10 @@ const openapiDocument = {
2043
2149
  "name": "Filters",
2044
2150
  "description": "Manage whitelist and blocklist filter rules"
2045
2151
  },
2152
+ {
2153
+ "name": "Routes",
2154
+ "description": "Recipient routing: route inbound mail to a single destination per recipient\naddress. Rules bind an address pattern (exact or wildcard) to an endpoint;\n`function_id` routes an address to a function, minting its route-target\nendpoint.\n"
2155
+ },
2046
2156
  {
2047
2157
  "name": "Payments",
2048
2158
  "description": "Collect and pay stablecoin (USDC) payments with x402. Settlement is\nnon-custodial: funds move directly from payer to payee on-chain via an\nEIP-3009 authorization the payer signs with their own key, and Primitive\nnever holds funds. The payee registers a payout address and creates a\nchallenge; the payer signs and settles it under a configurable spend\npolicy (kill-switch, per-payment and per-day caps, payee allowlist).\n"
@@ -3457,6 +3567,129 @@ const openapiDocument = {
3457
3567
  }
3458
3568
  }
3459
3569
  },
3570
+ "/routes": {
3571
+ "get": {
3572
+ "operationId": "listRoutes",
3573
+ "summary": "List recipient routes",
3574
+ "description": "Returns the org's recipient routing rules in evaluation order. Each rule\nbinds a recipient address pattern to one endpoint; inbound mail resolves\nto a single destination at delivery time.\n",
3575
+ "tags": ["Routes"],
3576
+ "responses": {
3577
+ "200": {
3578
+ "description": "List of routes",
3579
+ "content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/SuccessEnvelope" }, {
3580
+ "type": "object",
3581
+ "properties": { "data": {
3582
+ "type": "array",
3583
+ "items": { "$ref": "#/components/schemas/RecipientRoute" }
3584
+ } }
3585
+ }] } } }
3586
+ },
3587
+ "401": { "$ref": "#/components/responses/Unauthorized" }
3588
+ }
3589
+ },
3590
+ "post": {
3591
+ "operationId": "createRoute",
3592
+ "summary": "Create a recipient route",
3593
+ "description": "Binds a recipient pattern to a destination. Provide exactly one of\n`endpoint_id` (an existing endpoint) or `function_id`. With `function_id`,\na dedicated route-target endpoint is minted for that function in the same\ntransaction, enabling per-address function routing (e.g.\n`alice@acme.com -> functionA`).\n",
3594
+ "tags": ["Routes"],
3595
+ "requestBody": {
3596
+ "required": true,
3597
+ "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateRouteInput" } } }
3598
+ },
3599
+ "responses": {
3600
+ "201": {
3601
+ "description": "Route created",
3602
+ "content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/SuccessEnvelope" }, {
3603
+ "type": "object",
3604
+ "properties": { "data": { "$ref": "#/components/schemas/RecipientRoute" } }
3605
+ }] } } }
3606
+ },
3607
+ "400": { "$ref": "#/components/responses/ValidationError" },
3608
+ "401": { "$ref": "#/components/responses/Unauthorized" },
3609
+ "409": { "$ref": "#/components/responses/Conflict" }
3610
+ }
3611
+ }
3612
+ },
3613
+ "/routes/reorder": { "post": {
3614
+ "operationId": "reorderRoutes",
3615
+ "summary": "Reorder recipient routes",
3616
+ "description": "Update the priority of one or more routes in a single call.",
3617
+ "tags": ["Routes"],
3618
+ "requestBody": {
3619
+ "required": true,
3620
+ "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReorderRoutesInput" } } }
3621
+ },
3622
+ "responses": {
3623
+ "200": {
3624
+ "description": "Updated route list",
3625
+ "content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/SuccessEnvelope" }, {
3626
+ "type": "object",
3627
+ "properties": { "data": {
3628
+ "type": "array",
3629
+ "items": { "$ref": "#/components/schemas/RecipientRoute" }
3630
+ } }
3631
+ }] } } }
3632
+ },
3633
+ "400": { "$ref": "#/components/responses/ValidationError" },
3634
+ "401": { "$ref": "#/components/responses/Unauthorized" }
3635
+ }
3636
+ } },
3637
+ "/routes/simulate": { "post": {
3638
+ "operationId": "simulateRoute",
3639
+ "summary": "Simulate routing for a recipient",
3640
+ "description": "Resolves where an inbound email to `recipient` would be delivered, with a\ntrace of every rule evaluated and why. Read-only; creates nothing.\n",
3641
+ "tags": ["Routes"],
3642
+ "requestBody": {
3643
+ "required": true,
3644
+ "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SimulateRouteInput" } } }
3645
+ },
3646
+ "responses": {
3647
+ "200": {
3648
+ "description": "Routing decision",
3649
+ "content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/SuccessEnvelope" }, {
3650
+ "type": "object",
3651
+ "properties": { "data": { "$ref": "#/components/schemas/SimulateRouteResult" } }
3652
+ }] } } }
3653
+ },
3654
+ "400": { "$ref": "#/components/responses/ValidationError" },
3655
+ "401": { "$ref": "#/components/responses/Unauthorized" }
3656
+ }
3657
+ } },
3658
+ "/routes/{id}": {
3659
+ "parameters": [{ "$ref": "#/components/parameters/ResourceId" }],
3660
+ "patch": {
3661
+ "operationId": "updateRoute",
3662
+ "summary": "Update a recipient route",
3663
+ "tags": ["Routes"],
3664
+ "requestBody": {
3665
+ "required": true,
3666
+ "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateRouteInput" } } }
3667
+ },
3668
+ "responses": {
3669
+ "200": {
3670
+ "description": "Updated route",
3671
+ "content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/SuccessEnvelope" }, {
3672
+ "type": "object",
3673
+ "properties": { "data": { "$ref": "#/components/schemas/RecipientRoute" } }
3674
+ }] } } }
3675
+ },
3676
+ "400": { "$ref": "#/components/responses/ValidationError" },
3677
+ "401": { "$ref": "#/components/responses/Unauthorized" },
3678
+ "404": { "$ref": "#/components/responses/NotFound" },
3679
+ "409": { "$ref": "#/components/responses/Conflict" }
3680
+ }
3681
+ },
3682
+ "delete": {
3683
+ "operationId": "deleteRoute",
3684
+ "summary": "Delete a recipient route",
3685
+ "tags": ["Routes"],
3686
+ "responses": {
3687
+ "200": { "$ref": "#/components/responses/Deleted" },
3688
+ "401": { "$ref": "#/components/responses/Unauthorized" },
3689
+ "404": { "$ref": "#/components/responses/NotFound" }
3690
+ }
3691
+ }
3692
+ },
3460
3693
  "/webhooks/deliveries": { "get": {
3461
3694
  "operationId": "listDeliveries",
3462
3695
  "summary": "List webhook deliveries",
@@ -8712,6 +8945,20 @@ const openapiDocument = {
8712
8945
  "deactivated_at": {
8713
8946
  "type": ["string", "null"],
8714
8947
  "format": "date-time"
8948
+ },
8949
+ "kind": {
8950
+ "type": "string",
8951
+ "enum": ["http", "function"],
8952
+ "description": "http: deliver to the webhook URL. function: invoke a Primitive Function."
8953
+ },
8954
+ "function_id": {
8955
+ "type": ["string", "null"],
8956
+ "format": "uuid",
8957
+ "description": "The Function this endpoint invokes, when kind is function."
8958
+ },
8959
+ "is_route_target": {
8960
+ "type": "boolean",
8961
+ "description": "When true, this endpoint is reachable only via an explicit recipient\nroute, never as a domain's default destination, and is exempt from\nthe one-endpoint-per-domain rule (so many can share a domain).\n"
8715
8962
  }
8716
8963
  },
8717
8964
  "required": [
@@ -8727,14 +8974,20 @@ const openapiDocument = {
8727
8974
  "consecutive_fails"
8728
8975
  ]
8729
8976
  },
8730
- "CreateEndpointInput": {
8977
+ "CreateHttpEndpointInput": {
8731
8978
  "type": "object",
8732
8979
  "additionalProperties": false,
8733
8980
  "properties": {
8981
+ "kind": {
8982
+ "type": "string",
8983
+ "enum": ["http"],
8984
+ "default": "http",
8985
+ "description": "Deliver to a webhook URL."
8986
+ },
8734
8987
  "url": {
8735
8988
  "type": "string",
8736
8989
  "minLength": 1,
8737
- "description": "The webhook URL to deliver events to"
8990
+ "description": "The webhook URL to deliver events to."
8738
8991
  },
8739
8992
  "enabled": {
8740
8993
  "type": "boolean",
@@ -8749,10 +9002,61 @@ const openapiDocument = {
8749
9002
  "rules": {
8750
9003
  "type": "object",
8751
9004
  "description": "Endpoint-specific filtering rules"
9005
+ },
9006
+ "is_route_target": {
9007
+ "type": "boolean",
9008
+ "default": false,
9009
+ "description": "Create this endpoint as a route-target: reachable only via an\nexplicit recipient route, never a domain's default destination, and\nexempt from the one-endpoint-per-domain rule.\n"
8752
9010
  }
8753
9011
  },
8754
9012
  "required": ["url"]
8755
9013
  },
9014
+ "CreateFunctionEndpointInput": {
9015
+ "type": "object",
9016
+ "additionalProperties": false,
9017
+ "properties": {
9018
+ "kind": {
9019
+ "type": "string",
9020
+ "enum": ["function"],
9021
+ "description": "Invoke a Primitive Function."
9022
+ },
9023
+ "function_id": {
9024
+ "type": "string",
9025
+ "format": "uuid",
9026
+ "description": "The Function to invoke."
9027
+ },
9028
+ "enabled": {
9029
+ "type": "boolean",
9030
+ "default": true,
9031
+ "description": "Whether the endpoint is active"
9032
+ },
9033
+ "domain_id": {
9034
+ "type": ["string", "null"],
9035
+ "format": "uuid",
9036
+ "description": "Restrict to emails from a specific domain"
9037
+ },
9038
+ "rules": {
9039
+ "type": "object",
9040
+ "description": "Endpoint-specific filtering rules"
9041
+ },
9042
+ "is_route_target": {
9043
+ "type": "boolean",
9044
+ "default": false,
9045
+ "description": "Create this endpoint as a route-target: reachable only via an\nexplicit recipient route, never a domain's default destination, and\nexempt from the one-endpoint-per-domain rule.\n"
9046
+ }
9047
+ },
9048
+ "required": ["kind", "function_id"]
9049
+ },
9050
+ "CreateEndpointInput": {
9051
+ "oneOf": [{ "$ref": "#/components/schemas/CreateHttpEndpointInput" }, { "$ref": "#/components/schemas/CreateFunctionEndpointInput" }],
9052
+ "discriminator": {
9053
+ "propertyName": "kind",
9054
+ "mapping": {
9055
+ "http": "#/components/schemas/CreateHttpEndpointInput",
9056
+ "function": "#/components/schemas/CreateFunctionEndpointInput"
9057
+ }
9058
+ }
9059
+ },
8756
9060
  "UpdateEndpointInput": {
8757
9061
  "type": "object",
8758
9062
  "additionalProperties": false,
@@ -8856,14 +9160,11 @@ const openapiDocument = {
8856
9160
  "properties": { "enabled": { "type": "boolean" } },
8857
9161
  "required": ["enabled"]
8858
9162
  },
8859
- "DeliverySummary": {
9163
+ "RecipientRoute": {
8860
9164
  "type": "object",
9165
+ "description": "A recipient routing rule binding an address pattern to one endpoint.",
8861
9166
  "properties": {
8862
9167
  "id": {
8863
- "type": "string",
8864
- "description": "Delivery ID (numeric string)"
8865
- },
8866
- "email_id": {
8867
9168
  "type": "string",
8868
9169
  "format": "uuid"
8869
9170
  },
@@ -8871,47 +9172,309 @@ const openapiDocument = {
8871
9172
  "type": "string",
8872
9173
  "format": "uuid"
8873
9174
  },
8874
- "endpoint_id": {
8875
- "type": "string",
8876
- "format": "uuid"
9175
+ "domain_id": {
9176
+ "type": ["string", "null"],
9177
+ "format": "uuid",
9178
+ "description": "Domain the route is scoped to; null = org-wide."
8877
9179
  },
8878
- "endpoint_url": { "type": "string" },
8879
- "status": {
9180
+ "match_type": {
8880
9181
  "type": "string",
8881
9182
  "enum": [
8882
- "pending",
8883
- "delivered",
8884
- "header_confirmed",
8885
- "failed"
9183
+ "exact",
9184
+ "wildcard",
9185
+ "regex"
8886
9186
  ]
8887
9187
  },
8888
- "attempt_count": { "type": "integer" },
8889
- "duration_ms": { "type": ["integer", "null"] },
8890
- "last_error": { "type": ["string", "null"] },
8891
- "created_at": {
9188
+ "pattern": {
8892
9189
  "type": "string",
8893
- "format": "date-time"
9190
+ "description": "The recipient address pattern (an exact address or a wildcard)."
8894
9191
  },
8895
- "updated_at": {
9192
+ "pattern_norm": {
9193
+ "type": ["string", "null"],
9194
+ "description": "Normalized pattern used for matching."
9195
+ },
9196
+ "endpoint_id": {
9197
+ "type": "string",
9198
+ "format": "uuid",
9199
+ "description": "The endpoint inbound mail matching this rule is delivered to."
9200
+ },
9201
+ "priority": {
9202
+ "type": "integer",
9203
+ "description": "Evaluation order within a scope; lower is checked first."
9204
+ },
9205
+ "enabled": { "type": "boolean" },
9206
+ "match_count": {
8896
9207
  "type": "string",
9208
+ "description": "How many emails have matched this rule (a bigint, returned as a string)."
9209
+ },
9210
+ "last_matched_at": {
9211
+ "type": ["string", "null"],
8897
9212
  "format": "date-time"
8898
9213
  },
8899
- "email": {
8900
- "type": ["object", "null"],
8901
- "properties": {
8902
- "sender": { "type": "string" },
8903
- "recipient": { "type": "string" },
8904
- "subject": { "type": ["string", "null"] }
8905
- },
8906
- "required": ["sender", "recipient"]
9214
+ "created_at": {
9215
+ "type": "string",
9216
+ "format": "date-time"
8907
9217
  }
8908
9218
  },
8909
- "required": [
8910
- "id",
8911
- "email_id",
8912
- "org_id",
8913
- "endpoint_id",
8914
- "endpoint_url",
9219
+ "required": ["id"]
9220
+ },
9221
+ "CreateRouteInput": {
9222
+ "type": "object",
9223
+ "additionalProperties": false,
9224
+ "description": "Provide exactly one of `endpoint_id` or `function_id`. With `function_id`,\na route-target endpoint is minted for that function and the route is bound\nto it in one transaction.\n",
9225
+ "properties": {
9226
+ "match_type": {
9227
+ "type": "string",
9228
+ "enum": [
9229
+ "exact",
9230
+ "wildcard",
9231
+ "regex"
9232
+ ]
9233
+ },
9234
+ "pattern": {
9235
+ "type": "string",
9236
+ "minLength": 1,
9237
+ "maxLength": 512
9238
+ },
9239
+ "endpoint_id": {
9240
+ "type": "string",
9241
+ "format": "uuid",
9242
+ "description": "An existing endpoint to route to. Mutually exclusive with function_id."
9243
+ },
9244
+ "function_id": {
9245
+ "type": "string",
9246
+ "format": "uuid",
9247
+ "description": "Route to this function, minting its route-target endpoint if needed. Mutually exclusive with endpoint_id."
9248
+ },
9249
+ "domain_id": {
9250
+ "type": ["string", "null"],
9251
+ "format": "uuid",
9252
+ "description": "Scope the route to a domain; defaults to the pattern's domain."
9253
+ },
9254
+ "priority": {
9255
+ "type": "integer",
9256
+ "minimum": 0,
9257
+ "maximum": 1e6
9258
+ },
9259
+ "enabled": { "type": "boolean" }
9260
+ },
9261
+ "required": ["match_type", "pattern"]
9262
+ },
9263
+ "UpdateRouteInput": {
9264
+ "type": "object",
9265
+ "additionalProperties": false,
9266
+ "properties": {
9267
+ "match_type": {
9268
+ "type": "string",
9269
+ "enum": [
9270
+ "exact",
9271
+ "wildcard",
9272
+ "regex"
9273
+ ]
9274
+ },
9275
+ "pattern": {
9276
+ "type": "string",
9277
+ "minLength": 1,
9278
+ "maxLength": 512
9279
+ },
9280
+ "endpoint_id": {
9281
+ "type": "string",
9282
+ "format": "uuid"
9283
+ },
9284
+ "domain_id": {
9285
+ "type": ["string", "null"],
9286
+ "format": "uuid"
9287
+ },
9288
+ "priority": {
9289
+ "type": "integer",
9290
+ "minimum": 0,
9291
+ "maximum": 1e6
9292
+ },
9293
+ "enabled": { "type": "boolean" }
9294
+ }
9295
+ },
9296
+ "ReorderRoutesInput": {
9297
+ "type": "object",
9298
+ "additionalProperties": false,
9299
+ "properties": { "updates": {
9300
+ "type": "array",
9301
+ "minItems": 1,
9302
+ "maxItems": 1e3,
9303
+ "items": {
9304
+ "type": "object",
9305
+ "additionalProperties": false,
9306
+ "properties": {
9307
+ "id": {
9308
+ "type": "string",
9309
+ "format": "uuid"
9310
+ },
9311
+ "priority": {
9312
+ "type": "integer",
9313
+ "minimum": 0,
9314
+ "maximum": 1e6
9315
+ }
9316
+ },
9317
+ "required": ["id", "priority"]
9318
+ }
9319
+ } },
9320
+ "required": ["updates"]
9321
+ },
9322
+ "SimulateRouteInput": {
9323
+ "type": "object",
9324
+ "additionalProperties": false,
9325
+ "properties": {
9326
+ "recipient": {
9327
+ "type": "string",
9328
+ "minLength": 1,
9329
+ "maxLength": 320
9330
+ },
9331
+ "event_type": {
9332
+ "type": "string",
9333
+ "minLength": 1,
9334
+ "maxLength": 100,
9335
+ "description": "Event type to model; defaults to email.received."
9336
+ }
9337
+ },
9338
+ "required": ["recipient"]
9339
+ },
9340
+ "RouteEvaluatedEntry": {
9341
+ "type": "object",
9342
+ "properties": {
9343
+ "route_id": { "type": "string" },
9344
+ "tier": {
9345
+ "type": "string",
9346
+ "enum": [
9347
+ "exact",
9348
+ "wildcard",
9349
+ "regex"
9350
+ ]
9351
+ },
9352
+ "pattern": { "type": "string" },
9353
+ "result": {
9354
+ "type": "string",
9355
+ "enum": [
9356
+ "hit",
9357
+ "miss",
9358
+ "skipped",
9359
+ "error"
9360
+ ]
9361
+ },
9362
+ "reason": { "type": "string" }
9363
+ },
9364
+ "required": [
9365
+ "route_id",
9366
+ "tier",
9367
+ "pattern",
9368
+ "result"
9369
+ ]
9370
+ },
9371
+ "SimulateRouteResult": {
9372
+ "type": "object",
9373
+ "description": "Where an inbound email to the recipient would be delivered, and why.",
9374
+ "properties": {
9375
+ "outcome": {
9376
+ "type": "string",
9377
+ "enum": [
9378
+ "matched",
9379
+ "defaulted",
9380
+ "none"
9381
+ ]
9382
+ },
9383
+ "recipient": { "type": "string" },
9384
+ "endpoint_id": { "type": ["string", "null"] },
9385
+ "matched_route_id": { "type": ["string", "null"] },
9386
+ "matched_tier": {
9387
+ "type": ["string", "null"],
9388
+ "enum": [
9389
+ "exact",
9390
+ "wildcard",
9391
+ "regex",
9392
+ null
9393
+ ]
9394
+ },
9395
+ "matched_pattern": { "type": ["string", "null"] },
9396
+ "default_scope": {
9397
+ "type": ["string", "null"],
9398
+ "enum": [
9399
+ "domain",
9400
+ "org",
9401
+ null
9402
+ ]
9403
+ },
9404
+ "evaluated": {
9405
+ "type": "array",
9406
+ "items": { "$ref": "#/components/schemas/RouteEvaluatedEntry" }
9407
+ },
9408
+ "truncated": { "type": "boolean" }
9409
+ },
9410
+ "required": [
9411
+ "outcome",
9412
+ "recipient",
9413
+ "endpoint_id",
9414
+ "matched_route_id",
9415
+ "matched_tier",
9416
+ "matched_pattern",
9417
+ "default_scope",
9418
+ "evaluated",
9419
+ "truncated"
9420
+ ]
9421
+ },
9422
+ "DeliverySummary": {
9423
+ "type": "object",
9424
+ "properties": {
9425
+ "id": {
9426
+ "type": "string",
9427
+ "description": "Delivery ID (numeric string)"
9428
+ },
9429
+ "email_id": {
9430
+ "type": "string",
9431
+ "format": "uuid"
9432
+ },
9433
+ "org_id": {
9434
+ "type": "string",
9435
+ "format": "uuid"
9436
+ },
9437
+ "endpoint_id": {
9438
+ "type": "string",
9439
+ "format": "uuid"
9440
+ },
9441
+ "endpoint_url": { "type": "string" },
9442
+ "status": {
9443
+ "type": "string",
9444
+ "enum": [
9445
+ "pending",
9446
+ "delivered",
9447
+ "header_confirmed",
9448
+ "failed"
9449
+ ]
9450
+ },
9451
+ "attempt_count": { "type": "integer" },
9452
+ "duration_ms": { "type": ["integer", "null"] },
9453
+ "last_error": { "type": ["string", "null"] },
9454
+ "created_at": {
9455
+ "type": "string",
9456
+ "format": "date-time"
9457
+ },
9458
+ "updated_at": {
9459
+ "type": "string",
9460
+ "format": "date-time"
9461
+ },
9462
+ "email": {
9463
+ "type": ["object", "null"],
9464
+ "properties": {
9465
+ "sender": { "type": "string" },
9466
+ "recipient": { "type": "string" },
9467
+ "subject": { "type": ["string", "null"] }
9468
+ },
9469
+ "required": ["sender", "recipient"]
9470
+ }
9471
+ },
9472
+ "required": [
9473
+ "id",
9474
+ "email_id",
9475
+ "org_id",
9476
+ "endpoint_id",
9477
+ "endpoint_url",
8915
9478
  "status",
8916
9479
  "attempt_count",
8917
9480
  "created_at",
@@ -12806,30 +13369,85 @@ const operationManifest = [
12806
13369
  "pathParams": [],
12807
13370
  "queryParams": [],
12808
13371
  "requestSchema": {
12809
- "type": "object",
12810
- "additionalProperties": false,
12811
- "properties": {
12812
- "url": {
12813
- "type": "string",
12814
- "minLength": 1,
12815
- "description": "The webhook URL to deliver events to"
12816
- },
12817
- "enabled": {
12818
- "type": "boolean",
12819
- "default": true,
12820
- "description": "Whether the endpoint is active"
13372
+ "oneOf": [{
13373
+ "type": "object",
13374
+ "additionalProperties": false,
13375
+ "properties": {
13376
+ "kind": {
13377
+ "type": "string",
13378
+ "enum": ["http"],
13379
+ "default": "http",
13380
+ "description": "Deliver to a webhook URL."
13381
+ },
13382
+ "url": {
13383
+ "type": "string",
13384
+ "minLength": 1,
13385
+ "description": "The webhook URL to deliver events to."
13386
+ },
13387
+ "enabled": {
13388
+ "type": "boolean",
13389
+ "default": true,
13390
+ "description": "Whether the endpoint is active"
13391
+ },
13392
+ "domain_id": {
13393
+ "type": ["string", "null"],
13394
+ "format": "uuid",
13395
+ "description": "Restrict to emails from a specific domain"
13396
+ },
13397
+ "rules": {
13398
+ "type": "object",
13399
+ "description": "Endpoint-specific filtering rules"
13400
+ },
13401
+ "is_route_target": {
13402
+ "type": "boolean",
13403
+ "default": false,
13404
+ "description": "Create this endpoint as a route-target: reachable only via an\nexplicit recipient route, never a domain's default destination, and\nexempt from the one-endpoint-per-domain rule.\n"
13405
+ }
12821
13406
  },
12822
- "domain_id": {
12823
- "type": ["string", "null"],
12824
- "format": "uuid",
12825
- "description": "Restrict to emails from a specific domain"
13407
+ "required": ["url"]
13408
+ }, {
13409
+ "type": "object",
13410
+ "additionalProperties": false,
13411
+ "properties": {
13412
+ "kind": {
13413
+ "type": "string",
13414
+ "enum": ["function"],
13415
+ "description": "Invoke a Primitive Function."
13416
+ },
13417
+ "function_id": {
13418
+ "type": "string",
13419
+ "format": "uuid",
13420
+ "description": "The Function to invoke."
13421
+ },
13422
+ "enabled": {
13423
+ "type": "boolean",
13424
+ "default": true,
13425
+ "description": "Whether the endpoint is active"
13426
+ },
13427
+ "domain_id": {
13428
+ "type": ["string", "null"],
13429
+ "format": "uuid",
13430
+ "description": "Restrict to emails from a specific domain"
13431
+ },
13432
+ "rules": {
13433
+ "type": "object",
13434
+ "description": "Endpoint-specific filtering rules"
13435
+ },
13436
+ "is_route_target": {
13437
+ "type": "boolean",
13438
+ "default": false,
13439
+ "description": "Create this endpoint as a route-target: reachable only via an\nexplicit recipient route, never a domain's default destination, and\nexempt from the one-endpoint-per-domain rule.\n"
13440
+ }
12826
13441
  },
12827
- "rules": {
12828
- "type": "object",
12829
- "description": "Endpoint-specific filtering rules"
13442
+ "required": ["kind", "function_id"]
13443
+ }],
13444
+ "discriminator": {
13445
+ "propertyName": "kind",
13446
+ "mapping": {
13447
+ "http": "#/components/schemas/CreateHttpEndpointInput",
13448
+ "function": "#/components/schemas/CreateFunctionEndpointInput"
12830
13449
  }
12831
- },
12832
- "required": ["url"]
13450
+ }
12833
13451
  },
12834
13452
  "responseSchema": {
12835
13453
  "type": "object",
@@ -12892,6 +13510,20 @@ const operationManifest = [
12892
13510
  "deactivated_at": {
12893
13511
  "type": ["string", "null"],
12894
13512
  "format": "date-time"
13513
+ },
13514
+ "kind": {
13515
+ "type": "string",
13516
+ "enum": ["http", "function"],
13517
+ "description": "http: deliver to the webhook URL. function: invoke a Primitive Function."
13518
+ },
13519
+ "function_id": {
13520
+ "type": ["string", "null"],
13521
+ "format": "uuid",
13522
+ "description": "The Function this endpoint invokes, when kind is function."
13523
+ },
13524
+ "is_route_target": {
13525
+ "type": "boolean",
13526
+ "description": "When true, this endpoint is reachable only via an explicit recipient\nroute, never as a domain's default destination, and is exempt from\nthe one-endpoint-per-domain rule (so many can share a domain).\n"
12895
13527
  }
12896
13528
  },
12897
13529
  "required": [
@@ -13011,6 +13643,20 @@ const operationManifest = [
13011
13643
  "deactivated_at": {
13012
13644
  "type": ["string", "null"],
13013
13645
  "format": "date-time"
13646
+ },
13647
+ "kind": {
13648
+ "type": "string",
13649
+ "enum": ["http", "function"],
13650
+ "description": "http: deliver to the webhook URL. function: invoke a Primitive Function."
13651
+ },
13652
+ "function_id": {
13653
+ "type": ["string", "null"],
13654
+ "format": "uuid",
13655
+ "description": "The Function this endpoint invokes, when kind is function."
13656
+ },
13657
+ "is_route_target": {
13658
+ "type": "boolean",
13659
+ "description": "When true, this endpoint is reachable only via an explicit recipient\nroute, never as a domain's default destination, and is exempt from\nthe one-endpoint-per-domain rule (so many can share a domain).\n"
13014
13660
  }
13015
13661
  },
13016
13662
  "required": [
@@ -13169,6 +13815,20 @@ const operationManifest = [
13169
13815
  "deactivated_at": {
13170
13816
  "type": ["string", "null"],
13171
13817
  "format": "date-time"
13818
+ },
13819
+ "kind": {
13820
+ "type": "string",
13821
+ "enum": ["http", "function"],
13822
+ "description": "http: deliver to the webhook URL. function: invoke a Primitive Function."
13823
+ },
13824
+ "function_id": {
13825
+ "type": ["string", "null"],
13826
+ "format": "uuid",
13827
+ "description": "The Function this endpoint invokes, when kind is function."
13828
+ },
13829
+ "is_route_target": {
13830
+ "type": "boolean",
13831
+ "description": "When true, this endpoint is reachable only via an explicit recipient\nroute, never as a domain's default destination, and is exempt from\nthe one-endpoint-per-domain rule (so many can share a domain).\n"
13172
13832
  }
13173
13833
  },
13174
13834
  "required": [
@@ -16764,109 +17424,658 @@ const operationManifest = [
16764
17424
  "type": "array",
16765
17425
  "items": { "type": "string" }
16766
17426
  },
16767
- "handle": {
17427
+ "handle": {
17428
+ "type": ["string", "null"],
17429
+ "description": "The registry-scoped name. Null on the global by-address read."
17430
+ }
17431
+ },
17432
+ "required": [
17433
+ "address",
17434
+ "display_name",
17435
+ "title",
17436
+ "description",
17437
+ "tags",
17438
+ "handle"
17439
+ ]
17440
+ },
17441
+ "sdkName": "resolveRegistryHandle",
17442
+ "summary": "Resolve a registry handle to its agent",
17443
+ "tag": "Registries",
17444
+ "tagCommand": "registries"
17445
+ },
17446
+ {
17447
+ "binaryResponse": false,
17448
+ "bodyRequired": false,
17449
+ "command": "unpublish-agent",
17450
+ "description": null,
17451
+ "hasJsonBody": false,
17452
+ "method": "DELETE",
17453
+ "operationId": "unpublishAgent",
17454
+ "path": "/registries/{slug}/agents/{handle}",
17455
+ "pathParams": [{
17456
+ "description": "The registry slug.",
17457
+ "enum": null,
17458
+ "name": "slug",
17459
+ "required": true,
17460
+ "type": "string"
17461
+ }, {
17462
+ "description": "The registry-scoped handle the agent is published under.",
17463
+ "enum": null,
17464
+ "name": "handle",
17465
+ "required": true,
17466
+ "type": "string"
17467
+ }],
17468
+ "queryParams": [],
17469
+ "requestSchema": null,
17470
+ "responseSchema": null,
17471
+ "sdkName": "unpublishAgent",
17472
+ "summary": "Unpublish an agent from a registry",
17473
+ "tag": "Registries",
17474
+ "tagCommand": "registries"
17475
+ },
17476
+ {
17477
+ "binaryResponse": false,
17478
+ "bodyRequired": true,
17479
+ "command": "update-registry",
17480
+ "description": null,
17481
+ "hasJsonBody": true,
17482
+ "method": "PATCH",
17483
+ "operationId": "updateRegistry",
17484
+ "path": "/registries/{slug}",
17485
+ "pathParams": [{
17486
+ "description": "The registry slug",
17487
+ "enum": null,
17488
+ "name": "slug",
17489
+ "required": true,
17490
+ "type": "string"
17491
+ }],
17492
+ "queryParams": [],
17493
+ "requestSchema": {
17494
+ "type": "object",
17495
+ "minProperties": 1,
17496
+ "properties": {
17497
+ "name": {
17498
+ "type": "string",
17499
+ "minLength": 1,
17500
+ "maxLength": 120
17501
+ },
17502
+ "description": {
17503
+ "type": ["string", "null"],
17504
+ "maxLength": 2e3
17505
+ },
17506
+ "is_public": { "type": "boolean" },
17507
+ "publish_policy": {
17508
+ "type": "string",
17509
+ "enum": [
17510
+ "owner_only",
17511
+ "request",
17512
+ "open"
17513
+ ],
17514
+ "description": "Who may publish into a registry. owner_only: only the registry owner.\nrequest: anyone may request and the owner approves. open: anyone may\npublish and it lists immediately (no approval step).\n"
17515
+ }
17516
+ }
17517
+ },
17518
+ "responseSchema": {
17519
+ "type": "object",
17520
+ "properties": { "id": {
17521
+ "type": "string",
17522
+ "format": "uuid"
17523
+ } },
17524
+ "required": ["id"]
17525
+ },
17526
+ "sdkName": "updateRegistry",
17527
+ "summary": "Update a registry you own",
17528
+ "tag": "Registries",
17529
+ "tagCommand": "registries"
17530
+ },
17531
+ {
17532
+ "binaryResponse": false,
17533
+ "bodyRequired": true,
17534
+ "command": "create-route",
17535
+ "description": "Binds a recipient pattern to a destination. Provide exactly one of\n`endpoint_id` (an existing endpoint) or `function_id`. With `function_id`,\na dedicated route-target endpoint is minted for that function in the same\ntransaction, enabling per-address function routing (e.g.\n`alice@acme.com -> functionA`).\n",
17536
+ "hasJsonBody": true,
17537
+ "method": "POST",
17538
+ "operationId": "createRoute",
17539
+ "path": "/routes",
17540
+ "pathParams": [],
17541
+ "queryParams": [],
17542
+ "requestSchema": {
17543
+ "type": "object",
17544
+ "additionalProperties": false,
17545
+ "description": "Provide exactly one of `endpoint_id` or `function_id`. With `function_id`,\na route-target endpoint is minted for that function and the route is bound\nto it in one transaction.\n",
17546
+ "properties": {
17547
+ "match_type": {
17548
+ "type": "string",
17549
+ "enum": [
17550
+ "exact",
17551
+ "wildcard",
17552
+ "regex"
17553
+ ]
17554
+ },
17555
+ "pattern": {
17556
+ "type": "string",
17557
+ "minLength": 1,
17558
+ "maxLength": 512
17559
+ },
17560
+ "endpoint_id": {
17561
+ "type": "string",
17562
+ "format": "uuid",
17563
+ "description": "An existing endpoint to route to. Mutually exclusive with function_id."
17564
+ },
17565
+ "function_id": {
17566
+ "type": "string",
17567
+ "format": "uuid",
17568
+ "description": "Route to this function, minting its route-target endpoint if needed. Mutually exclusive with endpoint_id."
17569
+ },
17570
+ "domain_id": {
17571
+ "type": ["string", "null"],
17572
+ "format": "uuid",
17573
+ "description": "Scope the route to a domain; defaults to the pattern's domain."
17574
+ },
17575
+ "priority": {
17576
+ "type": "integer",
17577
+ "minimum": 0,
17578
+ "maximum": 1e6
17579
+ },
17580
+ "enabled": { "type": "boolean" }
17581
+ },
17582
+ "required": ["match_type", "pattern"]
17583
+ },
17584
+ "responseSchema": {
17585
+ "type": "object",
17586
+ "description": "A recipient routing rule binding an address pattern to one endpoint.",
17587
+ "properties": {
17588
+ "id": {
17589
+ "type": "string",
17590
+ "format": "uuid"
17591
+ },
17592
+ "org_id": {
17593
+ "type": "string",
17594
+ "format": "uuid"
17595
+ },
17596
+ "domain_id": {
17597
+ "type": ["string", "null"],
17598
+ "format": "uuid",
17599
+ "description": "Domain the route is scoped to; null = org-wide."
17600
+ },
17601
+ "match_type": {
17602
+ "type": "string",
17603
+ "enum": [
17604
+ "exact",
17605
+ "wildcard",
17606
+ "regex"
17607
+ ]
17608
+ },
17609
+ "pattern": {
17610
+ "type": "string",
17611
+ "description": "The recipient address pattern (an exact address or a wildcard)."
17612
+ },
17613
+ "pattern_norm": {
17614
+ "type": ["string", "null"],
17615
+ "description": "Normalized pattern used for matching."
17616
+ },
17617
+ "endpoint_id": {
17618
+ "type": "string",
17619
+ "format": "uuid",
17620
+ "description": "The endpoint inbound mail matching this rule is delivered to."
17621
+ },
17622
+ "priority": {
17623
+ "type": "integer",
17624
+ "description": "Evaluation order within a scope; lower is checked first."
17625
+ },
17626
+ "enabled": { "type": "boolean" },
17627
+ "match_count": {
17628
+ "type": "string",
17629
+ "description": "How many emails have matched this rule (a bigint, returned as a string)."
17630
+ },
17631
+ "last_matched_at": {
17632
+ "type": ["string", "null"],
17633
+ "format": "date-time"
17634
+ },
17635
+ "created_at": {
17636
+ "type": "string",
17637
+ "format": "date-time"
17638
+ }
17639
+ },
17640
+ "required": ["id"]
17641
+ },
17642
+ "sdkName": "createRoute",
17643
+ "summary": "Create a recipient route",
17644
+ "tag": "Routes",
17645
+ "tagCommand": "routes"
17646
+ },
17647
+ {
17648
+ "binaryResponse": false,
17649
+ "bodyRequired": false,
17650
+ "command": "delete-route",
17651
+ "description": null,
17652
+ "hasJsonBody": false,
17653
+ "method": "DELETE",
17654
+ "operationId": "deleteRoute",
17655
+ "path": "/routes/{id}",
17656
+ "pathParams": [{
17657
+ "description": "Resource UUID",
17658
+ "enum": null,
17659
+ "name": "id",
17660
+ "required": true,
17661
+ "type": "string"
17662
+ }],
17663
+ "queryParams": [],
17664
+ "requestSchema": null,
17665
+ "responseSchema": null,
17666
+ "sdkName": "deleteRoute",
17667
+ "summary": "Delete a recipient route",
17668
+ "tag": "Routes",
17669
+ "tagCommand": "routes"
17670
+ },
17671
+ {
17672
+ "binaryResponse": false,
17673
+ "bodyRequired": false,
17674
+ "command": "list-routes",
17675
+ "description": "Returns the org's recipient routing rules in evaluation order. Each rule\nbinds a recipient address pattern to one endpoint; inbound mail resolves\nto a single destination at delivery time.\n",
17676
+ "hasJsonBody": false,
17677
+ "method": "GET",
17678
+ "operationId": "listRoutes",
17679
+ "path": "/routes",
17680
+ "pathParams": [],
17681
+ "queryParams": [],
17682
+ "requestSchema": null,
17683
+ "responseSchema": {
17684
+ "type": "array",
17685
+ "items": {
17686
+ "type": "object",
17687
+ "description": "A recipient routing rule binding an address pattern to one endpoint.",
17688
+ "properties": {
17689
+ "id": {
17690
+ "type": "string",
17691
+ "format": "uuid"
17692
+ },
17693
+ "org_id": {
17694
+ "type": "string",
17695
+ "format": "uuid"
17696
+ },
17697
+ "domain_id": {
17698
+ "type": ["string", "null"],
17699
+ "format": "uuid",
17700
+ "description": "Domain the route is scoped to; null = org-wide."
17701
+ },
17702
+ "match_type": {
17703
+ "type": "string",
17704
+ "enum": [
17705
+ "exact",
17706
+ "wildcard",
17707
+ "regex"
17708
+ ]
17709
+ },
17710
+ "pattern": {
17711
+ "type": "string",
17712
+ "description": "The recipient address pattern (an exact address or a wildcard)."
17713
+ },
17714
+ "pattern_norm": {
17715
+ "type": ["string", "null"],
17716
+ "description": "Normalized pattern used for matching."
17717
+ },
17718
+ "endpoint_id": {
17719
+ "type": "string",
17720
+ "format": "uuid",
17721
+ "description": "The endpoint inbound mail matching this rule is delivered to."
17722
+ },
17723
+ "priority": {
17724
+ "type": "integer",
17725
+ "description": "Evaluation order within a scope; lower is checked first."
17726
+ },
17727
+ "enabled": { "type": "boolean" },
17728
+ "match_count": {
17729
+ "type": "string",
17730
+ "description": "How many emails have matched this rule (a bigint, returned as a string)."
17731
+ },
17732
+ "last_matched_at": {
17733
+ "type": ["string", "null"],
17734
+ "format": "date-time"
17735
+ },
17736
+ "created_at": {
17737
+ "type": "string",
17738
+ "format": "date-time"
17739
+ }
17740
+ },
17741
+ "required": ["id"]
17742
+ }
17743
+ },
17744
+ "sdkName": "listRoutes",
17745
+ "summary": "List recipient routes",
17746
+ "tag": "Routes",
17747
+ "tagCommand": "routes"
17748
+ },
17749
+ {
17750
+ "binaryResponse": false,
17751
+ "bodyRequired": true,
17752
+ "command": "reorder-routes",
17753
+ "description": "Update the priority of one or more routes in a single call.",
17754
+ "hasJsonBody": true,
17755
+ "method": "POST",
17756
+ "operationId": "reorderRoutes",
17757
+ "path": "/routes/reorder",
17758
+ "pathParams": [],
17759
+ "queryParams": [],
17760
+ "requestSchema": {
17761
+ "type": "object",
17762
+ "additionalProperties": false,
17763
+ "properties": { "updates": {
17764
+ "type": "array",
17765
+ "minItems": 1,
17766
+ "maxItems": 1e3,
17767
+ "items": {
17768
+ "type": "object",
17769
+ "additionalProperties": false,
17770
+ "properties": {
17771
+ "id": {
17772
+ "type": "string",
17773
+ "format": "uuid"
17774
+ },
17775
+ "priority": {
17776
+ "type": "integer",
17777
+ "minimum": 0,
17778
+ "maximum": 1e6
17779
+ }
17780
+ },
17781
+ "required": ["id", "priority"]
17782
+ }
17783
+ } },
17784
+ "required": ["updates"]
17785
+ },
17786
+ "responseSchema": {
17787
+ "type": "array",
17788
+ "items": {
17789
+ "type": "object",
17790
+ "description": "A recipient routing rule binding an address pattern to one endpoint.",
17791
+ "properties": {
17792
+ "id": {
17793
+ "type": "string",
17794
+ "format": "uuid"
17795
+ },
17796
+ "org_id": {
17797
+ "type": "string",
17798
+ "format": "uuid"
17799
+ },
17800
+ "domain_id": {
17801
+ "type": ["string", "null"],
17802
+ "format": "uuid",
17803
+ "description": "Domain the route is scoped to; null = org-wide."
17804
+ },
17805
+ "match_type": {
17806
+ "type": "string",
17807
+ "enum": [
17808
+ "exact",
17809
+ "wildcard",
17810
+ "regex"
17811
+ ]
17812
+ },
17813
+ "pattern": {
17814
+ "type": "string",
17815
+ "description": "The recipient address pattern (an exact address or a wildcard)."
17816
+ },
17817
+ "pattern_norm": {
17818
+ "type": ["string", "null"],
17819
+ "description": "Normalized pattern used for matching."
17820
+ },
17821
+ "endpoint_id": {
17822
+ "type": "string",
17823
+ "format": "uuid",
17824
+ "description": "The endpoint inbound mail matching this rule is delivered to."
17825
+ },
17826
+ "priority": {
17827
+ "type": "integer",
17828
+ "description": "Evaluation order within a scope; lower is checked first."
17829
+ },
17830
+ "enabled": { "type": "boolean" },
17831
+ "match_count": {
17832
+ "type": "string",
17833
+ "description": "How many emails have matched this rule (a bigint, returned as a string)."
17834
+ },
17835
+ "last_matched_at": {
17836
+ "type": ["string", "null"],
17837
+ "format": "date-time"
17838
+ },
17839
+ "created_at": {
17840
+ "type": "string",
17841
+ "format": "date-time"
17842
+ }
17843
+ },
17844
+ "required": ["id"]
17845
+ }
17846
+ },
17847
+ "sdkName": "reorderRoutes",
17848
+ "summary": "Reorder recipient routes",
17849
+ "tag": "Routes",
17850
+ "tagCommand": "routes"
17851
+ },
17852
+ {
17853
+ "binaryResponse": false,
17854
+ "bodyRequired": true,
17855
+ "command": "simulate-route",
17856
+ "description": "Resolves where an inbound email to `recipient` would be delivered, with a\ntrace of every rule evaluated and why. Read-only; creates nothing.\n",
17857
+ "hasJsonBody": true,
17858
+ "method": "POST",
17859
+ "operationId": "simulateRoute",
17860
+ "path": "/routes/simulate",
17861
+ "pathParams": [],
17862
+ "queryParams": [],
17863
+ "requestSchema": {
17864
+ "type": "object",
17865
+ "additionalProperties": false,
17866
+ "properties": {
17867
+ "recipient": {
17868
+ "type": "string",
17869
+ "minLength": 1,
17870
+ "maxLength": 320
17871
+ },
17872
+ "event_type": {
17873
+ "type": "string",
17874
+ "minLength": 1,
17875
+ "maxLength": 100,
17876
+ "description": "Event type to model; defaults to email.received."
17877
+ }
17878
+ },
17879
+ "required": ["recipient"]
17880
+ },
17881
+ "responseSchema": {
17882
+ "type": "object",
17883
+ "description": "Where an inbound email to the recipient would be delivered, and why.",
17884
+ "properties": {
17885
+ "outcome": {
17886
+ "type": "string",
17887
+ "enum": [
17888
+ "matched",
17889
+ "defaulted",
17890
+ "none"
17891
+ ]
17892
+ },
17893
+ "recipient": { "type": "string" },
17894
+ "endpoint_id": { "type": ["string", "null"] },
17895
+ "matched_route_id": { "type": ["string", "null"] },
17896
+ "matched_tier": {
16768
17897
  "type": ["string", "null"],
16769
- "description": "The registry-scoped name. Null on the global by-address read."
16770
- }
17898
+ "enum": [
17899
+ "exact",
17900
+ "wildcard",
17901
+ "regex",
17902
+ null
17903
+ ]
17904
+ },
17905
+ "matched_pattern": { "type": ["string", "null"] },
17906
+ "default_scope": {
17907
+ "type": ["string", "null"],
17908
+ "enum": [
17909
+ "domain",
17910
+ "org",
17911
+ null
17912
+ ]
17913
+ },
17914
+ "evaluated": {
17915
+ "type": "array",
17916
+ "items": {
17917
+ "type": "object",
17918
+ "properties": {
17919
+ "route_id": { "type": "string" },
17920
+ "tier": {
17921
+ "type": "string",
17922
+ "enum": [
17923
+ "exact",
17924
+ "wildcard",
17925
+ "regex"
17926
+ ]
17927
+ },
17928
+ "pattern": { "type": "string" },
17929
+ "result": {
17930
+ "type": "string",
17931
+ "enum": [
17932
+ "hit",
17933
+ "miss",
17934
+ "skipped",
17935
+ "error"
17936
+ ]
17937
+ },
17938
+ "reason": { "type": "string" }
17939
+ },
17940
+ "required": [
17941
+ "route_id",
17942
+ "tier",
17943
+ "pattern",
17944
+ "result"
17945
+ ]
17946
+ }
17947
+ },
17948
+ "truncated": { "type": "boolean" }
16771
17949
  },
16772
17950
  "required": [
16773
- "address",
16774
- "display_name",
16775
- "title",
16776
- "description",
16777
- "tags",
16778
- "handle"
17951
+ "outcome",
17952
+ "recipient",
17953
+ "endpoint_id",
17954
+ "matched_route_id",
17955
+ "matched_tier",
17956
+ "matched_pattern",
17957
+ "default_scope",
17958
+ "evaluated",
17959
+ "truncated"
16779
17960
  ]
16780
17961
  },
16781
- "sdkName": "resolveRegistryHandle",
16782
- "summary": "Resolve a registry handle to its agent",
16783
- "tag": "Registries",
16784
- "tagCommand": "registries"
16785
- },
16786
- {
16787
- "binaryResponse": false,
16788
- "bodyRequired": false,
16789
- "command": "unpublish-agent",
16790
- "description": null,
16791
- "hasJsonBody": false,
16792
- "method": "DELETE",
16793
- "operationId": "unpublishAgent",
16794
- "path": "/registries/{slug}/agents/{handle}",
16795
- "pathParams": [{
16796
- "description": "The registry slug.",
16797
- "enum": null,
16798
- "name": "slug",
16799
- "required": true,
16800
- "type": "string"
16801
- }, {
16802
- "description": "The registry-scoped handle the agent is published under.",
16803
- "enum": null,
16804
- "name": "handle",
16805
- "required": true,
16806
- "type": "string"
16807
- }],
16808
- "queryParams": [],
16809
- "requestSchema": null,
16810
- "responseSchema": null,
16811
- "sdkName": "unpublishAgent",
16812
- "summary": "Unpublish an agent from a registry",
16813
- "tag": "Registries",
16814
- "tagCommand": "registries"
17962
+ "sdkName": "simulateRoute",
17963
+ "summary": "Simulate routing for a recipient",
17964
+ "tag": "Routes",
17965
+ "tagCommand": "routes"
16815
17966
  },
16816
17967
  {
16817
17968
  "binaryResponse": false,
16818
17969
  "bodyRequired": true,
16819
- "command": "update-registry",
17970
+ "command": "update-route",
16820
17971
  "description": null,
16821
17972
  "hasJsonBody": true,
16822
17973
  "method": "PATCH",
16823
- "operationId": "updateRegistry",
16824
- "path": "/registries/{slug}",
17974
+ "operationId": "updateRoute",
17975
+ "path": "/routes/{id}",
16825
17976
  "pathParams": [{
16826
- "description": "The registry slug",
17977
+ "description": "Resource UUID",
16827
17978
  "enum": null,
16828
- "name": "slug",
17979
+ "name": "id",
16829
17980
  "required": true,
16830
17981
  "type": "string"
16831
17982
  }],
16832
17983
  "queryParams": [],
16833
17984
  "requestSchema": {
16834
17985
  "type": "object",
16835
- "minProperties": 1,
17986
+ "additionalProperties": false,
16836
17987
  "properties": {
16837
- "name": {
17988
+ "match_type": {
17989
+ "type": "string",
17990
+ "enum": [
17991
+ "exact",
17992
+ "wildcard",
17993
+ "regex"
17994
+ ]
17995
+ },
17996
+ "pattern": {
16838
17997
  "type": "string",
16839
17998
  "minLength": 1,
16840
- "maxLength": 120
17999
+ "maxLength": 512
16841
18000
  },
16842
- "description": {
18001
+ "endpoint_id": {
18002
+ "type": "string",
18003
+ "format": "uuid"
18004
+ },
18005
+ "domain_id": {
16843
18006
  "type": ["string", "null"],
16844
- "maxLength": 2e3
18007
+ "format": "uuid"
16845
18008
  },
16846
- "is_public": { "type": "boolean" },
16847
- "publish_policy": {
16848
- "type": "string",
16849
- "enum": [
16850
- "owner_only",
16851
- "request",
16852
- "open"
16853
- ],
16854
- "description": "Who may publish into a registry. owner_only: only the registry owner.\nrequest: anyone may request and the owner approves. open: anyone may\npublish and it lists immediately (no approval step).\n"
16855
- }
18009
+ "priority": {
18010
+ "type": "integer",
18011
+ "minimum": 0,
18012
+ "maximum": 1e6
18013
+ },
18014
+ "enabled": { "type": "boolean" }
16856
18015
  }
16857
18016
  },
16858
18017
  "responseSchema": {
16859
18018
  "type": "object",
16860
- "properties": { "id": {
16861
- "type": "string",
16862
- "format": "uuid"
16863
- } },
18019
+ "description": "A recipient routing rule binding an address pattern to one endpoint.",
18020
+ "properties": {
18021
+ "id": {
18022
+ "type": "string",
18023
+ "format": "uuid"
18024
+ },
18025
+ "org_id": {
18026
+ "type": "string",
18027
+ "format": "uuid"
18028
+ },
18029
+ "domain_id": {
18030
+ "type": ["string", "null"],
18031
+ "format": "uuid",
18032
+ "description": "Domain the route is scoped to; null = org-wide."
18033
+ },
18034
+ "match_type": {
18035
+ "type": "string",
18036
+ "enum": [
18037
+ "exact",
18038
+ "wildcard",
18039
+ "regex"
18040
+ ]
18041
+ },
18042
+ "pattern": {
18043
+ "type": "string",
18044
+ "description": "The recipient address pattern (an exact address or a wildcard)."
18045
+ },
18046
+ "pattern_norm": {
18047
+ "type": ["string", "null"],
18048
+ "description": "Normalized pattern used for matching."
18049
+ },
18050
+ "endpoint_id": {
18051
+ "type": "string",
18052
+ "format": "uuid",
18053
+ "description": "The endpoint inbound mail matching this rule is delivered to."
18054
+ },
18055
+ "priority": {
18056
+ "type": "integer",
18057
+ "description": "Evaluation order within a scope; lower is checked first."
18058
+ },
18059
+ "enabled": { "type": "boolean" },
18060
+ "match_count": {
18061
+ "type": "string",
18062
+ "description": "How many emails have matched this rule (a bigint, returned as a string)."
18063
+ },
18064
+ "last_matched_at": {
18065
+ "type": ["string", "null"],
18066
+ "format": "date-time"
18067
+ },
18068
+ "created_at": {
18069
+ "type": "string",
18070
+ "format": "date-time"
18071
+ }
18072
+ },
16864
18073
  "required": ["id"]
16865
18074
  },
16866
- "sdkName": "updateRegistry",
16867
- "summary": "Update a registry you own",
16868
- "tag": "Registries",
16869
- "tagCommand": "registries"
18075
+ "sdkName": "updateRoute",
18076
+ "summary": "Update a recipient route",
18077
+ "tag": "Routes",
18078
+ "tagCommand": "routes"
16870
18079
  },
16871
18080
  {
16872
18081
  "binaryResponse": false,
@@ -22655,8 +23864,8 @@ const PRIMITIVE_TEAM_AUTHOR = {
22655
23864
  name: "Primitive Team",
22656
23865
  url: "https://primitive.dev"
22657
23866
  };
22658
- const SDK_VERSION_RANGE = "^1.11.0";
22659
- const CLI_VERSION_RANGE = "^1.11.0";
23867
+ const SDK_VERSION_RANGE = "^1.13.0";
23868
+ const CLI_VERSION_RANGE = "^1.13.0";
22660
23869
  const ESBUILD_VERSION_RANGE = "^0.27.0";
22661
23870
  function renderHandler() {
22662
23871
  return `// env.PRIMITIVE_API_KEY, env.PRIMITIVE_WEBHOOK_SECRET, and
@@ -26720,6 +27929,22 @@ const X402_ERROR_HINTS = {
26720
27929
  payment_verification_failed: "The signed payment did not match the challenge. Make sure you are paying with the wallet and network the challenge was issued for.",
26721
27930
  ownership_proof_failed: "The signature did not prove control of the address. Make sure the wallet key matches the address you are registering."
26722
27931
  };
27932
+ /**
27933
+ * Sign an email-native x402 challenge into a payment-step `interaction.json`
27934
+ * envelope, locally and with no network call. This is the exact signing path
27935
+ * shared by `payments pay-email-step` (sign only) and `payments pay-email`
27936
+ * (sign and send), so both produce byte-identical `interaction.json` bytes for
27937
+ * the same challenge + key. The EIP-3009 / nonce derivation lives in the SDK's
27938
+ * `payEmailChallenge`; this helper just wires the CLI's key handling to it.
27939
+ */
27940
+ async function signEmailChallenge(params) {
27941
+ const client = createX402Client({
27942
+ apiKey: params.apiKey || void 0,
27943
+ baseUrl: x402BaseUrl(params.resolvedApiBaseUrl)
27944
+ });
27945
+ const signer = signerFromPrivateKey(params.privateKey);
27946
+ return client.payEmailChallenge(params.challenge, { signer });
27947
+ }
26723
27948
  /** Turn a hex private key into a viem account (a valid X402Signer). */
26724
27949
  function signerFromPrivateKey(rawKey) {
26725
27950
  const trimmed = rawKey.trim();
@@ -27040,17 +28265,16 @@ var PaymentsPayEmailStepCommand = class PaymentsPayEmailStepCommand extends Comm
27040
28265
  credentials: null
27041
28266
  };
27042
28267
  await runWithTiming(flags.time, async () => {
27043
- const client = createX402Client({
27044
- apiKey: flags["api-key"] || void 0,
27045
- baseUrl: x402BaseUrl(requestConfig.resolvedApiBaseUrl)
27046
- });
27047
28268
  try {
27048
- const challenge = readEmailChallenge({
27049
- inline: flags.challenge,
27050
- file: flags["challenge-file"]
28269
+ const built = await signEmailChallenge({
28270
+ challenge: readEmailChallenge({
28271
+ inline: flags.challenge,
28272
+ file: flags["challenge-file"]
28273
+ }),
28274
+ privateKey: flags["private-key"] ?? "",
28275
+ resolvedApiBaseUrl: requestConfig.resolvedApiBaseUrl,
28276
+ apiKey: flags["api-key"]
27051
28277
  });
27052
- const signer = signerFromPrivateKey(flags["private-key"] ?? "");
27053
- const built = await client.payEmailChallenge(challenge, { signer });
27054
28278
  if (flags.json) this.log(JSON.stringify(built.envelope, null, 2));
27055
28279
  else this.log(built.json);
27056
28280
  } catch (error) {
@@ -27065,6 +28289,136 @@ var PaymentsPayEmailStepCommand = class PaymentsPayEmailStepCommand extends Comm
27065
28289
  }
27066
28290
  };
27067
28291
  //#endregion
28292
+ //#region src/oclif/commands/payments-pay-email.ts
28293
+ /** The exact part name + content type the inbound matcher requires. */
28294
+ const INTERACTION_PART_FILENAME = "interaction.json";
28295
+ const INTERACTION_PART_CONTENT_TYPE = "application/json";
28296
+ /** Build the `interaction.json` attachment from a signed payment step. */
28297
+ function interactionAttachment(built) {
28298
+ return {
28299
+ filename: INTERACTION_PART_FILENAME,
28300
+ content_type: INTERACTION_PART_CONTENT_TYPE,
28301
+ content_base64: Buffer.from(built.json, "utf8").toString("base64")
28302
+ };
28303
+ }
28304
+ var PaymentsPayEmailCommand = class PaymentsPayEmailCommand extends Command {
28305
+ static description = `Pay an email-native x402 challenge in one step: sign it and send the signed interaction.json as an in-thread reply.
28306
+
28307
+ Reads the email challenge the payee issued (the JSON from
28308
+ \`payments create-email-challenge\`), derives and signs the interaction-bound
28309
+ EIP-3009 authorization locally with your wallet key (read from
28310
+ ${PRIVATE_KEY_ENV} by default), and replies in-thread to the challenge email
28311
+ with the signed \`interaction.json\` attached as an \`application/json\` part.
28312
+ The key never leaves your machine.
28313
+
28314
+ This is the recommended payer path. It replaces the two-step
28315
+ \`pay-email-step\` + \`reply --attachment interaction.json\` dance: no manual
28316
+ address or threading wrangling. Use \`pay-email-step\` only when you need the
28317
+ signed bytes as a portable artifact without sending.
28318
+
28319
+ --in-reply-to is the id of the inbound challenge email you received; the reply
28320
+ endpoint derives the recipient (the payee) and threading headers from it, and
28321
+ defaults the From to the inbound's recipient (you, the payer). Pass --from
28322
+ only to override that default.
28323
+
28324
+ Provide the challenge inline with --challenge, from a file with
28325
+ --challenge-file, or piped on stdin.`;
28326
+ static summary = "Sign an email x402 challenge and send it as an in-thread reply (one step)";
28327
+ static examples = [
28328
+ "<%= config.bin %> payments pay-email --challenge-file challenge.json --in-reply-to <inbound-email-id>",
28329
+ "cat challenge.json | <%= config.bin %> payments pay-email --in-reply-to <inbound-email-id> --wait",
28330
+ "<%= config.bin %> payments pay-email --challenge-file challenge.json --in-reply-to <inbound-email-id> --from 'Payer <payer@your-domain.example>'"
28331
+ ];
28332
+ static flags = {
28333
+ "api-key": Flags.string({
28334
+ description: "Primitive API key override (defaults to PRIMITIVE_API_KEY or saved OAuth login credentials)",
28335
+ env: "PRIMITIVE_API_KEY"
28336
+ }),
28337
+ "api-base-url": Flags.string({
28338
+ description: API_BASE_URL_FLAG_DESCRIPTION,
28339
+ env: "PRIMITIVE_API_BASE_URL",
28340
+ hidden: true
28341
+ }),
28342
+ "private-key": Flags.string({
28343
+ description: PRIVATE_KEY_FLAG_DESCRIPTION,
28344
+ env: PRIVATE_KEY_ENV
28345
+ }),
28346
+ challenge: Flags.string({
28347
+ description: "The email challenge object as a JSON string.",
28348
+ exclusive: ["challenge-file"]
28349
+ }),
28350
+ "challenge-file": Flags.string({
28351
+ description: "Path to a file containing the email challenge JSON.",
28352
+ exclusive: ["challenge"]
28353
+ }),
28354
+ "in-reply-to": Flags.string({
28355
+ description: "Id of the inbound challenge email you received. The reply is threaded to it and addressed to the payee derived from it.",
28356
+ required: true
28357
+ }),
28358
+ from: Flags.string({ description: "Optional From header override. Defaults to the inbound's recipient (the payer the challenge was addressed to)." }),
28359
+ wait: Flags.boolean({ description: "Block until the receiving MTA returns an outcome. Without --wait, the call returns once Primitive has accepted the reply for delivery." }),
28360
+ json: Flags.boolean({ description: "Print a JSON object with the signed interaction step and the send result." }),
28361
+ time: Flags.boolean({ description: TIME_FLAG_DESCRIPTION })
28362
+ };
28363
+ async run() {
28364
+ const { flags } = await this.parse(PaymentsPayEmailCommand);
28365
+ const { apiClient, auth, baseUrlOverridden } = await createAuthenticatedCliApiClient({
28366
+ apiKey: flags["api-key"],
28367
+ apiBaseUrl: flags["api-base-url"],
28368
+ configDir: this.config.configDir
28369
+ });
28370
+ const authFailureContext = {
28371
+ auth,
28372
+ baseUrlOverridden,
28373
+ configDir: this.config.configDir
28374
+ };
28375
+ await runWithTiming(flags.time, async () => {
28376
+ let built;
28377
+ try {
28378
+ built = await signEmailChallenge({
28379
+ challenge: readEmailChallenge({
28380
+ inline: flags.challenge,
28381
+ file: flags["challenge-file"]
28382
+ }),
28383
+ privateKey: flags["private-key"] ?? "",
28384
+ resolvedApiBaseUrl: auth.apiBaseUrl,
28385
+ apiKey: flags["api-key"]
28386
+ });
28387
+ } catch (error) {
28388
+ reportX402Error(error, authFailureContext);
28389
+ process.exitCode = 1;
28390
+ return;
28391
+ }
28392
+ const result = await replyToEmail({
28393
+ body: {
28394
+ attachments: [interactionAttachment(built)],
28395
+ ...flags.from !== void 0 ? { from: flags.from } : {},
28396
+ ...flags.wait !== void 0 ? { wait: flags.wait } : {}
28397
+ },
28398
+ client: apiClient.client,
28399
+ path: { id: flags["in-reply-to"] },
28400
+ responseStyle: "fields"
28401
+ });
28402
+ if (result.error) {
28403
+ const errorPayload = extractErrorPayload(result.error);
28404
+ writeErrorWithHints(errorPayload);
28405
+ surfaceUnauthorizedHint({
28406
+ ...authFailureContext,
28407
+ payload: errorPayload
28408
+ });
28409
+ process.exitCode = 1;
28410
+ return;
28411
+ }
28412
+ const sent = result.data?.data ?? null;
28413
+ if (flags.json) this.log(JSON.stringify({
28414
+ interaction: built.envelope,
28415
+ sent
28416
+ }, null, 2));
28417
+ else this.log(JSON.stringify(sent, null, 2));
28418
+ });
28419
+ }
28420
+ };
28421
+ //#endregion
27068
28422
  //#region src/oclif/commands/payments-register-payout-address.ts
27069
28423
  var PaymentsRegisterPayoutAddressCommand = class PaymentsRegisterPayoutAddressCommand extends Command {
27070
28424
  static description = `Register the default payout address your org receives x402 payments at.
@@ -28677,6 +30031,7 @@ const COMMANDS = {
28677
30031
  "payments:charge": PaymentsChargeCommand,
28678
30032
  "payments:pay-challenge": PaymentsPayCommand,
28679
30033
  "payments:pay": PaymentsPayCommand,
30034
+ "payments:pay-email": PaymentsPayEmailCommand,
28680
30035
  "payments:pay-email-step": PaymentsPayEmailStepCommand
28681
30036
  };
28682
30037
  //#endregion