primcli 1.4.0 → 1.6.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 +40 -1
  2. package/dist/oclif/index.js +2628 -148
  3. package/package.json +7 -2
@@ -7,6 +7,8 @@ import process$1 from "node:process";
7
7
  import { createInterface } from "node:readline/promises";
8
8
  import { hostname } from "node:os";
9
9
  import { spawn } from "node:child_process";
10
+ import { X402Error, createX402Client } from "@primitivedotdev/sdk/x402";
11
+ import { privateKeyToAccount } from "viem/accounts";
10
12
  //#region \0rolldown/runtime.js
11
13
  var __defProp = Object.defineProperty;
12
14
  var __exportAll = (all, no_symbols) => {
@@ -28,21 +30,25 @@ var sdk_gen_exports = /* @__PURE__ */ __exportAll({
28
30
  cliLogout: () => cliLogout,
29
31
  createAgentAccount: () => createAgentAccount,
30
32
  createAgentClaimLink: () => createAgentClaimLink,
33
+ createChallenge: () => createChallenge,
31
34
  createEndpoint: () => createEndpoint,
32
35
  createFilter: () => createFilter,
33
36
  createFunction: () => createFunction,
34
37
  createFunctionSecret: () => createFunctionSecret,
38
+ createOrgSecret: () => createOrgSecret,
35
39
  deleteDomain: () => deleteDomain,
36
40
  deleteEmail: () => deleteEmail,
37
41
  deleteEndpoint: () => deleteEndpoint,
38
42
  deleteFilter: () => deleteFilter,
39
43
  deleteFunction: () => deleteFunction,
40
44
  deleteFunctionSecret: () => deleteFunctionSecret,
45
+ deleteOrgSecret: () => deleteOrgSecret,
41
46
  discardEmailContent: () => discardEmailContent,
42
47
  downloadAttachments: () => downloadAttachments,
43
48
  downloadDomainZoneFile: () => downloadDomainZoneFile,
44
49
  downloadRawEmail: () => downloadRawEmail,
45
50
  getAccount: () => getAccount,
51
+ getChallenge: () => getChallenge,
46
52
  getConversation: () => getConversation,
47
53
  getEmail: () => getEmail,
48
54
  getFunction: () => getFunction,
@@ -52,9 +58,11 @@ var sdk_gen_exports = /* @__PURE__ */ __exportAll({
52
58
  getOrgRoutingTopology: () => getOrgRoutingTopology,
53
59
  getSendPermissions: () => getSendPermissions,
54
60
  getSentEmail: () => getSentEmail,
61
+ getSpendPolicy: () => getSpendPolicy,
55
62
  getStorageStats: () => getStorageStats,
56
63
  getThread: () => getThread,
57
64
  getWebhookSecret: () => getWebhookSecret,
65
+ listDeclinedPayments: () => listDeclinedPayments,
58
66
  listDeliveries: () => listDeliveries,
59
67
  listDomains: () => listDomains,
60
68
  listEmails: () => listEmails,
@@ -63,8 +71,12 @@ var sdk_gen_exports = /* @__PURE__ */ __exportAll({
63
71
  listFunctionLogs: () => listFunctionLogs,
64
72
  listFunctionSecrets: () => listFunctionSecrets,
65
73
  listFunctions: () => listFunctions,
74
+ listOrgSecrets: () => listOrgSecrets,
75
+ listPayoutAddresses: () => listPayoutAddresses,
66
76
  listSentEmails: () => listSentEmails,
77
+ payChallenge: () => payChallenge,
67
78
  pollCliLogin: () => pollCliLogin,
79
+ registerPayoutAddress: () => registerPayoutAddress,
68
80
  replayDelivery: () => replayDelivery,
69
81
  replayEmailWebhooks: () => replayEmailWebhooks,
70
82
  replyToEmail: () => replyToEmail,
@@ -76,6 +88,7 @@ var sdk_gen_exports = /* @__PURE__ */ __exportAll({
76
88
  sendEmail: () => sendEmail,
77
89
  setFunctionRoute: () => setFunctionRoute,
78
90
  setFunctionSecret: () => setFunctionSecret,
91
+ setOrgSecret: () => setOrgSecret,
79
92
  startAgentClaim: () => startAgentClaim,
80
93
  startAgentSignup: () => startAgentSignup,
81
94
  startCliLogin: () => startCliLogin,
@@ -88,6 +101,7 @@ var sdk_gen_exports = /* @__PURE__ */ __exportAll({
88
101
  updateEndpoint: () => updateEndpoint,
89
102
  updateFilter: () => updateFilter,
90
103
  updateFunction: () => updateFunction,
104
+ updateSpendPolicy: () => updateSpendPolicy,
91
105
  verifyAgentClaim: () => verifyAgentClaim,
92
106
  verifyAgentSignup: () => verifyAgentSignup,
93
107
  verifyCliSignup: () => verifyCliSignup,
@@ -1517,6 +1531,85 @@ const setFunctionSecret = (options) => (options.client ?? client).put({
1517
1531
  }
1518
1532
  });
1519
1533
  /**
1534
+ * List org-level (global) secrets
1535
+ *
1536
+ * Returns metadata for every org-level secret. Org secrets apply
1537
+ * to every function in the org and are read as `env.<KEY>` in
1538
+ * handlers. **Values are never returned.** Secret writes are
1539
+ * write-only. A function-level secret of the same name overrides
1540
+ * the org-level value for that function.
1541
+ *
1542
+ */
1543
+ const listOrgSecrets = (options) => (options?.client ?? client).get({
1544
+ security: [{
1545
+ scheme: "bearer",
1546
+ type: "http"
1547
+ }],
1548
+ url: "/org/secrets",
1549
+ ...options
1550
+ });
1551
+ /**
1552
+ * Create or update an org secret
1553
+ *
1554
+ * Idempotent insert-or-update keyed on `(org_id, key)`. Returns
1555
+ * 201 the first time the key is set, 200 on subsequent updates.
1556
+ * Values are encrypted at rest. A changed value lands in a
1557
+ * function only on that function's next deploy.
1558
+ *
1559
+ * Keys must match `^[A-Z_][A-Z0-9_]*$` (uppercase letters,
1560
+ * digits, underscores; first character is a letter or
1561
+ * underscore). Values are at most 4096 UTF-8 bytes. System-
1562
+ * managed keys are reserved and rejected.
1563
+ *
1564
+ */
1565
+ const createOrgSecret = (options) => (options.client ?? client).post({
1566
+ security: [{
1567
+ scheme: "bearer",
1568
+ type: "http"
1569
+ }],
1570
+ url: "/org/secrets",
1571
+ ...options,
1572
+ headers: {
1573
+ ...options.body !== void 0 && { "Content-Type": "application/json" },
1574
+ ...options.headers
1575
+ }
1576
+ });
1577
+ /**
1578
+ * Delete an org secret
1579
+ *
1580
+ * Removes the org secret. Functions keep the previous value until
1581
+ * each is redeployed. Returns 404 if the key did not exist.
1582
+ *
1583
+ */
1584
+ const deleteOrgSecret = (options) => (options.client ?? client).delete({
1585
+ security: [{
1586
+ scheme: "bearer",
1587
+ type: "http"
1588
+ }],
1589
+ url: "/org/secrets/{key}",
1590
+ ...options
1591
+ });
1592
+ /**
1593
+ * Set an org secret by key
1594
+ *
1595
+ * Path-keyed companion to `POST /org/secrets`. Idempotent:
1596
+ * returns 201 the first time the key is set, 200 on subsequent
1597
+ * updates. Same validation and write-only guarantees as POST.
1598
+ *
1599
+ */
1600
+ const setOrgSecret = (options) => (options.client ?? client).put({
1601
+ security: [{
1602
+ scheme: "bearer",
1603
+ type: "http"
1604
+ }],
1605
+ url: "/org/secrets/{key}",
1606
+ ...options,
1607
+ headers: {
1608
+ ...options.body !== void 0 && { "Content-Type": "application/json" },
1609
+ ...options.headers
1610
+ }
1611
+ });
1612
+ /**
1520
1613
  * List a function's execution logs
1521
1614
  *
1522
1615
  * Returns the most recent `function_logs` rows for the function,
@@ -1538,6 +1631,165 @@ const listFunctionLogs = (options) => (options.client ?? client).get({
1538
1631
  url: "/functions/{id}/logs",
1539
1632
  ...options
1540
1633
  });
1634
+ /**
1635
+ * List payout addresses
1636
+ *
1637
+ * List your org's registered payout addresses, newest first.
1638
+ */
1639
+ const listPayoutAddresses = (options) => (options?.client ?? client).get({
1640
+ security: [{
1641
+ scheme: "bearer",
1642
+ type: "http"
1643
+ }],
1644
+ url: "/x402/payout-addresses",
1645
+ ...options
1646
+ });
1647
+ /**
1648
+ * Register a payout address
1649
+ *
1650
+ * Register (or update) the default payout address your org receives x402
1651
+ * payments at, for a given network. You prove control of the address with
1652
+ * an org-bound `personal_sign` signature over the message produced by the
1653
+ * SDK helper `buildPayoutRegistrationMessage`. The org id is taken from your
1654
+ * authenticated key, never the body, so a captured signature can't register
1655
+ * an address under another org. Exactly one default address exists per
1656
+ * (org, network); registering again replaces it. A payee MUST register a
1657
+ * payout address before calling `createChallenge`, because the challenge's
1658
+ * `pay_to` is resolved from this directory.
1659
+ *
1660
+ */
1661
+ const registerPayoutAddress = (options) => (options.client ?? client).post({
1662
+ security: [{
1663
+ scheme: "bearer",
1664
+ type: "http"
1665
+ }],
1666
+ url: "/x402/payout-addresses",
1667
+ ...options,
1668
+ headers: {
1669
+ ...options.body !== void 0 && { "Content-Type": "application/json" },
1670
+ ...options.headers
1671
+ }
1672
+ });
1673
+ /**
1674
+ * Create a payment challenge
1675
+ *
1676
+ * Create an x402 payment challenge (the payee side of a payment). The
1677
+ * `pay_to` address is resolved server-side from your registered default
1678
+ * payout address for the network, never from the request. The response
1679
+ * carries the `nonce_binding` and `payment_requirements` the payer needs to
1680
+ * sign; hand the whole challenge object to the payer (for example in an
1681
+ * email reply). Amounts are in token base units (USDC has 6 decimals, so
1682
+ * `"10000"` is 0.01 USDC).
1683
+ *
1684
+ */
1685
+ const createChallenge = (options) => (options.client ?? client).post({
1686
+ security: [{
1687
+ scheme: "bearer",
1688
+ type: "http"
1689
+ }],
1690
+ url: "/x402/challenges",
1691
+ ...options,
1692
+ headers: {
1693
+ ...options.body !== void 0 && { "Content-Type": "application/json" },
1694
+ ...options.headers
1695
+ }
1696
+ });
1697
+ /**
1698
+ * Get a payment challenge
1699
+ *
1700
+ * Fetch a challenge you created, to poll its `status` and settlement
1701
+ * receipt (`settle_tx`). Scoped to the challenger org that created it.
1702
+ *
1703
+ */
1704
+ const getChallenge = (options) => (options.client ?? client).get({
1705
+ security: [{
1706
+ scheme: "bearer",
1707
+ type: "http"
1708
+ }],
1709
+ url: "/x402/challenges/{id}",
1710
+ ...options
1711
+ });
1712
+ /**
1713
+ * Pay a payment challenge
1714
+ *
1715
+ * Settle a challenge addressed to your org as payer. The request body
1716
+ * carries a signed x402 `PaymentPayload`: an EIP-3009
1717
+ * `transferWithAuthorization` signed locally with your own key, whose nonce
1718
+ * is bound to the challenge via the SDK's `deriveEip3009Nonce`. The platform
1719
+ * verifies every signed field against its own record of the challenge,
1720
+ * applies your spend policy, and settles on-chain through a facilitator.
1721
+ * Settlement is non-custodial; Primitive never holds funds. Idempotent:
1722
+ * paying an already-settled challenge returns the original receipt. Most
1723
+ * callers use the SDK `pay()` helper rather than building the payload by
1724
+ * hand.
1725
+ *
1726
+ */
1727
+ const payChallenge = (options) => (options.client ?? client).post({
1728
+ security: [{
1729
+ scheme: "bearer",
1730
+ type: "http"
1731
+ }],
1732
+ url: "/x402/challenges/{id}/pay",
1733
+ ...options,
1734
+ headers: {
1735
+ ...options.body !== void 0 && { "Content-Type": "application/json" },
1736
+ ...options.headers
1737
+ }
1738
+ });
1739
+ /**
1740
+ * Get your spend policy
1741
+ *
1742
+ * Read your org's outbound spend policy: the kill-switch, per-payment and
1743
+ * per-day caps, and the payee allowlist. Returns the defaults (no limits,
1744
+ * not paused) when no policy has been set.
1745
+ *
1746
+ */
1747
+ const getSpendPolicy = (options) => (options?.client ?? client).get({
1748
+ security: [{
1749
+ scheme: "bearer",
1750
+ type: "http"
1751
+ }],
1752
+ url: "/x402/spend-policy",
1753
+ ...options
1754
+ });
1755
+ /**
1756
+ * Update your spend policy
1757
+ *
1758
+ * Update your org's spend policy. Applied as a merge: only the fields you
1759
+ * include change, and omitted fields keep their current value, so a partial
1760
+ * update can't silently reset the kill-switch. Send an explicit `null` to
1761
+ * clear a cap. Caps are in token base units.
1762
+ *
1763
+ */
1764
+ const updateSpendPolicy = (options) => (options.client ?? client).put({
1765
+ security: [{
1766
+ scheme: "bearer",
1767
+ type: "http"
1768
+ }],
1769
+ url: "/x402/spend-policy",
1770
+ ...options,
1771
+ headers: {
1772
+ ...options.body !== void 0 && { "Content-Type": "application/json" },
1773
+ ...options.headers
1774
+ }
1775
+ });
1776
+ /**
1777
+ * List declined payments
1778
+ *
1779
+ * The 50 most recent payments your org's spend policy declined, newest
1780
+ * first. Use this to see why an outbound payment was refused (a cap, the
1781
+ * payee allowlist, or the kill-switch) instead of only reading the
1782
+ * dashboard.
1783
+ *
1784
+ */
1785
+ const listDeclinedPayments = (options) => (options?.client ?? client).get({
1786
+ security: [{
1787
+ scheme: "bearer",
1788
+ type: "http"
1789
+ }],
1790
+ url: "/x402/declined-payments",
1791
+ ...options
1792
+ });
1541
1793
  //#endregion
1542
1794
  //#region ../packages/api-core/src/openapi/openapi.generated.ts
1543
1795
  /**
@@ -1614,6 +1866,10 @@ const openapiDocument = {
1614
1866
  "name": "Filters",
1615
1867
  "description": "Manage whitelist and blocklist filter rules"
1616
1868
  },
1869
+ {
1870
+ "name": "Payments",
1871
+ "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"
1872
+ },
1617
1873
  {
1618
1874
  "name": "Webhook Deliveries",
1619
1875
  "description": "View and replay webhook delivery attempts"
@@ -3709,6 +3965,111 @@ const openapiDocument = {
3709
3965
  }
3710
3966
  }
3711
3967
  },
3968
+ "/org/secrets": {
3969
+ "get": {
3970
+ "operationId": "listOrgSecrets",
3971
+ "summary": "List org-level (global) secrets",
3972
+ "description": "Returns metadata for every org-level secret. Org secrets apply\nto every function in the org and are read as `env.<KEY>` in\nhandlers. **Values are never returned.** Secret writes are\nwrite-only. A function-level secret of the same name overrides\nthe org-level value for that function.\n",
3973
+ "tags": ["Functions"],
3974
+ "responses": {
3975
+ "200": {
3976
+ "description": "List of org secrets (metadata only, no values)",
3977
+ "content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/SuccessEnvelope" }, {
3978
+ "type": "object",
3979
+ "properties": { "data": {
3980
+ "type": "object",
3981
+ "properties": { "items": {
3982
+ "type": "array",
3983
+ "items": { "$ref": "#/components/schemas/OrgSecretListItem" }
3984
+ } },
3985
+ "required": ["items"]
3986
+ } }
3987
+ }] } } }
3988
+ },
3989
+ "401": { "$ref": "#/components/responses/Unauthorized" }
3990
+ }
3991
+ },
3992
+ "post": {
3993
+ "operationId": "createOrgSecret",
3994
+ "summary": "Create or update an org secret",
3995
+ "description": "Idempotent insert-or-update keyed on `(org_id, key)`. Returns\n201 the first time the key is set, 200 on subsequent updates.\nValues are encrypted at rest. A changed value lands in a\nfunction only on that function's next deploy.\n\nKeys must match `^[A-Z_][A-Z0-9_]*$` (uppercase letters,\ndigits, underscores; first character is a letter or\nunderscore). Values are at most 4096 UTF-8 bytes. System-\nmanaged keys are reserved and rejected.\n",
3996
+ "tags": ["Functions"],
3997
+ "requestBody": {
3998
+ "required": true,
3999
+ "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateOrgSecretInput" } } }
4000
+ },
4001
+ "responses": {
4002
+ "200": {
4003
+ "description": "Secret updated",
4004
+ "content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/SuccessEnvelope" }, {
4005
+ "type": "object",
4006
+ "properties": { "data": { "$ref": "#/components/schemas/OrgSecretWriteResult" } }
4007
+ }] } } }
4008
+ },
4009
+ "201": {
4010
+ "description": "Secret created",
4011
+ "content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/SuccessEnvelope" }, {
4012
+ "type": "object",
4013
+ "properties": { "data": { "$ref": "#/components/schemas/OrgSecretWriteResult" } }
4014
+ }] } } }
4015
+ },
4016
+ "400": { "$ref": "#/components/responses/ValidationError" },
4017
+ "401": { "$ref": "#/components/responses/Unauthorized" }
4018
+ }
4019
+ }
4020
+ },
4021
+ "/org/secrets/{key}": {
4022
+ "parameters": [{
4023
+ "name": "key",
4024
+ "in": "path",
4025
+ "required": true,
4026
+ "description": "Secret key. Must match `^[A-Z_][A-Z0-9_]*$`.",
4027
+ "schema": {
4028
+ "type": "string",
4029
+ "pattern": "^[A-Z_][A-Z0-9_]*$"
4030
+ }
4031
+ }],
4032
+ "put": {
4033
+ "operationId": "setOrgSecret",
4034
+ "summary": "Set an org secret by key",
4035
+ "description": "Path-keyed companion to `POST /org/secrets`. Idempotent:\nreturns 201 the first time the key is set, 200 on subsequent\nupdates. Same validation and write-only guarantees as POST.\n",
4036
+ "tags": ["Functions"],
4037
+ "requestBody": {
4038
+ "required": true,
4039
+ "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SetOrgSecretInput" } } }
4040
+ },
4041
+ "responses": {
4042
+ "200": {
4043
+ "description": "Secret updated",
4044
+ "content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/SuccessEnvelope" }, {
4045
+ "type": "object",
4046
+ "properties": { "data": { "$ref": "#/components/schemas/OrgSecretWriteResult" } }
4047
+ }] } } }
4048
+ },
4049
+ "201": {
4050
+ "description": "Secret created",
4051
+ "content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/SuccessEnvelope" }, {
4052
+ "type": "object",
4053
+ "properties": { "data": { "$ref": "#/components/schemas/OrgSecretWriteResult" } }
4054
+ }] } } }
4055
+ },
4056
+ "400": { "$ref": "#/components/responses/ValidationError" },
4057
+ "401": { "$ref": "#/components/responses/Unauthorized" }
4058
+ }
4059
+ },
4060
+ "delete": {
4061
+ "operationId": "deleteOrgSecret",
4062
+ "summary": "Delete an org secret",
4063
+ "description": "Removes the org secret. Functions keep the previous value until\neach is redeployed. Returns 404 if the key did not exist.\n",
4064
+ "tags": ["Functions"],
4065
+ "responses": {
4066
+ "204": { "description": "Secret deleted" },
4067
+ "400": { "$ref": "#/components/responses/ValidationError" },
4068
+ "401": { "$ref": "#/components/responses/Unauthorized" },
4069
+ "404": { "$ref": "#/components/responses/NotFound" }
4070
+ }
4071
+ }
4072
+ },
3712
4073
  "/functions/{id}/logs": {
3713
4074
  "parameters": [{ "$ref": "#/components/parameters/ResourceId" }],
3714
4075
  "get": {
@@ -3761,30 +4122,222 @@ const openapiDocument = {
3761
4122
  "404": { "$ref": "#/components/responses/NotFound" }
3762
4123
  }
3763
4124
  }
3764
- }
3765
- },
3766
- "components": {
3767
- "securitySchemes": {
3768
- "BearerAuth": {
3769
- "type": "http",
3770
- "scheme": "bearer",
3771
- "description": "API key with `prim_` prefix: `Authorization: Bearer prim_<key>`"
3772
- },
3773
- "DownloadToken": {
3774
- "type": "apiKey",
3775
- "in": "query",
3776
- "name": "token",
3777
- "description": "Signed download token provided in webhook payloads"
3778
- }
3779
4125
  },
3780
- "parameters": {
3781
- "ResourceId": {
3782
- "name": "id",
3783
- "in": "path",
3784
- "required": true,
3785
- "schema": {
3786
- "type": "string",
3787
- "format": "uuid"
4126
+ "/x402/payout-addresses": {
4127
+ "post": {
4128
+ "operationId": "registerPayoutAddress",
4129
+ "summary": "Register a payout address",
4130
+ "description": "Register (or update) the default payout address your org receives x402\npayments at, for a given network. You prove control of the address with\nan org-bound `personal_sign` signature over the message produced by the\nSDK helper `buildPayoutRegistrationMessage`. The org id is taken from your\nauthenticated key, never the body, so a captured signature can't register\nan address under another org. Exactly one default address exists per\n(org, network); registering again replaces it. A payee MUST register a\npayout address before calling `createChallenge`, because the challenge's\n`pay_to` is resolved from this directory.\n",
4131
+ "tags": ["Payments"],
4132
+ "security": [{ "BearerAuth": [] }],
4133
+ "requestBody": {
4134
+ "required": true,
4135
+ "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RegisterPayoutAddressInput" } } }
4136
+ },
4137
+ "responses": {
4138
+ "201": {
4139
+ "description": "Payout address registered (or updated) and set as default",
4140
+ "content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/SuccessEnvelope" }, {
4141
+ "type": "object",
4142
+ "properties": { "data": { "$ref": "#/components/schemas/X402PayoutAddress" } }
4143
+ }] } } }
4144
+ },
4145
+ "400": { "$ref": "#/components/responses/ValidationError" },
4146
+ "401": { "$ref": "#/components/responses/Unauthorized" },
4147
+ "403": { "$ref": "#/components/responses/Forbidden" },
4148
+ "422": { "$ref": "#/components/responses/UnprocessableEntity" },
4149
+ "429": { "$ref": "#/components/responses/RateLimited" }
4150
+ }
4151
+ },
4152
+ "get": {
4153
+ "operationId": "listPayoutAddresses",
4154
+ "summary": "List payout addresses",
4155
+ "description": "List your org's registered payout addresses, newest first.",
4156
+ "tags": ["Payments"],
4157
+ "security": [{ "BearerAuth": [] }],
4158
+ "responses": {
4159
+ "200": {
4160
+ "description": "Your registered payout addresses",
4161
+ "content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/SuccessEnvelope" }, {
4162
+ "type": "object",
4163
+ "properties": { "data": {
4164
+ "type": "array",
4165
+ "items": { "$ref": "#/components/schemas/X402PayoutAddress" }
4166
+ } }
4167
+ }] } } }
4168
+ },
4169
+ "401": { "$ref": "#/components/responses/Unauthorized" },
4170
+ "403": { "$ref": "#/components/responses/Forbidden" },
4171
+ "429": { "$ref": "#/components/responses/RateLimited" }
4172
+ }
4173
+ }
4174
+ },
4175
+ "/x402/challenges": { "post": {
4176
+ "operationId": "createChallenge",
4177
+ "summary": "Create a payment challenge",
4178
+ "description": "Create an x402 payment challenge (the payee side of a payment). The\n`pay_to` address is resolved server-side from your registered default\npayout address for the network, never from the request. The response\ncarries the `nonce_binding` and `payment_requirements` the payer needs to\nsign; hand the whole challenge object to the payer (for example in an\nemail reply). Amounts are in token base units (USDC has 6 decimals, so\n`\"10000\"` is 0.01 USDC).\n",
4179
+ "tags": ["Payments"],
4180
+ "security": [{ "BearerAuth": [] }],
4181
+ "requestBody": {
4182
+ "required": true,
4183
+ "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateChallengeInput" } } }
4184
+ },
4185
+ "responses": {
4186
+ "201": {
4187
+ "description": "Challenge created",
4188
+ "content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/SuccessEnvelope" }, {
4189
+ "type": "object",
4190
+ "properties": { "data": { "$ref": "#/components/schemas/X402Challenge" } }
4191
+ }] } } }
4192
+ },
4193
+ "400": { "$ref": "#/components/responses/ValidationError" },
4194
+ "401": { "$ref": "#/components/responses/Unauthorized" },
4195
+ "403": { "$ref": "#/components/responses/Forbidden" },
4196
+ "422": { "$ref": "#/components/responses/UnprocessableEntity" },
4197
+ "429": { "$ref": "#/components/responses/RateLimited" }
4198
+ }
4199
+ } },
4200
+ "/x402/challenges/{id}": { "get": {
4201
+ "operationId": "getChallenge",
4202
+ "summary": "Get a payment challenge",
4203
+ "description": "Fetch a challenge you created, to poll its `status` and settlement\nreceipt (`settle_tx`). Scoped to the challenger org that created it.\n",
4204
+ "tags": ["Payments"],
4205
+ "security": [{ "BearerAuth": [] }],
4206
+ "parameters": [{ "$ref": "#/components/parameters/ResourceId" }],
4207
+ "responses": {
4208
+ "200": {
4209
+ "description": "The challenge",
4210
+ "content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/SuccessEnvelope" }, {
4211
+ "type": "object",
4212
+ "properties": { "data": { "$ref": "#/components/schemas/X402Challenge" } }
4213
+ }] } } }
4214
+ },
4215
+ "400": { "$ref": "#/components/responses/ValidationError" },
4216
+ "401": { "$ref": "#/components/responses/Unauthorized" },
4217
+ "403": { "$ref": "#/components/responses/Forbidden" },
4218
+ "404": { "$ref": "#/components/responses/NotFound" },
4219
+ "429": { "$ref": "#/components/responses/RateLimited" }
4220
+ }
4221
+ } },
4222
+ "/x402/challenges/{id}/pay": { "post": {
4223
+ "operationId": "payChallenge",
4224
+ "summary": "Pay a payment challenge",
4225
+ "description": "Settle a challenge addressed to your org as payer. The request body\ncarries a signed x402 `PaymentPayload`: an EIP-3009\n`transferWithAuthorization` signed locally with your own key, whose nonce\nis bound to the challenge via the SDK's `deriveEip3009Nonce`. The platform\nverifies every signed field against its own record of the challenge,\napplies your spend policy, and settles on-chain through a facilitator.\nSettlement is non-custodial; Primitive never holds funds. Idempotent:\npaying an already-settled challenge returns the original receipt. Most\ncallers use the SDK `pay()` helper rather than building the payload by\nhand.\n",
4226
+ "tags": ["Payments"],
4227
+ "security": [{ "BearerAuth": [] }],
4228
+ "parameters": [{ "$ref": "#/components/parameters/ResourceId" }],
4229
+ "requestBody": {
4230
+ "required": true,
4231
+ "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PayChallengeInput" } } }
4232
+ },
4233
+ "responses": {
4234
+ "200": {
4235
+ "description": "Challenge settled (or already settled)",
4236
+ "content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/SuccessEnvelope" }, {
4237
+ "type": "object",
4238
+ "properties": { "data": { "$ref": "#/components/schemas/X402Receipt" } }
4239
+ }] } } }
4240
+ },
4241
+ "400": { "$ref": "#/components/responses/ValidationError" },
4242
+ "401": { "$ref": "#/components/responses/Unauthorized" },
4243
+ "403": { "$ref": "#/components/responses/Forbidden" },
4244
+ "404": { "$ref": "#/components/responses/NotFound" },
4245
+ "409": { "$ref": "#/components/responses/Conflict" },
4246
+ "422": { "$ref": "#/components/responses/UnprocessableEntity" },
4247
+ "429": { "$ref": "#/components/responses/RateLimited" },
4248
+ "502": { "$ref": "#/components/responses/BadGateway" }
4249
+ }
4250
+ } },
4251
+ "/x402/spend-policy": {
4252
+ "get": {
4253
+ "operationId": "getSpendPolicy",
4254
+ "summary": "Get your spend policy",
4255
+ "description": "Read your org's outbound spend policy: the kill-switch, per-payment and\nper-day caps, and the payee allowlist. Returns the defaults (no limits,\nnot paused) when no policy has been set.\n",
4256
+ "tags": ["Payments"],
4257
+ "security": [{ "BearerAuth": [] }],
4258
+ "responses": {
4259
+ "200": {
4260
+ "description": "The spend policy",
4261
+ "content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/SuccessEnvelope" }, {
4262
+ "type": "object",
4263
+ "properties": { "data": { "$ref": "#/components/schemas/X402SpendPolicy" } }
4264
+ }] } } }
4265
+ },
4266
+ "401": { "$ref": "#/components/responses/Unauthorized" },
4267
+ "403": { "$ref": "#/components/responses/Forbidden" },
4268
+ "429": { "$ref": "#/components/responses/RateLimited" }
4269
+ }
4270
+ },
4271
+ "put": {
4272
+ "operationId": "updateSpendPolicy",
4273
+ "summary": "Update your spend policy",
4274
+ "description": "Update your org's spend policy. Applied as a merge: only the fields you\ninclude change, and omitted fields keep their current value, so a partial\nupdate can't silently reset the kill-switch. Send an explicit `null` to\nclear a cap. Caps are in token base units.\n",
4275
+ "tags": ["Payments"],
4276
+ "security": [{ "BearerAuth": [] }],
4277
+ "requestBody": {
4278
+ "required": true,
4279
+ "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateSpendPolicyInput" } } }
4280
+ },
4281
+ "responses": {
4282
+ "200": {
4283
+ "description": "The updated spend policy",
4284
+ "content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/SuccessEnvelope" }, {
4285
+ "type": "object",
4286
+ "properties": { "data": { "$ref": "#/components/schemas/X402SpendPolicy" } }
4287
+ }] } } }
4288
+ },
4289
+ "400": { "$ref": "#/components/responses/ValidationError" },
4290
+ "401": { "$ref": "#/components/responses/Unauthorized" },
4291
+ "403": { "$ref": "#/components/responses/Forbidden" },
4292
+ "429": { "$ref": "#/components/responses/RateLimited" }
4293
+ }
4294
+ }
4295
+ },
4296
+ "/x402/declined-payments": { "get": {
4297
+ "operationId": "listDeclinedPayments",
4298
+ "summary": "List declined payments",
4299
+ "description": "The 50 most recent payments your org's spend policy declined, newest\nfirst. Use this to see why an outbound payment was refused (a cap, the\npayee allowlist, or the kill-switch) instead of only reading the\ndashboard.\n",
4300
+ "tags": ["Payments"],
4301
+ "security": [{ "BearerAuth": [] }],
4302
+ "responses": {
4303
+ "200": {
4304
+ "description": "Recently declined payments",
4305
+ "content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/SuccessEnvelope" }, {
4306
+ "type": "object",
4307
+ "properties": { "data": {
4308
+ "type": "array",
4309
+ "items": { "$ref": "#/components/schemas/X402DeclinedPayment" }
4310
+ } }
4311
+ }] } } }
4312
+ },
4313
+ "401": { "$ref": "#/components/responses/Unauthorized" },
4314
+ "403": { "$ref": "#/components/responses/Forbidden" },
4315
+ "429": { "$ref": "#/components/responses/RateLimited" }
4316
+ }
4317
+ } }
4318
+ },
4319
+ "components": {
4320
+ "securitySchemes": {
4321
+ "BearerAuth": {
4322
+ "type": "http",
4323
+ "scheme": "bearer",
4324
+ "description": "API key with `prim_` prefix: `Authorization: Bearer prim_<key>`"
4325
+ },
4326
+ "DownloadToken": {
4327
+ "type": "apiKey",
4328
+ "in": "query",
4329
+ "name": "token",
4330
+ "description": "Signed download token provided in webhook payloads"
4331
+ }
4332
+ },
4333
+ "parameters": {
4334
+ "ResourceId": {
4335
+ "name": "id",
4336
+ "in": "path",
4337
+ "required": true,
4338
+ "schema": {
4339
+ "type": "string",
4340
+ "format": "uuid"
3788
4341
  },
3789
4342
  "description": "Resource UUID"
3790
4343
  },
@@ -3928,6 +4481,32 @@ const openapiDocument = {
3928
4481
  }
3929
4482
  } }
3930
4483
  },
4484
+ "Conflict": {
4485
+ "description": "The request conflicts with the current state of the resource",
4486
+ "content": { "application/json": {
4487
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
4488
+ "example": {
4489
+ "success": false,
4490
+ "error": {
4491
+ "code": "conflict",
4492
+ "message": "settlement already in progress"
4493
+ }
4494
+ }
4495
+ } }
4496
+ },
4497
+ "UnprocessableEntity": {
4498
+ "description": "The request was well-formed but could not be processed. For Payments\nthis covers a missing payout address, a failed payment verification, a\nspend-policy decline, or an expired challenge; `error.code` distinguishes\nthem.\n",
4499
+ "content": { "application/json": {
4500
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
4501
+ "example": {
4502
+ "success": false,
4503
+ "error": {
4504
+ "code": "payment_declined",
4505
+ "message": "payment exceeds the per-payment cap"
4506
+ }
4507
+ }
4508
+ } }
4509
+ },
3931
4510
  "Deleted": {
3932
4511
  "description": "Resource deleted",
3933
4512
  "content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/SuccessEnvelope" }, {
@@ -3944,60 +4523,500 @@ const openapiDocument = {
3944
4523
  }
3945
4524
  },
3946
4525
  "schemas": {
3947
- "SuccessEnvelope": {
4526
+ "RegisterPayoutAddressInput": {
3948
4527
  "type": "object",
3949
- "properties": { "success": {
3950
- "type": "boolean",
3951
- "const": true
3952
- } },
3953
- "required": ["success", "data"]
4528
+ "additionalProperties": false,
4529
+ "properties": {
4530
+ "address": {
4531
+ "type": "string",
4532
+ "pattern": "^0x[0-9a-fA-F]{40}$",
4533
+ "description": "The payout address (your signer's own EVM address), 0x-prefixed."
4534
+ },
4535
+ "network": {
4536
+ "type": "string",
4537
+ "enum": ["base", "base-sepolia"],
4538
+ "description": "The chain the address receives on."
4539
+ },
4540
+ "signature": {
4541
+ "type": "string",
4542
+ "pattern": "^0x[0-9a-fA-F]+$",
4543
+ "description": "A `personal_sign` signature over the org-bound message produced by\nthe SDK helper `buildPayoutRegistrationMessage`. Recovered and\nchecked against `address`; the org id is bound into the signed bytes.\n"
4544
+ },
4545
+ "issued_at": {
4546
+ "type": "string",
4547
+ "format": "date-time",
4548
+ "description": "ISO-8601 timestamp embedded in the signed message. Must be within a\nshort freshness window (about 10 minutes) of server time.\n"
4549
+ },
4550
+ "label": {
4551
+ "type": "string",
4552
+ "maxLength": 80,
4553
+ "description": "Optional human-readable label."
4554
+ }
4555
+ },
4556
+ "required": [
4557
+ "address",
4558
+ "network",
4559
+ "signature",
4560
+ "issued_at"
4561
+ ]
3954
4562
  },
3955
- "ListEnvelope": {
4563
+ "X402PayoutAddress": {
3956
4564
  "type": "object",
3957
4565
  "properties": {
3958
- "success": {
4566
+ "id": {
4567
+ "type": "string",
4568
+ "format": "uuid"
4569
+ },
4570
+ "address": {
4571
+ "type": "string",
4572
+ "description": "The checksummed payout address."
4573
+ },
4574
+ "network": {
4575
+ "type": "string",
4576
+ "enum": ["base", "base-sepolia"]
4577
+ },
4578
+ "label": { "type": ["string", "null"] },
4579
+ "is_default": {
3959
4580
  "type": "boolean",
3960
- "const": true
4581
+ "description": "Exactly one address per (org, network) is the default."
3961
4582
  },
3962
- "meta": { "$ref": "#/components/schemas/PaginationMeta" }
4583
+ "verified_at": {
4584
+ "type": "string",
4585
+ "format": "date-time",
4586
+ "description": "When ownership of the address was last proven."
4587
+ },
4588
+ "created_at": {
4589
+ "type": "string",
4590
+ "format": "date-time"
4591
+ }
3963
4592
  },
3964
4593
  "required": [
3965
- "success",
3966
- "data",
3967
- "meta"
4594
+ "id",
4595
+ "address",
4596
+ "network",
4597
+ "label",
4598
+ "is_default",
4599
+ "verified_at"
3968
4600
  ]
3969
4601
  },
3970
- "PaginationMeta": {
4602
+ "CreateChallengeInput": {
3971
4603
  "type": "object",
4604
+ "additionalProperties": false,
3972
4605
  "properties": {
3973
- "total": {
3974
- "type": "integer",
3975
- "description": "Total number of matching records"
4606
+ "amount": {
4607
+ "type": "string",
4608
+ "pattern": "^[1-9][0-9]{0,38}$",
4609
+ "description": "Amount to collect, in token base units. USDC has 6 decimals, so\n`\"10000\"` is 0.01 USDC.\n"
3976
4610
  },
3977
- "limit": {
4611
+ "network": {
4612
+ "type": "string",
4613
+ "enum": ["base", "base-sepolia"]
4614
+ },
4615
+ "payer_org": {
4616
+ "type": "string",
4617
+ "format": "uuid",
4618
+ "description": "The org id allowed to pay this challenge (on-net binding). Optional.\n"
4619
+ },
4620
+ "expires_in": {
3978
4621
  "type": "integer",
3979
- "description": "Page size used for this request"
4622
+ "minimum": 60,
4623
+ "maximum": 86400,
4624
+ "description": "Seconds until the challenge expires. Defaults to 3600."
3980
4625
  },
3981
- "cursor": {
3982
- "type": ["string", "null"],
3983
- "description": "Cursor for the next page, or null if no more results"
4626
+ "resource": {
4627
+ "type": "string",
4628
+ "format": "uri",
4629
+ "maxLength": 2048,
4630
+ "description": "Optional URL identifying what is being paid for. Defaults to a\nsynthetic `x402:challenge:<id>` identifier.\n"
4631
+ },
4632
+ "description": {
4633
+ "type": "string",
4634
+ "maxLength": 512,
4635
+ "description": "Optional human-readable description of the payment."
4636
+ }
4637
+ },
4638
+ "required": ["amount", "network"]
4639
+ },
4640
+ "X402NonceBinding": {
4641
+ "type": "object",
4642
+ "description": "The interaction binding the payer hashes into the EIP-3009 nonce\n(`deriveEip3009Nonce`). Pinning the nonce to this binding is what lets an\nx402 payment ride asynchronous transports safely: a replayed challenge\ncan't redirect funds and a signed payment can't settle twice.\n",
4643
+ "properties": {
4644
+ "interaction_id": {
4645
+ "type": "string",
4646
+ "description": "Interaction id, including its `@domain` part."
4647
+ },
4648
+ "challenge_step_id": {
4649
+ "type": "string",
4650
+ "format": "uuid"
4651
+ },
4652
+ "challenge_nonce": {
4653
+ "type": "string",
4654
+ "pattern": "^[0-9a-f]{64}$",
4655
+ "description": "32 random bytes as 64 lowercase hex chars."
3984
4656
  }
3985
4657
  },
3986
4658
  "required": [
3987
- "total",
3988
- "limit",
3989
- "cursor"
4659
+ "interaction_id",
4660
+ "challenge_step_id",
4661
+ "challenge_nonce"
3990
4662
  ]
3991
4663
  },
3992
- "ErrorResponse": {
4664
+ "X402PaymentRequirements": {
3993
4665
  "type": "object",
4666
+ "description": "The x402 `PaymentRequirements` the payer signs over. Field names are\nx402's native camelCase, preserved byte-for-byte.\n",
3994
4667
  "properties": {
3995
- "success": {
3996
- "type": "boolean",
3997
- "const": false
4668
+ "scheme": {
4669
+ "type": "string",
4670
+ "description": "The x402 settlement scheme. Always `exact` for v1.",
4671
+ "example": "exact"
3998
4672
  },
3999
- "error": {
4000
- "type": "object",
4673
+ "network": {
4674
+ "type": "string",
4675
+ "enum": ["base", "base-sepolia"]
4676
+ },
4677
+ "maxAmountRequired": {
4678
+ "type": "string",
4679
+ "description": "Amount in token base units."
4680
+ },
4681
+ "payTo": {
4682
+ "type": "string",
4683
+ "description": "The payee's resolved payout address (checksummed)."
4684
+ },
4685
+ "asset": {
4686
+ "type": "string",
4687
+ "description": "The token contract address (checksummed). USDC."
4688
+ },
4689
+ "resource": { "type": "string" },
4690
+ "description": { "type": "string" },
4691
+ "maxTimeoutSeconds": { "type": "integer" },
4692
+ "extra": {
4693
+ "type": "object",
4694
+ "description": "The token's load-bearing EIP-712 domain params. `name` differs by\nchain (Base mainnet USDC is `USD Coin`, Base Sepolia is `USDC`); a\nwrong value produces a signature the verifier rejects.\n",
4695
+ "properties": {
4696
+ "name": { "type": "string" },
4697
+ "version": { "type": "string" }
4698
+ },
4699
+ "required": ["name", "version"]
4700
+ }
4701
+ },
4702
+ "required": [
4703
+ "scheme",
4704
+ "network",
4705
+ "maxAmountRequired",
4706
+ "payTo",
4707
+ "asset",
4708
+ "extra"
4709
+ ]
4710
+ },
4711
+ "X402Challenge": {
4712
+ "type": "object",
4713
+ "properties": {
4714
+ "id": {
4715
+ "type": "string",
4716
+ "format": "uuid"
4717
+ },
4718
+ "status": {
4719
+ "type": "string",
4720
+ "enum": [
4721
+ "pending",
4722
+ "settling",
4723
+ "settled",
4724
+ "failed",
4725
+ "expired"
4726
+ ]
4727
+ },
4728
+ "network": {
4729
+ "type": "string",
4730
+ "enum": ["base", "base-sepolia"]
4731
+ },
4732
+ "asset": {
4733
+ "type": "string",
4734
+ "description": "Token contract address (checksummed)."
4735
+ },
4736
+ "amount": {
4737
+ "type": "string",
4738
+ "description": "Amount in token base units."
4739
+ },
4740
+ "pay_to": {
4741
+ "type": "string",
4742
+ "description": "The payee's resolved payout address (checksummed)."
4743
+ },
4744
+ "payer_org": {
4745
+ "type": ["string", "null"],
4746
+ "description": "The org id bound as payer, if one was set at creation."
4747
+ },
4748
+ "resource": { "type": ["string", "null"] },
4749
+ "description": { "type": ["string", "null"] },
4750
+ "nonce_binding": { "$ref": "#/components/schemas/X402NonceBinding" },
4751
+ "settle_tx": {
4752
+ "type": ["string", "null"],
4753
+ "description": "On-chain settlement transaction hash once settled."
4754
+ },
4755
+ "settled_at": {
4756
+ "type": ["string", "null"],
4757
+ "format": "date-time"
4758
+ },
4759
+ "failure_reason": { "type": ["string", "null"] },
4760
+ "expires_at": {
4761
+ "type": "string",
4762
+ "format": "date-time"
4763
+ },
4764
+ "created_at": {
4765
+ "type": "string",
4766
+ "format": "date-time"
4767
+ },
4768
+ "payment_requirements": {
4769
+ "description": "Present on the create response. Hand the whole challenge (including\nthis) to the payer; `getChallenge` omits it (it is for status polling\nby the challenger).\n",
4770
+ "allOf": [{ "$ref": "#/components/schemas/X402PaymentRequirements" }]
4771
+ }
4772
+ },
4773
+ "required": [
4774
+ "id",
4775
+ "status",
4776
+ "network",
4777
+ "asset",
4778
+ "amount",
4779
+ "pay_to",
4780
+ "nonce_binding",
4781
+ "expires_at"
4782
+ ]
4783
+ },
4784
+ "X402PaymentPayload": {
4785
+ "type": "object",
4786
+ "description": "A signed x402 v1 `PaymentPayload`. The SDK `pay()` helper builds this;\ncallers rarely construct it by hand. Field names are x402-native.\n",
4787
+ "properties": {
4788
+ "x402Version": {
4789
+ "type": "integer",
4790
+ "const": 1
4791
+ },
4792
+ "scheme": {
4793
+ "type": "string",
4794
+ "const": "exact"
4795
+ },
4796
+ "network": {
4797
+ "type": "string",
4798
+ "enum": ["base", "base-sepolia"]
4799
+ },
4800
+ "payload": {
4801
+ "type": "object",
4802
+ "properties": {
4803
+ "signature": {
4804
+ "type": "string",
4805
+ "pattern": "^0x[0-9a-fA-F]+$",
4806
+ "description": "The EIP-712 signature over the authorization."
4807
+ },
4808
+ "authorization": {
4809
+ "type": "object",
4810
+ "description": "The EIP-3009 `transferWithAuthorization` fields, as strings.",
4811
+ "properties": {
4812
+ "from": { "type": "string" },
4813
+ "to": { "type": "string" },
4814
+ "value": { "type": "string" },
4815
+ "validAfter": { "type": "string" },
4816
+ "validBefore": { "type": "string" },
4817
+ "nonce": { "type": "string" }
4818
+ },
4819
+ "required": [
4820
+ "from",
4821
+ "to",
4822
+ "value",
4823
+ "validAfter",
4824
+ "validBefore",
4825
+ "nonce"
4826
+ ]
4827
+ }
4828
+ },
4829
+ "required": ["signature", "authorization"]
4830
+ }
4831
+ },
4832
+ "required": [
4833
+ "x402Version",
4834
+ "scheme",
4835
+ "network",
4836
+ "payload"
4837
+ ]
4838
+ },
4839
+ "PayChallengeInput": {
4840
+ "type": "object",
4841
+ "additionalProperties": false,
4842
+ "properties": { "payment": { "$ref": "#/components/schemas/X402PaymentPayload" } },
4843
+ "required": ["payment"]
4844
+ },
4845
+ "X402Receipt": {
4846
+ "type": "object",
4847
+ "properties": {
4848
+ "id": {
4849
+ "type": "string",
4850
+ "format": "uuid"
4851
+ },
4852
+ "status": {
4853
+ "type": "string",
4854
+ "enum": ["settled"]
4855
+ },
4856
+ "settle_tx": {
4857
+ "type": ["string", "null"],
4858
+ "description": "On-chain settlement transaction hash."
4859
+ }
4860
+ },
4861
+ "required": [
4862
+ "id",
4863
+ "status",
4864
+ "settle_tx"
4865
+ ]
4866
+ },
4867
+ "X402SpendPolicy": {
4868
+ "type": "object",
4869
+ "description": "The payer's outbound spend policy. Returned with defaults (not paused,\nno caps, any on-net payee) when none is set.\n",
4870
+ "properties": {
4871
+ "paused": {
4872
+ "type": "boolean",
4873
+ "description": "Kill-switch. When true, all outbound payments are refused."
4874
+ },
4875
+ "max_per_payment": {
4876
+ "type": ["string", "null"],
4877
+ "description": "Per-payment cap in token base units, or null for no cap."
4878
+ },
4879
+ "max_per_day": {
4880
+ "type": ["string", "null"],
4881
+ "description": "Rolling-day cap in token base units, or null for no cap."
4882
+ },
4883
+ "allowlist": {
4884
+ "type": ["array", "null"],
4885
+ "items": {
4886
+ "type": "string",
4887
+ "format": "uuid"
4888
+ },
4889
+ "description": "Allowed payee org ids. `null` allows any on-net payee; `[]` denies\nall.\n"
4890
+ }
4891
+ },
4892
+ "required": [
4893
+ "paused",
4894
+ "max_per_payment",
4895
+ "max_per_day",
4896
+ "allowlist"
4897
+ ]
4898
+ },
4899
+ "UpdateSpendPolicyInput": {
4900
+ "type": "object",
4901
+ "additionalProperties": false,
4902
+ "description": "Merge update: only the fields you include change; omit a field to keep\nits current value; send `null` to clear a cap.\n",
4903
+ "properties": {
4904
+ "paused": { "type": "boolean" },
4905
+ "max_per_payment": {
4906
+ "type": ["string", "null"],
4907
+ "pattern": "^[1-9][0-9]{0,38}$"
4908
+ },
4909
+ "max_per_day": {
4910
+ "type": ["string", "null"],
4911
+ "pattern": "^[1-9][0-9]{0,38}$"
4912
+ },
4913
+ "allowlist": {
4914
+ "type": ["array", "null"],
4915
+ "maxItems": 1e3,
4916
+ "items": {
4917
+ "type": "string",
4918
+ "format": "uuid"
4919
+ }
4920
+ }
4921
+ }
4922
+ },
4923
+ "X402DeclinedPayment": {
4924
+ "type": "object",
4925
+ "description": "A payment the org's spend policy refused.",
4926
+ "properties": {
4927
+ "id": {
4928
+ "type": "string",
4929
+ "format": "uuid"
4930
+ },
4931
+ "challenge_id": {
4932
+ "type": ["string", "null"],
4933
+ "format": "uuid",
4934
+ "description": "The challenge that was declined, if still present."
4935
+ },
4936
+ "counterparty_org": {
4937
+ "type": ["string", "null"],
4938
+ "format": "uuid",
4939
+ "description": "The payee (challenger) org, when known."
4940
+ },
4941
+ "network": {
4942
+ "type": "string",
4943
+ "enum": ["base", "base-sepolia"]
4944
+ },
4945
+ "amount": {
4946
+ "type": "string",
4947
+ "description": "Amount in token base units."
4948
+ },
4949
+ "reason": {
4950
+ "type": "string",
4951
+ "description": "Why the payment was declined (cap, allowlist, paused)."
4952
+ },
4953
+ "declined_at": {
4954
+ "type": "string",
4955
+ "format": "date-time"
4956
+ }
4957
+ },
4958
+ "required": [
4959
+ "id",
4960
+ "network",
4961
+ "amount",
4962
+ "reason",
4963
+ "declined_at"
4964
+ ]
4965
+ },
4966
+ "SuccessEnvelope": {
4967
+ "type": "object",
4968
+ "properties": { "success": {
4969
+ "type": "boolean",
4970
+ "const": true
4971
+ } },
4972
+ "required": ["success", "data"]
4973
+ },
4974
+ "ListEnvelope": {
4975
+ "type": "object",
4976
+ "properties": {
4977
+ "success": {
4978
+ "type": "boolean",
4979
+ "const": true
4980
+ },
4981
+ "meta": { "$ref": "#/components/schemas/PaginationMeta" }
4982
+ },
4983
+ "required": [
4984
+ "success",
4985
+ "data",
4986
+ "meta"
4987
+ ]
4988
+ },
4989
+ "PaginationMeta": {
4990
+ "type": "object",
4991
+ "properties": {
4992
+ "total": {
4993
+ "type": "integer",
4994
+ "description": "Total number of matching records"
4995
+ },
4996
+ "limit": {
4997
+ "type": "integer",
4998
+ "description": "Page size used for this request"
4999
+ },
5000
+ "cursor": {
5001
+ "type": ["string", "null"],
5002
+ "description": "Cursor for the next page, or null if no more results"
5003
+ }
5004
+ },
5005
+ "required": [
5006
+ "total",
5007
+ "limit",
5008
+ "cursor"
5009
+ ]
5010
+ },
5011
+ "ErrorResponse": {
5012
+ "type": "object",
5013
+ "properties": {
5014
+ "success": {
5015
+ "type": "boolean",
5016
+ "const": false
5017
+ },
5018
+ "error": {
5019
+ "type": "object",
4001
5020
  "properties": {
4002
5021
  "code": {
4003
5022
  "type": "string",
@@ -4033,7 +5052,14 @@ const openapiDocument = {
4033
5052
  "email_delivery_failed",
4034
5053
  "clerk_signup_failed",
4035
5054
  "no_orgs_for_user",
4036
- "org_not_accessible"
5055
+ "org_not_accessible",
5056
+ "feature_disabled",
5057
+ "no_payout_address",
5058
+ "ownership_proof_failed",
5059
+ "payment_verification_failed",
5060
+ "payment_declined",
5061
+ "challenge_expired",
5062
+ "settlement_failed"
4037
5063
  ]
4038
5064
  },
4039
5065
  "message": { "type": "string" },
@@ -7920,31 +8946,106 @@ const openapiDocument = {
7920
8946
  "updated_at",
7921
8947
  "created"
7922
8948
  ]
7923
- }
7924
- }
7925
- }
7926
- };
7927
- //#endregion
7928
- //#region ../packages/api-core/src/openapi/operations.generated.ts
7929
- const operationManifest = [
7930
- {
7931
- "binaryResponse": false,
7932
- "bodyRequired": false,
7933
- "command": "get-account",
7934
- "description": null,
7935
- "hasJsonBody": false,
7936
- "method": "GET",
7937
- "operationId": "getAccount",
7938
- "path": "/account",
7939
- "pathParams": [],
7940
- "queryParams": [],
7941
- "requestSchema": null,
7942
- "responseSchema": {
7943
- "type": "object",
7944
- "properties": {
7945
- "id": {
7946
- "type": "string",
7947
- "format": "uuid"
8949
+ },
8950
+ "OrgSecretListItem": {
8951
+ "type": "object",
8952
+ "description": "One row from GET /org/secrets. Org secrets are always user-set\n(there are no managed org secrets), so `created_at` /\n`updated_at` are always present.\n",
8953
+ "properties": {
8954
+ "key": { "type": "string" },
8955
+ "created_at": {
8956
+ "type": "string",
8957
+ "format": "date-time"
8958
+ },
8959
+ "updated_at": {
8960
+ "type": "string",
8961
+ "format": "date-time"
8962
+ }
8963
+ },
8964
+ "required": [
8965
+ "key",
8966
+ "created_at",
8967
+ "updated_at"
8968
+ ]
8969
+ },
8970
+ "CreateOrgSecretInput": {
8971
+ "type": "object",
8972
+ "additionalProperties": false,
8973
+ "description": "Body for POST /org/secrets.",
8974
+ "properties": {
8975
+ "key": {
8976
+ "type": "string",
8977
+ "pattern": "^[A-Z_][A-Z0-9_]*$",
8978
+ "description": "Uppercase letters, digits, and underscores. Must start with\na letter or underscore. System-managed keys are reserved.\n"
8979
+ },
8980
+ "value": {
8981
+ "type": "string",
8982
+ "minLength": 1,
8983
+ "maxLength": 4096,
8984
+ "description": "Secret value, up to 4096 UTF-8 bytes. Encrypted at rest.\nNever returned by any read endpoint.\n"
8985
+ }
8986
+ },
8987
+ "required": ["key", "value"]
8988
+ },
8989
+ "SetOrgSecretInput": {
8990
+ "type": "object",
8991
+ "additionalProperties": false,
8992
+ "description": "Body for PUT /org/secrets/{key}. Key comes from the path.",
8993
+ "properties": { "value": {
8994
+ "type": "string",
8995
+ "minLength": 1,
8996
+ "maxLength": 4096
8997
+ } },
8998
+ "required": ["value"]
8999
+ },
9000
+ "OrgSecretWriteResult": {
9001
+ "type": "object",
9002
+ "description": "Returned by POST and PUT org secret routes.",
9003
+ "properties": {
9004
+ "key": { "type": "string" },
9005
+ "created_at": {
9006
+ "type": "string",
9007
+ "format": "date-time"
9008
+ },
9009
+ "updated_at": {
9010
+ "type": "string",
9011
+ "format": "date-time"
9012
+ },
9013
+ "created": {
9014
+ "type": "boolean",
9015
+ "description": "True if this call inserted a new row, false if it updated an existing one."
9016
+ }
9017
+ },
9018
+ "required": [
9019
+ "key",
9020
+ "created_at",
9021
+ "updated_at",
9022
+ "created"
9023
+ ]
9024
+ }
9025
+ }
9026
+ }
9027
+ };
9028
+ //#endregion
9029
+ //#region ../packages/api-core/src/openapi/operations.generated.ts
9030
+ const operationManifest = [
9031
+ {
9032
+ "binaryResponse": false,
9033
+ "bodyRequired": false,
9034
+ "command": "get-account",
9035
+ "description": null,
9036
+ "hasJsonBody": false,
9037
+ "method": "GET",
9038
+ "operationId": "getAccount",
9039
+ "path": "/account",
9040
+ "pathParams": [],
9041
+ "queryParams": [],
9042
+ "requestSchema": null,
9043
+ "responseSchema": {
9044
+ "type": "object",
9045
+ "properties": {
9046
+ "id": {
9047
+ "type": "string",
9048
+ "format": "uuid"
7948
9049
  },
7949
9050
  "email": { "type": "string" },
7950
9051
  "plan": { "type": "string" },
@@ -11624,6 +12725,66 @@ const operationManifest = [
11624
12725
  "tag": "Functions",
11625
12726
  "tagCommand": "functions"
11626
12727
  },
12728
+ {
12729
+ "binaryResponse": false,
12730
+ "bodyRequired": true,
12731
+ "command": "create-org-secret",
12732
+ "description": "Idempotent insert-or-update keyed on `(org_id, key)`. Returns\n201 the first time the key is set, 200 on subsequent updates.\nValues are encrypted at rest. A changed value lands in a\nfunction only on that function's next deploy.\n\nKeys must match `^[A-Z_][A-Z0-9_]*$` (uppercase letters,\ndigits, underscores; first character is a letter or\nunderscore). Values are at most 4096 UTF-8 bytes. System-\nmanaged keys are reserved and rejected.\n",
12733
+ "hasJsonBody": true,
12734
+ "method": "POST",
12735
+ "operationId": "createOrgSecret",
12736
+ "path": "/org/secrets",
12737
+ "pathParams": [],
12738
+ "queryParams": [],
12739
+ "requestSchema": {
12740
+ "type": "object",
12741
+ "additionalProperties": false,
12742
+ "description": "Body for POST /org/secrets.",
12743
+ "properties": {
12744
+ "key": {
12745
+ "type": "string",
12746
+ "pattern": "^[A-Z_][A-Z0-9_]*$",
12747
+ "description": "Uppercase letters, digits, and underscores. Must start with\na letter or underscore. System-managed keys are reserved.\n"
12748
+ },
12749
+ "value": {
12750
+ "type": "string",
12751
+ "minLength": 1,
12752
+ "maxLength": 4096,
12753
+ "description": "Secret value, up to 4096 UTF-8 bytes. Encrypted at rest.\nNever returned by any read endpoint.\n"
12754
+ }
12755
+ },
12756
+ "required": ["key", "value"]
12757
+ },
12758
+ "responseSchema": {
12759
+ "type": "object",
12760
+ "description": "Returned by POST and PUT org secret routes.",
12761
+ "properties": {
12762
+ "key": { "type": "string" },
12763
+ "created_at": {
12764
+ "type": "string",
12765
+ "format": "date-time"
12766
+ },
12767
+ "updated_at": {
12768
+ "type": "string",
12769
+ "format": "date-time"
12770
+ },
12771
+ "created": {
12772
+ "type": "boolean",
12773
+ "description": "True if this call inserted a new row, false if it updated an existing one."
12774
+ }
12775
+ },
12776
+ "required": [
12777
+ "key",
12778
+ "created_at",
12779
+ "updated_at",
12780
+ "created"
12781
+ ]
12782
+ },
12783
+ "sdkName": "createOrgSecret",
12784
+ "summary": "Create or update an org secret",
12785
+ "tag": "Functions",
12786
+ "tagCommand": "functions"
12787
+ },
11627
12788
  {
11628
12789
  "binaryResponse": false,
11629
12790
  "bodyRequired": false,
@@ -11678,6 +12839,30 @@ const operationManifest = [
11678
12839
  "tag": "Functions",
11679
12840
  "tagCommand": "functions"
11680
12841
  },
12842
+ {
12843
+ "binaryResponse": false,
12844
+ "bodyRequired": false,
12845
+ "command": "delete-org-secret",
12846
+ "description": "Removes the org secret. Functions keep the previous value until\neach is redeployed. Returns 404 if the key did not exist.\n",
12847
+ "hasJsonBody": false,
12848
+ "method": "DELETE",
12849
+ "operationId": "deleteOrgSecret",
12850
+ "path": "/org/secrets/{key}",
12851
+ "pathParams": [{
12852
+ "description": "Secret key. Must match `^[A-Z_][A-Z0-9_]*$`.",
12853
+ "enum": null,
12854
+ "name": "key",
12855
+ "required": true,
12856
+ "type": "string"
12857
+ }],
12858
+ "queryParams": [],
12859
+ "requestSchema": null,
12860
+ "responseSchema": null,
12861
+ "sdkName": "deleteOrgSecret",
12862
+ "summary": "Delete an org secret",
12863
+ "tag": "Functions",
12864
+ "tagCommand": "functions"
12865
+ },
11681
12866
  {
11682
12867
  "binaryResponse": false,
11683
12868
  "bodyRequired": false,
@@ -12558,6 +13743,50 @@ const operationManifest = [
12558
13743
  "tag": "Functions",
12559
13744
  "tagCommand": "functions"
12560
13745
  },
13746
+ {
13747
+ "binaryResponse": false,
13748
+ "bodyRequired": false,
13749
+ "command": "list-org-secrets",
13750
+ "description": "Returns metadata for every org-level secret. Org secrets apply\nto every function in the org and are read as `env.<KEY>` in\nhandlers. **Values are never returned.** Secret writes are\nwrite-only. A function-level secret of the same name overrides\nthe org-level value for that function.\n",
13751
+ "hasJsonBody": false,
13752
+ "method": "GET",
13753
+ "operationId": "listOrgSecrets",
13754
+ "path": "/org/secrets",
13755
+ "pathParams": [],
13756
+ "queryParams": [],
13757
+ "requestSchema": null,
13758
+ "responseSchema": {
13759
+ "type": "object",
13760
+ "properties": { "items": {
13761
+ "type": "array",
13762
+ "items": {
13763
+ "type": "object",
13764
+ "description": "One row from GET /org/secrets. Org secrets are always user-set\n(there are no managed org secrets), so `created_at` /\n`updated_at` are always present.\n",
13765
+ "properties": {
13766
+ "key": { "type": "string" },
13767
+ "created_at": {
13768
+ "type": "string",
13769
+ "format": "date-time"
13770
+ },
13771
+ "updated_at": {
13772
+ "type": "string",
13773
+ "format": "date-time"
13774
+ }
13775
+ },
13776
+ "required": [
13777
+ "key",
13778
+ "created_at",
13779
+ "updated_at"
13780
+ ]
13781
+ }
13782
+ } },
13783
+ "required": ["items"]
13784
+ },
13785
+ "sdkName": "listOrgSecrets",
13786
+ "summary": "List org-level (global) secrets",
13787
+ "tag": "Functions",
13788
+ "tagCommand": "functions"
13789
+ },
12561
13790
  {
12562
13791
  "binaryResponse": false,
12563
13792
  "bodyRequired": true,
@@ -12746,6 +13975,64 @@ const operationManifest = [
12746
13975
  "tag": "Functions",
12747
13976
  "tagCommand": "functions"
12748
13977
  },
13978
+ {
13979
+ "binaryResponse": false,
13980
+ "bodyRequired": true,
13981
+ "command": "set-org-secret",
13982
+ "description": "Path-keyed companion to `POST /org/secrets`. Idempotent:\nreturns 201 the first time the key is set, 200 on subsequent\nupdates. Same validation and write-only guarantees as POST.\n",
13983
+ "hasJsonBody": true,
13984
+ "method": "PUT",
13985
+ "operationId": "setOrgSecret",
13986
+ "path": "/org/secrets/{key}",
13987
+ "pathParams": [{
13988
+ "description": "Secret key. Must match `^[A-Z_][A-Z0-9_]*$`.",
13989
+ "enum": null,
13990
+ "name": "key",
13991
+ "required": true,
13992
+ "type": "string"
13993
+ }],
13994
+ "queryParams": [],
13995
+ "requestSchema": {
13996
+ "type": "object",
13997
+ "additionalProperties": false,
13998
+ "description": "Body for PUT /org/secrets/{key}. Key comes from the path.",
13999
+ "properties": { "value": {
14000
+ "type": "string",
14001
+ "minLength": 1,
14002
+ "maxLength": 4096
14003
+ } },
14004
+ "required": ["value"]
14005
+ },
14006
+ "responseSchema": {
14007
+ "type": "object",
14008
+ "description": "Returned by POST and PUT org secret routes.",
14009
+ "properties": {
14010
+ "key": { "type": "string" },
14011
+ "created_at": {
14012
+ "type": "string",
14013
+ "format": "date-time"
14014
+ },
14015
+ "updated_at": {
14016
+ "type": "string",
14017
+ "format": "date-time"
14018
+ },
14019
+ "created": {
14020
+ "type": "boolean",
14021
+ "description": "True if this call inserted a new row, false if it updated an existing one."
14022
+ }
14023
+ },
14024
+ "required": [
14025
+ "key",
14026
+ "created_at",
14027
+ "updated_at",
14028
+ "created"
14029
+ ]
14030
+ },
14031
+ "sdkName": "setOrgSecret",
14032
+ "summary": "Set an org secret by key",
14033
+ "tag": "Functions",
14034
+ "tagCommand": "functions"
14035
+ },
12749
14036
  {
12750
14037
  "binaryResponse": false,
12751
14038
  "bodyRequired": false,
@@ -13073,78 +14360,878 @@ const operationManifest = [
13073
14360
  ]
13074
14361
  }
13075
14362
  },
13076
- "endpoints": {
13077
- "type": "object",
13078
- "additionalProperties": false,
13079
- "properties": {
13080
- "total": { "type": "integer" },
13081
- "enabled": { "type": "integer" },
13082
- "disabled": { "type": "integer" },
13083
- "fallback_enabled": { "type": "integer" },
13084
- "domain_scoped_enabled": { "type": "integer" },
13085
- "http_enabled": { "type": "integer" },
13086
- "function_enabled": { "type": "integer" }
13087
- },
13088
- "required": [
13089
- "total",
13090
- "enabled",
13091
- "disabled",
13092
- "fallback_enabled",
13093
- "domain_scoped_enabled",
13094
- "http_enabled",
13095
- "function_enabled"
13096
- ]
14363
+ "endpoints": {
14364
+ "type": "object",
14365
+ "additionalProperties": false,
14366
+ "properties": {
14367
+ "total": { "type": "integer" },
14368
+ "enabled": { "type": "integer" },
14369
+ "disabled": { "type": "integer" },
14370
+ "fallback_enabled": { "type": "integer" },
14371
+ "domain_scoped_enabled": { "type": "integer" },
14372
+ "http_enabled": { "type": "integer" },
14373
+ "function_enabled": { "type": "integer" }
14374
+ },
14375
+ "required": [
14376
+ "total",
14377
+ "enabled",
14378
+ "disabled",
14379
+ "fallback_enabled",
14380
+ "domain_scoped_enabled",
14381
+ "http_enabled",
14382
+ "function_enabled"
14383
+ ]
14384
+ },
14385
+ "functions": {
14386
+ "type": "object",
14387
+ "additionalProperties": false,
14388
+ "properties": {
14389
+ "total": { "type": "integer" },
14390
+ "deployed": { "type": "integer" },
14391
+ "pending": { "type": "integer" },
14392
+ "failed": { "type": "integer" }
14393
+ },
14394
+ "required": [
14395
+ "total",
14396
+ "deployed",
14397
+ "pending",
14398
+ "failed"
14399
+ ]
14400
+ },
14401
+ "recent_emails": {
14402
+ "type": "object",
14403
+ "description": "Inbound email activity from the last 30 days.",
14404
+ "additionalProperties": false,
14405
+ "properties": {
14406
+ "total": {
14407
+ "type": "integer",
14408
+ "description": "Number of inbound emails received in the last 30 days."
14409
+ },
14410
+ "latest_received_at": {
14411
+ "type": ["string", "null"],
14412
+ "format": "date-time",
14413
+ "description": "Most recent inbound email received in the last 30 days."
14414
+ }
14415
+ },
14416
+ "required": ["total", "latest_received_at"]
14417
+ }
14418
+ },
14419
+ "required": [
14420
+ "ready",
14421
+ "receiving_ready",
14422
+ "processing_ready",
14423
+ "summary",
14424
+ "next_actions",
14425
+ "domains",
14426
+ "endpoints",
14427
+ "functions",
14428
+ "recent_emails"
14429
+ ]
14430
+ },
14431
+ "sdkName": "getInboxStatus",
14432
+ "summary": "Get inbound inbox readiness",
14433
+ "tag": "Inbox",
14434
+ "tagCommand": "inbox"
14435
+ },
14436
+ {
14437
+ "binaryResponse": false,
14438
+ "bodyRequired": true,
14439
+ "command": "create-challenge",
14440
+ "description": "Create an x402 payment challenge (the payee side of a payment). The\n`pay_to` address is resolved server-side from your registered default\npayout address for the network, never from the request. The response\ncarries the `nonce_binding` and `payment_requirements` the payer needs to\nsign; hand the whole challenge object to the payer (for example in an\nemail reply). Amounts are in token base units (USDC has 6 decimals, so\n`\"10000\"` is 0.01 USDC).\n",
14441
+ "hasJsonBody": true,
14442
+ "method": "POST",
14443
+ "operationId": "createChallenge",
14444
+ "path": "/x402/challenges",
14445
+ "pathParams": [],
14446
+ "queryParams": [],
14447
+ "requestSchema": {
14448
+ "type": "object",
14449
+ "additionalProperties": false,
14450
+ "properties": {
14451
+ "amount": {
14452
+ "type": "string",
14453
+ "pattern": "^[1-9][0-9]{0,38}$",
14454
+ "description": "Amount to collect, in token base units. USDC has 6 decimals, so\n`\"10000\"` is 0.01 USDC.\n"
14455
+ },
14456
+ "network": {
14457
+ "type": "string",
14458
+ "enum": ["base", "base-sepolia"]
14459
+ },
14460
+ "payer_org": {
14461
+ "type": "string",
14462
+ "format": "uuid",
14463
+ "description": "The org id allowed to pay this challenge (on-net binding). Optional.\n"
14464
+ },
14465
+ "expires_in": {
14466
+ "type": "integer",
14467
+ "minimum": 60,
14468
+ "maximum": 86400,
14469
+ "description": "Seconds until the challenge expires. Defaults to 3600."
14470
+ },
14471
+ "resource": {
14472
+ "type": "string",
14473
+ "format": "uri",
14474
+ "maxLength": 2048,
14475
+ "description": "Optional URL identifying what is being paid for. Defaults to a\nsynthetic `x402:challenge:<id>` identifier.\n"
14476
+ },
14477
+ "description": {
14478
+ "type": "string",
14479
+ "maxLength": 512,
14480
+ "description": "Optional human-readable description of the payment."
14481
+ }
14482
+ },
14483
+ "required": ["amount", "network"]
14484
+ },
14485
+ "responseSchema": {
14486
+ "type": "object",
14487
+ "properties": {
14488
+ "id": {
14489
+ "type": "string",
14490
+ "format": "uuid"
14491
+ },
14492
+ "status": {
14493
+ "type": "string",
14494
+ "enum": [
14495
+ "pending",
14496
+ "settling",
14497
+ "settled",
14498
+ "failed",
14499
+ "expired"
14500
+ ]
14501
+ },
14502
+ "network": {
14503
+ "type": "string",
14504
+ "enum": ["base", "base-sepolia"]
14505
+ },
14506
+ "asset": {
14507
+ "type": "string",
14508
+ "description": "Token contract address (checksummed)."
14509
+ },
14510
+ "amount": {
14511
+ "type": "string",
14512
+ "description": "Amount in token base units."
14513
+ },
14514
+ "pay_to": {
14515
+ "type": "string",
14516
+ "description": "The payee's resolved payout address (checksummed)."
14517
+ },
14518
+ "payer_org": {
14519
+ "type": ["string", "null"],
14520
+ "description": "The org id bound as payer, if one was set at creation."
14521
+ },
14522
+ "resource": { "type": ["string", "null"] },
14523
+ "description": { "type": ["string", "null"] },
14524
+ "nonce_binding": {
14525
+ "type": "object",
14526
+ "description": "The interaction binding the payer hashes into the EIP-3009 nonce\n(`deriveEip3009Nonce`). Pinning the nonce to this binding is what lets an\nx402 payment ride asynchronous transports safely: a replayed challenge\ncan't redirect funds and a signed payment can't settle twice.\n",
14527
+ "properties": {
14528
+ "interaction_id": {
14529
+ "type": "string",
14530
+ "description": "Interaction id, including its `@domain` part."
14531
+ },
14532
+ "challenge_step_id": {
14533
+ "type": "string",
14534
+ "format": "uuid"
14535
+ },
14536
+ "challenge_nonce": {
14537
+ "type": "string",
14538
+ "pattern": "^[0-9a-f]{64}$",
14539
+ "description": "32 random bytes as 64 lowercase hex chars."
14540
+ }
14541
+ },
14542
+ "required": [
14543
+ "interaction_id",
14544
+ "challenge_step_id",
14545
+ "challenge_nonce"
14546
+ ]
14547
+ },
14548
+ "settle_tx": {
14549
+ "type": ["string", "null"],
14550
+ "description": "On-chain settlement transaction hash once settled."
14551
+ },
14552
+ "settled_at": {
14553
+ "type": ["string", "null"],
14554
+ "format": "date-time"
14555
+ },
14556
+ "failure_reason": { "type": ["string", "null"] },
14557
+ "expires_at": {
14558
+ "type": "string",
14559
+ "format": "date-time"
14560
+ },
14561
+ "created_at": {
14562
+ "type": "string",
14563
+ "format": "date-time"
14564
+ },
14565
+ "payment_requirements": {
14566
+ "description": "Present on the create response. Hand the whole challenge (including\nthis) to the payer; `getChallenge` omits it (it is for status polling\nby the challenger).\n",
14567
+ "allOf": [{
14568
+ "type": "object",
14569
+ "description": "The x402 `PaymentRequirements` the payer signs over. Field names are\nx402's native camelCase, preserved byte-for-byte.\n",
14570
+ "properties": {
14571
+ "scheme": {
14572
+ "type": "string",
14573
+ "description": "The x402 settlement scheme. Always `exact` for v1.",
14574
+ "example": "exact"
14575
+ },
14576
+ "network": {
14577
+ "type": "string",
14578
+ "enum": ["base", "base-sepolia"]
14579
+ },
14580
+ "maxAmountRequired": {
14581
+ "type": "string",
14582
+ "description": "Amount in token base units."
14583
+ },
14584
+ "payTo": {
14585
+ "type": "string",
14586
+ "description": "The payee's resolved payout address (checksummed)."
14587
+ },
14588
+ "asset": {
14589
+ "type": "string",
14590
+ "description": "The token contract address (checksummed). USDC."
14591
+ },
14592
+ "resource": { "type": "string" },
14593
+ "description": { "type": "string" },
14594
+ "maxTimeoutSeconds": { "type": "integer" },
14595
+ "extra": {
14596
+ "type": "object",
14597
+ "description": "The token's load-bearing EIP-712 domain params. `name` differs by\nchain (Base mainnet USDC is `USD Coin`, Base Sepolia is `USDC`); a\nwrong value produces a signature the verifier rejects.\n",
14598
+ "properties": {
14599
+ "name": { "type": "string" },
14600
+ "version": { "type": "string" }
14601
+ },
14602
+ "required": ["name", "version"]
14603
+ }
14604
+ },
14605
+ "required": [
14606
+ "scheme",
14607
+ "network",
14608
+ "maxAmountRequired",
14609
+ "payTo",
14610
+ "asset",
14611
+ "extra"
14612
+ ]
14613
+ }]
14614
+ }
14615
+ },
14616
+ "required": [
14617
+ "id",
14618
+ "status",
14619
+ "network",
14620
+ "asset",
14621
+ "amount",
14622
+ "pay_to",
14623
+ "nonce_binding",
14624
+ "expires_at"
14625
+ ]
14626
+ },
14627
+ "sdkName": "createChallenge",
14628
+ "summary": "Create a payment challenge",
14629
+ "tag": "Payments",
14630
+ "tagCommand": "payments"
14631
+ },
14632
+ {
14633
+ "binaryResponse": false,
14634
+ "bodyRequired": false,
14635
+ "command": "get-challenge",
14636
+ "description": "Fetch a challenge you created, to poll its `status` and settlement\nreceipt (`settle_tx`). Scoped to the challenger org that created it.\n",
14637
+ "hasJsonBody": false,
14638
+ "method": "GET",
14639
+ "operationId": "getChallenge",
14640
+ "path": "/x402/challenges/{id}",
14641
+ "pathParams": [{
14642
+ "description": "Resource UUID",
14643
+ "enum": null,
14644
+ "name": "id",
14645
+ "required": true,
14646
+ "type": "string"
14647
+ }],
14648
+ "queryParams": [],
14649
+ "requestSchema": null,
14650
+ "responseSchema": {
14651
+ "type": "object",
14652
+ "properties": {
14653
+ "id": {
14654
+ "type": "string",
14655
+ "format": "uuid"
14656
+ },
14657
+ "status": {
14658
+ "type": "string",
14659
+ "enum": [
14660
+ "pending",
14661
+ "settling",
14662
+ "settled",
14663
+ "failed",
14664
+ "expired"
14665
+ ]
14666
+ },
14667
+ "network": {
14668
+ "type": "string",
14669
+ "enum": ["base", "base-sepolia"]
14670
+ },
14671
+ "asset": {
14672
+ "type": "string",
14673
+ "description": "Token contract address (checksummed)."
14674
+ },
14675
+ "amount": {
14676
+ "type": "string",
14677
+ "description": "Amount in token base units."
14678
+ },
14679
+ "pay_to": {
14680
+ "type": "string",
14681
+ "description": "The payee's resolved payout address (checksummed)."
14682
+ },
14683
+ "payer_org": {
14684
+ "type": ["string", "null"],
14685
+ "description": "The org id bound as payer, if one was set at creation."
14686
+ },
14687
+ "resource": { "type": ["string", "null"] },
14688
+ "description": { "type": ["string", "null"] },
14689
+ "nonce_binding": {
14690
+ "type": "object",
14691
+ "description": "The interaction binding the payer hashes into the EIP-3009 nonce\n(`deriveEip3009Nonce`). Pinning the nonce to this binding is what lets an\nx402 payment ride asynchronous transports safely: a replayed challenge\ncan't redirect funds and a signed payment can't settle twice.\n",
14692
+ "properties": {
14693
+ "interaction_id": {
14694
+ "type": "string",
14695
+ "description": "Interaction id, including its `@domain` part."
14696
+ },
14697
+ "challenge_step_id": {
14698
+ "type": "string",
14699
+ "format": "uuid"
14700
+ },
14701
+ "challenge_nonce": {
14702
+ "type": "string",
14703
+ "pattern": "^[0-9a-f]{64}$",
14704
+ "description": "32 random bytes as 64 lowercase hex chars."
14705
+ }
14706
+ },
14707
+ "required": [
14708
+ "interaction_id",
14709
+ "challenge_step_id",
14710
+ "challenge_nonce"
14711
+ ]
14712
+ },
14713
+ "settle_tx": {
14714
+ "type": ["string", "null"],
14715
+ "description": "On-chain settlement transaction hash once settled."
14716
+ },
14717
+ "settled_at": {
14718
+ "type": ["string", "null"],
14719
+ "format": "date-time"
14720
+ },
14721
+ "failure_reason": { "type": ["string", "null"] },
14722
+ "expires_at": {
14723
+ "type": "string",
14724
+ "format": "date-time"
14725
+ },
14726
+ "created_at": {
14727
+ "type": "string",
14728
+ "format": "date-time"
14729
+ },
14730
+ "payment_requirements": {
14731
+ "description": "Present on the create response. Hand the whole challenge (including\nthis) to the payer; `getChallenge` omits it (it is for status polling\nby the challenger).\n",
14732
+ "allOf": [{
14733
+ "type": "object",
14734
+ "description": "The x402 `PaymentRequirements` the payer signs over. Field names are\nx402's native camelCase, preserved byte-for-byte.\n",
14735
+ "properties": {
14736
+ "scheme": {
14737
+ "type": "string",
14738
+ "description": "The x402 settlement scheme. Always `exact` for v1.",
14739
+ "example": "exact"
14740
+ },
14741
+ "network": {
14742
+ "type": "string",
14743
+ "enum": ["base", "base-sepolia"]
14744
+ },
14745
+ "maxAmountRequired": {
14746
+ "type": "string",
14747
+ "description": "Amount in token base units."
14748
+ },
14749
+ "payTo": {
14750
+ "type": "string",
14751
+ "description": "The payee's resolved payout address (checksummed)."
14752
+ },
14753
+ "asset": {
14754
+ "type": "string",
14755
+ "description": "The token contract address (checksummed). USDC."
14756
+ },
14757
+ "resource": { "type": "string" },
14758
+ "description": { "type": "string" },
14759
+ "maxTimeoutSeconds": { "type": "integer" },
14760
+ "extra": {
14761
+ "type": "object",
14762
+ "description": "The token's load-bearing EIP-712 domain params. `name` differs by\nchain (Base mainnet USDC is `USD Coin`, Base Sepolia is `USDC`); a\nwrong value produces a signature the verifier rejects.\n",
14763
+ "properties": {
14764
+ "name": { "type": "string" },
14765
+ "version": { "type": "string" }
14766
+ },
14767
+ "required": ["name", "version"]
14768
+ }
14769
+ },
14770
+ "required": [
14771
+ "scheme",
14772
+ "network",
14773
+ "maxAmountRequired",
14774
+ "payTo",
14775
+ "asset",
14776
+ "extra"
14777
+ ]
14778
+ }]
14779
+ }
14780
+ },
14781
+ "required": [
14782
+ "id",
14783
+ "status",
14784
+ "network",
14785
+ "asset",
14786
+ "amount",
14787
+ "pay_to",
14788
+ "nonce_binding",
14789
+ "expires_at"
14790
+ ]
14791
+ },
14792
+ "sdkName": "getChallenge",
14793
+ "summary": "Get a payment challenge",
14794
+ "tag": "Payments",
14795
+ "tagCommand": "payments"
14796
+ },
14797
+ {
14798
+ "binaryResponse": false,
14799
+ "bodyRequired": false,
14800
+ "command": "get-spend-policy",
14801
+ "description": "Read your org's outbound spend policy: the kill-switch, per-payment and\nper-day caps, and the payee allowlist. Returns the defaults (no limits,\nnot paused) when no policy has been set.\n",
14802
+ "hasJsonBody": false,
14803
+ "method": "GET",
14804
+ "operationId": "getSpendPolicy",
14805
+ "path": "/x402/spend-policy",
14806
+ "pathParams": [],
14807
+ "queryParams": [],
14808
+ "requestSchema": null,
14809
+ "responseSchema": {
14810
+ "type": "object",
14811
+ "description": "The payer's outbound spend policy. Returned with defaults (not paused,\nno caps, any on-net payee) when none is set.\n",
14812
+ "properties": {
14813
+ "paused": {
14814
+ "type": "boolean",
14815
+ "description": "Kill-switch. When true, all outbound payments are refused."
14816
+ },
14817
+ "max_per_payment": {
14818
+ "type": ["string", "null"],
14819
+ "description": "Per-payment cap in token base units, or null for no cap."
14820
+ },
14821
+ "max_per_day": {
14822
+ "type": ["string", "null"],
14823
+ "description": "Rolling-day cap in token base units, or null for no cap."
14824
+ },
14825
+ "allowlist": {
14826
+ "type": ["array", "null"],
14827
+ "items": {
14828
+ "type": "string",
14829
+ "format": "uuid"
14830
+ },
14831
+ "description": "Allowed payee org ids. `null` allows any on-net payee; `[]` denies\nall.\n"
14832
+ }
14833
+ },
14834
+ "required": [
14835
+ "paused",
14836
+ "max_per_payment",
14837
+ "max_per_day",
14838
+ "allowlist"
14839
+ ]
14840
+ },
14841
+ "sdkName": "getSpendPolicy",
14842
+ "summary": "Get your spend policy",
14843
+ "tag": "Payments",
14844
+ "tagCommand": "payments"
14845
+ },
14846
+ {
14847
+ "binaryResponse": false,
14848
+ "bodyRequired": false,
14849
+ "command": "list-declined-payments",
14850
+ "description": "The 50 most recent payments your org's spend policy declined, newest\nfirst. Use this to see why an outbound payment was refused (a cap, the\npayee allowlist, or the kill-switch) instead of only reading the\ndashboard.\n",
14851
+ "hasJsonBody": false,
14852
+ "method": "GET",
14853
+ "operationId": "listDeclinedPayments",
14854
+ "path": "/x402/declined-payments",
14855
+ "pathParams": [],
14856
+ "queryParams": [],
14857
+ "requestSchema": null,
14858
+ "responseSchema": {
14859
+ "type": "array",
14860
+ "items": {
14861
+ "type": "object",
14862
+ "description": "A payment the org's spend policy refused.",
14863
+ "properties": {
14864
+ "id": {
14865
+ "type": "string",
14866
+ "format": "uuid"
14867
+ },
14868
+ "challenge_id": {
14869
+ "type": ["string", "null"],
14870
+ "format": "uuid",
14871
+ "description": "The challenge that was declined, if still present."
14872
+ },
14873
+ "counterparty_org": {
14874
+ "type": ["string", "null"],
14875
+ "format": "uuid",
14876
+ "description": "The payee (challenger) org, when known."
14877
+ },
14878
+ "network": {
14879
+ "type": "string",
14880
+ "enum": ["base", "base-sepolia"]
14881
+ },
14882
+ "amount": {
14883
+ "type": "string",
14884
+ "description": "Amount in token base units."
14885
+ },
14886
+ "reason": {
14887
+ "type": "string",
14888
+ "description": "Why the payment was declined (cap, allowlist, paused)."
14889
+ },
14890
+ "declined_at": {
14891
+ "type": "string",
14892
+ "format": "date-time"
14893
+ }
14894
+ },
14895
+ "required": [
14896
+ "id",
14897
+ "network",
14898
+ "amount",
14899
+ "reason",
14900
+ "declined_at"
14901
+ ]
14902
+ }
14903
+ },
14904
+ "sdkName": "listDeclinedPayments",
14905
+ "summary": "List declined payments",
14906
+ "tag": "Payments",
14907
+ "tagCommand": "payments"
14908
+ },
14909
+ {
14910
+ "binaryResponse": false,
14911
+ "bodyRequired": false,
14912
+ "command": "list-payout-addresses",
14913
+ "description": "List your org's registered payout addresses, newest first.",
14914
+ "hasJsonBody": false,
14915
+ "method": "GET",
14916
+ "operationId": "listPayoutAddresses",
14917
+ "path": "/x402/payout-addresses",
14918
+ "pathParams": [],
14919
+ "queryParams": [],
14920
+ "requestSchema": null,
14921
+ "responseSchema": {
14922
+ "type": "array",
14923
+ "items": {
14924
+ "type": "object",
14925
+ "properties": {
14926
+ "id": {
14927
+ "type": "string",
14928
+ "format": "uuid"
14929
+ },
14930
+ "address": {
14931
+ "type": "string",
14932
+ "description": "The checksummed payout address."
14933
+ },
14934
+ "network": {
14935
+ "type": "string",
14936
+ "enum": ["base", "base-sepolia"]
14937
+ },
14938
+ "label": { "type": ["string", "null"] },
14939
+ "is_default": {
14940
+ "type": "boolean",
14941
+ "description": "Exactly one address per (org, network) is the default."
14942
+ },
14943
+ "verified_at": {
14944
+ "type": "string",
14945
+ "format": "date-time",
14946
+ "description": "When ownership of the address was last proven."
14947
+ },
14948
+ "created_at": {
14949
+ "type": "string",
14950
+ "format": "date-time"
14951
+ }
14952
+ },
14953
+ "required": [
14954
+ "id",
14955
+ "address",
14956
+ "network",
14957
+ "label",
14958
+ "is_default",
14959
+ "verified_at"
14960
+ ]
14961
+ }
14962
+ },
14963
+ "sdkName": "listPayoutAddresses",
14964
+ "summary": "List payout addresses",
14965
+ "tag": "Payments",
14966
+ "tagCommand": "payments"
14967
+ },
14968
+ {
14969
+ "binaryResponse": false,
14970
+ "bodyRequired": true,
14971
+ "command": "pay-challenge",
14972
+ "description": "Settle a challenge addressed to your org as payer. The request body\ncarries a signed x402 `PaymentPayload`: an EIP-3009\n`transferWithAuthorization` signed locally with your own key, whose nonce\nis bound to the challenge via the SDK's `deriveEip3009Nonce`. The platform\nverifies every signed field against its own record of the challenge,\napplies your spend policy, and settles on-chain through a facilitator.\nSettlement is non-custodial; Primitive never holds funds. Idempotent:\npaying an already-settled challenge returns the original receipt. Most\ncallers use the SDK `pay()` helper rather than building the payload by\nhand.\n",
14973
+ "hasJsonBody": true,
14974
+ "method": "POST",
14975
+ "operationId": "payChallenge",
14976
+ "path": "/x402/challenges/{id}/pay",
14977
+ "pathParams": [{
14978
+ "description": "Resource UUID",
14979
+ "enum": null,
14980
+ "name": "id",
14981
+ "required": true,
14982
+ "type": "string"
14983
+ }],
14984
+ "queryParams": [],
14985
+ "requestSchema": {
14986
+ "type": "object",
14987
+ "additionalProperties": false,
14988
+ "properties": { "payment": {
14989
+ "type": "object",
14990
+ "description": "A signed x402 v1 `PaymentPayload`. The SDK `pay()` helper builds this;\ncallers rarely construct it by hand. Field names are x402-native.\n",
14991
+ "properties": {
14992
+ "x402Version": {
14993
+ "type": "integer",
14994
+ "const": 1
14995
+ },
14996
+ "scheme": {
14997
+ "type": "string",
14998
+ "const": "exact"
14999
+ },
15000
+ "network": {
15001
+ "type": "string",
15002
+ "enum": ["base", "base-sepolia"]
15003
+ },
15004
+ "payload": {
15005
+ "type": "object",
15006
+ "properties": {
15007
+ "signature": {
15008
+ "type": "string",
15009
+ "pattern": "^0x[0-9a-fA-F]+$",
15010
+ "description": "The EIP-712 signature over the authorization."
15011
+ },
15012
+ "authorization": {
15013
+ "type": "object",
15014
+ "description": "The EIP-3009 `transferWithAuthorization` fields, as strings.",
15015
+ "properties": {
15016
+ "from": { "type": "string" },
15017
+ "to": { "type": "string" },
15018
+ "value": { "type": "string" },
15019
+ "validAfter": { "type": "string" },
15020
+ "validBefore": { "type": "string" },
15021
+ "nonce": { "type": "string" }
15022
+ },
15023
+ "required": [
15024
+ "from",
15025
+ "to",
15026
+ "value",
15027
+ "validAfter",
15028
+ "validBefore",
15029
+ "nonce"
15030
+ ]
15031
+ }
15032
+ },
15033
+ "required": ["signature", "authorization"]
15034
+ }
15035
+ },
15036
+ "required": [
15037
+ "x402Version",
15038
+ "scheme",
15039
+ "network",
15040
+ "payload"
15041
+ ]
15042
+ } },
15043
+ "required": ["payment"]
15044
+ },
15045
+ "responseSchema": {
15046
+ "type": "object",
15047
+ "properties": {
15048
+ "id": {
15049
+ "type": "string",
15050
+ "format": "uuid"
15051
+ },
15052
+ "status": {
15053
+ "type": "string",
15054
+ "enum": ["settled"]
15055
+ },
15056
+ "settle_tx": {
15057
+ "type": ["string", "null"],
15058
+ "description": "On-chain settlement transaction hash."
15059
+ }
15060
+ },
15061
+ "required": [
15062
+ "id",
15063
+ "status",
15064
+ "settle_tx"
15065
+ ]
15066
+ },
15067
+ "sdkName": "payChallenge",
15068
+ "summary": "Pay a payment challenge",
15069
+ "tag": "Payments",
15070
+ "tagCommand": "payments"
15071
+ },
15072
+ {
15073
+ "binaryResponse": false,
15074
+ "bodyRequired": true,
15075
+ "command": "register-payout-address",
15076
+ "description": "Register (or update) the default payout address your org receives x402\npayments at, for a given network. You prove control of the address with\nan org-bound `personal_sign` signature over the message produced by the\nSDK helper `buildPayoutRegistrationMessage`. The org id is taken from your\nauthenticated key, never the body, so a captured signature can't register\nan address under another org. Exactly one default address exists per\n(org, network); registering again replaces it. A payee MUST register a\npayout address before calling `createChallenge`, because the challenge's\n`pay_to` is resolved from this directory.\n",
15077
+ "hasJsonBody": true,
15078
+ "method": "POST",
15079
+ "operationId": "registerPayoutAddress",
15080
+ "path": "/x402/payout-addresses",
15081
+ "pathParams": [],
15082
+ "queryParams": [],
15083
+ "requestSchema": {
15084
+ "type": "object",
15085
+ "additionalProperties": false,
15086
+ "properties": {
15087
+ "address": {
15088
+ "type": "string",
15089
+ "pattern": "^0x[0-9a-fA-F]{40}$",
15090
+ "description": "The payout address (your signer's own EVM address), 0x-prefixed."
15091
+ },
15092
+ "network": {
15093
+ "type": "string",
15094
+ "enum": ["base", "base-sepolia"],
15095
+ "description": "The chain the address receives on."
15096
+ },
15097
+ "signature": {
15098
+ "type": "string",
15099
+ "pattern": "^0x[0-9a-fA-F]+$",
15100
+ "description": "A `personal_sign` signature over the org-bound message produced by\nthe SDK helper `buildPayoutRegistrationMessage`. Recovered and\nchecked against `address`; the org id is bound into the signed bytes.\n"
15101
+ },
15102
+ "issued_at": {
15103
+ "type": "string",
15104
+ "format": "date-time",
15105
+ "description": "ISO-8601 timestamp embedded in the signed message. Must be within a\nshort freshness window (about 10 minutes) of server time.\n"
15106
+ },
15107
+ "label": {
15108
+ "type": "string",
15109
+ "maxLength": 80,
15110
+ "description": "Optional human-readable label."
15111
+ }
15112
+ },
15113
+ "required": [
15114
+ "address",
15115
+ "network",
15116
+ "signature",
15117
+ "issued_at"
15118
+ ]
15119
+ },
15120
+ "responseSchema": {
15121
+ "type": "object",
15122
+ "properties": {
15123
+ "id": {
15124
+ "type": "string",
15125
+ "format": "uuid"
15126
+ },
15127
+ "address": {
15128
+ "type": "string",
15129
+ "description": "The checksummed payout address."
15130
+ },
15131
+ "network": {
15132
+ "type": "string",
15133
+ "enum": ["base", "base-sepolia"]
15134
+ },
15135
+ "label": { "type": ["string", "null"] },
15136
+ "is_default": {
15137
+ "type": "boolean",
15138
+ "description": "Exactly one address per (org, network) is the default."
15139
+ },
15140
+ "verified_at": {
15141
+ "type": "string",
15142
+ "format": "date-time",
15143
+ "description": "When ownership of the address was last proven."
15144
+ },
15145
+ "created_at": {
15146
+ "type": "string",
15147
+ "format": "date-time"
15148
+ }
15149
+ },
15150
+ "required": [
15151
+ "id",
15152
+ "address",
15153
+ "network",
15154
+ "label",
15155
+ "is_default",
15156
+ "verified_at"
15157
+ ]
15158
+ },
15159
+ "sdkName": "registerPayoutAddress",
15160
+ "summary": "Register a payout address",
15161
+ "tag": "Payments",
15162
+ "tagCommand": "payments"
15163
+ },
15164
+ {
15165
+ "binaryResponse": false,
15166
+ "bodyRequired": true,
15167
+ "command": "update-spend-policy",
15168
+ "description": "Update your org's spend policy. Applied as a merge: only the fields you\ninclude change, and omitted fields keep their current value, so a partial\nupdate can't silently reset the kill-switch. Send an explicit `null` to\nclear a cap. Caps are in token base units.\n",
15169
+ "hasJsonBody": true,
15170
+ "method": "PUT",
15171
+ "operationId": "updateSpendPolicy",
15172
+ "path": "/x402/spend-policy",
15173
+ "pathParams": [],
15174
+ "queryParams": [],
15175
+ "requestSchema": {
15176
+ "type": "object",
15177
+ "additionalProperties": false,
15178
+ "description": "Merge update: only the fields you include change; omit a field to keep\nits current value; send `null` to clear a cap.\n",
15179
+ "properties": {
15180
+ "paused": { "type": "boolean" },
15181
+ "max_per_payment": {
15182
+ "type": ["string", "null"],
15183
+ "pattern": "^[1-9][0-9]{0,38}$"
15184
+ },
15185
+ "max_per_day": {
15186
+ "type": ["string", "null"],
15187
+ "pattern": "^[1-9][0-9]{0,38}$"
15188
+ },
15189
+ "allowlist": {
15190
+ "type": ["array", "null"],
15191
+ "maxItems": 1e3,
15192
+ "items": {
15193
+ "type": "string",
15194
+ "format": "uuid"
15195
+ }
15196
+ }
15197
+ }
15198
+ },
15199
+ "responseSchema": {
15200
+ "type": "object",
15201
+ "description": "The payer's outbound spend policy. Returned with defaults (not paused,\nno caps, any on-net payee) when none is set.\n",
15202
+ "properties": {
15203
+ "paused": {
15204
+ "type": "boolean",
15205
+ "description": "Kill-switch. When true, all outbound payments are refused."
15206
+ },
15207
+ "max_per_payment": {
15208
+ "type": ["string", "null"],
15209
+ "description": "Per-payment cap in token base units, or null for no cap."
13097
15210
  },
13098
- "functions": {
13099
- "type": "object",
13100
- "additionalProperties": false,
13101
- "properties": {
13102
- "total": { "type": "integer" },
13103
- "deployed": { "type": "integer" },
13104
- "pending": { "type": "integer" },
13105
- "failed": { "type": "integer" }
13106
- },
13107
- "required": [
13108
- "total",
13109
- "deployed",
13110
- "pending",
13111
- "failed"
13112
- ]
15211
+ "max_per_day": {
15212
+ "type": ["string", "null"],
15213
+ "description": "Rolling-day cap in token base units, or null for no cap."
13113
15214
  },
13114
- "recent_emails": {
13115
- "type": "object",
13116
- "description": "Inbound email activity from the last 30 days.",
13117
- "additionalProperties": false,
13118
- "properties": {
13119
- "total": {
13120
- "type": "integer",
13121
- "description": "Number of inbound emails received in the last 30 days."
13122
- },
13123
- "latest_received_at": {
13124
- "type": ["string", "null"],
13125
- "format": "date-time",
13126
- "description": "Most recent inbound email received in the last 30 days."
13127
- }
15215
+ "allowlist": {
15216
+ "type": ["array", "null"],
15217
+ "items": {
15218
+ "type": "string",
15219
+ "format": "uuid"
13128
15220
  },
13129
- "required": ["total", "latest_received_at"]
15221
+ "description": "Allowed payee org ids. `null` allows any on-net payee; `[]` denies\nall.\n"
13130
15222
  }
13131
15223
  },
13132
15224
  "required": [
13133
- "ready",
13134
- "receiving_ready",
13135
- "processing_ready",
13136
- "summary",
13137
- "next_actions",
13138
- "domains",
13139
- "endpoints",
13140
- "functions",
13141
- "recent_emails"
15225
+ "paused",
15226
+ "max_per_payment",
15227
+ "max_per_day",
15228
+ "allowlist"
13142
15229
  ]
13143
15230
  },
13144
- "sdkName": "getInboxStatus",
13145
- "summary": "Get inbound inbox readiness",
13146
- "tag": "Inbox",
13147
- "tagCommand": "inbox"
15231
+ "sdkName": "updateSpendPolicy",
15232
+ "summary": "Update your spend policy",
15233
+ "tag": "Payments",
15234
+ "tagCommand": "payments"
13148
15235
  },
13149
15236
  {
13150
15237
  "binaryResponse": false,
@@ -18933,8 +21020,8 @@ const PRIMITIVE_TEAM_AUTHOR = {
18933
21020
  name: "Primitive Team",
18934
21021
  url: "https://primitive.dev"
18935
21022
  };
18936
- const SDK_VERSION_RANGE = "^1.4.0";
18937
- const CLI_VERSION_RANGE = "^1.4.0";
21023
+ const SDK_VERSION_RANGE = "^1.6.0";
21024
+ const CLI_VERSION_RANGE = "^1.6.0";
18938
21025
  const ESBUILD_VERSION_RANGE = "^0.27.0";
18939
21026
  function renderHandler() {
18940
21027
  return `// env.PRIMITIVE_API_KEY, env.PRIMITIVE_WEBHOOK_SECRET, and
@@ -22324,6 +24411,392 @@ var OrgSecretsSetCommand = class OrgSecretsSetCommand extends Command {
22324
24411
  }
22325
24412
  };
22326
24413
  //#endregion
24414
+ //#region src/oclif/commands/payments-shared.ts
24415
+ const PRIVATE_KEY_ENV = "PRIMITIVE_X402_PRIVATE_KEY";
24416
+ const PRIVATE_KEY_FLAG_DESCRIPTION = `Hex private key (0x-prefixed) of the wallet that signs. Prefer the ${PRIVATE_KEY_ENV} environment variable so the key is not exposed in shell history or the process list. The key is used locally to sign and never sent to Primitive.`;
24417
+ function x402BaseUrl(resolvedApiBaseUrl) {
24418
+ return resolvedApiBaseUrl.replace(/\/v1\/?$/, "");
24419
+ }
24420
+ /**
24421
+ * Build the x402 signing client. Returns null (after writing a hint) when no
24422
+ * API key resolved, so a not-signed-in caller gets the same guidance as any
24423
+ * other command rather than an opaque "no API key" throw from the SDK.
24424
+ */
24425
+ function buildX402Client(params) {
24426
+ if (!params.apiKey) {
24427
+ process.stderr.write("Not signed in. Set PRIMITIVE_API_KEY or run `primitive signin`, then retry.\n");
24428
+ return null;
24429
+ }
24430
+ return createX402Client({
24431
+ apiKey: params.apiKey,
24432
+ baseUrl: x402BaseUrl(params.resolvedApiBaseUrl)
24433
+ });
24434
+ }
24435
+ const USDC_DECIMALS = 6;
24436
+ /**
24437
+ * Convert a human USDC amount ("0.01") to token base units ("10000"). Returns
24438
+ * null for a non-positive, malformed, or over-precise value (more than 6
24439
+ * fractional digits), so the caller can show a clear error instead of sending
24440
+ * a wrong amount.
24441
+ */
24442
+ function usdcToBaseUnits(human) {
24443
+ const trimmed = human.trim();
24444
+ if (!/^\d+(\.\d+)?$/.test(trimmed)) return null;
24445
+ const [whole, frac = ""] = trimmed.split(".");
24446
+ if (frac.length > USDC_DECIMALS) return null;
24447
+ const padded = frac.padEnd(USDC_DECIMALS, "0");
24448
+ const base = BigInt(whole) * 10n ** BigInt(USDC_DECIMALS) + BigInt(padded);
24449
+ if (base <= 0n) return null;
24450
+ return base.toString();
24451
+ }
24452
+ /** Format token base units ("10000") back to a human USDC string ("0.01"). */
24453
+ function formatUsdc(baseUnits) {
24454
+ if (!/^\d+$/.test(baseUnits)) return baseUnits;
24455
+ const padded = baseUnits.padStart(USDC_DECIMALS + 1, "0");
24456
+ const whole = padded.slice(0, -USDC_DECIMALS);
24457
+ const frac = padded.slice(-USDC_DECIMALS).replace(/0+$/, "");
24458
+ return frac ? `${whole}.${frac}` : whole;
24459
+ }
24460
+ /** Block-explorer URL for a settlement tx, or null for an unknown network/tx. */
24461
+ function explorerTxUrl(network, tx) {
24462
+ if (!/^0x[0-9a-fA-F]{64}$/.test(tx)) return null;
24463
+ if (network === "base") return `https://basescan.org/tx/${tx}`;
24464
+ if (network === "base-sepolia") return `https://sepolia.basescan.org/tx/${tx}`;
24465
+ return null;
24466
+ }
24467
+ const X402_ERROR_HINTS = {
24468
+ no_payout_address: "Register a payout address first: `primitive payments register-payout-address --network <network>`.",
24469
+ feature_disabled: "x402 payments are not enabled for this organization yet.",
24470
+ payment_declined: "Your spend policy declined this payment. Check it with `primitive payments get-spend-policy`; if it is paused, re-enable with `primitive payments update-spend-policy --paused false`.",
24471
+ challenge_expired: "This challenge has expired. Ask the payee to create a new one (raise `--expires-in` when creating long-lived challenges).",
24472
+ settlement_failed: "On-chain settlement failed. The most common cause is insufficient USDC in the paying wallet on this network. Fund the wallet and retry.",
24473
+ 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.",
24474
+ ownership_proof_failed: "The signature did not prove control of the address. Make sure the wallet key matches the address you are registering."
24475
+ };
24476
+ /** Turn a hex private key into a viem account (a valid X402Signer). */
24477
+ function signerFromPrivateKey(rawKey) {
24478
+ const trimmed = rawKey.trim();
24479
+ const hex = trimmed.startsWith("0x") ? trimmed : `0x${trimmed}`;
24480
+ if (!/^0x[0-9a-fA-F]{64}$/.test(hex)) throw new X402Error(`private key must be 32 bytes of hex (64 hex chars, optionally 0x-prefixed); set ${PRIVATE_KEY_ENV} or pass --private-key`, 0);
24481
+ return privateKeyToAccount(hex);
24482
+ }
24483
+ /**
24484
+ * Map an X402Error onto the CLI's standard stderr error + hint surface, so a
24485
+ * payments failure reads like every other command's failure. Returns nothing;
24486
+ * the caller sets the exit code.
24487
+ */
24488
+ function reportX402Error(error, ctx) {
24489
+ if (!(error instanceof X402Error)) {
24490
+ process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
24491
+ return;
24492
+ }
24493
+ const body = error.body;
24494
+ const payload = body && typeof body === "object" && "error" in body ? body : {
24495
+ success: false,
24496
+ error: {
24497
+ code: error.status === 0 ? "client_error" : "request_failed",
24498
+ message: error.message
24499
+ }
24500
+ };
24501
+ writeErrorWithHints(payload);
24502
+ const code = payload.error?.code;
24503
+ if (code && code in X402_ERROR_HINTS) process.stderr.write(`${X402_ERROR_HINTS[code]}\n`);
24504
+ surfaceUnauthorizedHint({
24505
+ auth: ctx.auth,
24506
+ baseUrlOverridden: ctx.baseUrlOverridden,
24507
+ configDir: ctx.configDir,
24508
+ payload
24509
+ });
24510
+ }
24511
+ //#endregion
24512
+ //#region src/oclif/commands/payments-charge.ts
24513
+ var PaymentsChargeCommand = class PaymentsChargeCommand extends Command {
24514
+ static description = `Request an x402 payment by creating a challenge (payee side).
24515
+
24516
+ Give the amount as human USDC with --amount-usdc (e.g. 0.01) or as token base
24517
+ units with --amount (e.g. 10000). The challenge JSON is printed to stdout;
24518
+ hand it to the payer (for example in an email reply) so they can pay it. The
24519
+ payee must have a registered payout address first.`;
24520
+ static summary = "Request an x402 payment (create a challenge)";
24521
+ static examples = [
24522
+ "<%= config.bin %> payments charge --amount-usdc 0.01",
24523
+ "<%= config.bin %> payments charge --amount 10000 --network base",
24524
+ "<%= config.bin %> payments charge --amount-usdc 1.50 > challenge.json"
24525
+ ];
24526
+ static flags = {
24527
+ "api-key": Flags.string({
24528
+ description: "Primitive API key override (defaults to PRIMITIVE_API_KEY or saved OAuth login credentials)",
24529
+ env: "PRIMITIVE_API_KEY"
24530
+ }),
24531
+ "api-base-url": Flags.string({
24532
+ description: API_BASE_URL_FLAG_DESCRIPTION,
24533
+ env: "PRIMITIVE_API_BASE_URL",
24534
+ hidden: true
24535
+ }),
24536
+ "amount-usdc": Flags.string({
24537
+ description: "Amount to collect in USDC, e.g. 0.01. Converted to base units.",
24538
+ exclusive: ["amount"]
24539
+ }),
24540
+ amount: Flags.string({
24541
+ description: "Amount to collect in token base units, e.g. 10000 (0.01 USDC).",
24542
+ exclusive: ["amount-usdc"]
24543
+ }),
24544
+ network: Flags.string({
24545
+ description: "Chain to collect on.",
24546
+ options: ["base", "base-sepolia"],
24547
+ default: "base-sepolia"
24548
+ }),
24549
+ "payer-org": Flags.string({ description: "Restrict who can pay to this organization id (on-net binding)." }),
24550
+ description: Flags.string({ description: "Human-readable description of what the payment is for." }),
24551
+ resource: Flags.string({ description: "A URL identifying the thing being paid for." }),
24552
+ "expires-in": Flags.integer({ description: "Seconds until the challenge expires (60-86400; default 3600)." }),
24553
+ "idempotency-key": Flags.string({ description: "Retry-safe key: charging again with the same key returns the original challenge instead of a duplicate." }),
24554
+ time: Flags.boolean({ description: TIME_FLAG_DESCRIPTION })
24555
+ };
24556
+ async run() {
24557
+ const { flags } = await this.parse(PaymentsChargeCommand);
24558
+ let amount;
24559
+ if (flags["amount-usdc"] !== void 0) {
24560
+ const base = usdcToBaseUnits(flags["amount-usdc"]);
24561
+ if (!base) {
24562
+ process.stderr.write(`Invalid --amount-usdc "${flags["amount-usdc"]}". Use a positive amount with at most 6 decimals, e.g. 0.01.\n`);
24563
+ process.exitCode = 1;
24564
+ return;
24565
+ }
24566
+ amount = base;
24567
+ } else if (flags.amount !== void 0) amount = flags.amount;
24568
+ else {
24569
+ process.stderr.write("Provide --amount-usdc <usdc> (e.g. 0.01) or --amount <base-units> (e.g. 10000).\n");
24570
+ process.exitCode = 1;
24571
+ return;
24572
+ }
24573
+ const { auth, baseUrlOverridden, requestConfig } = await createAuthenticatedCliApiClient({
24574
+ apiKey: flags["api-key"],
24575
+ apiBaseUrl: flags["api-base-url"],
24576
+ configDir: this.config.configDir
24577
+ });
24578
+ await runWithTiming(flags.time, async () => {
24579
+ const client = buildX402Client({
24580
+ apiKey: auth.apiKey,
24581
+ resolvedApiBaseUrl: requestConfig.resolvedApiBaseUrl
24582
+ });
24583
+ if (!client) {
24584
+ process.exitCode = 1;
24585
+ return;
24586
+ }
24587
+ try {
24588
+ const challenge = await client.charge({
24589
+ amount,
24590
+ network: flags.network,
24591
+ ...flags["payer-org"] ? { payerOrg: flags["payer-org"] } : {},
24592
+ ...flags.description ? { description: flags.description } : {},
24593
+ ...flags.resource ? { resource: flags.resource } : {},
24594
+ ...flags["expires-in"] !== void 0 ? { expiresIn: flags["expires-in"] } : {},
24595
+ ...flags["idempotency-key"] ? { idempotencyKey: flags["idempotency-key"] } : {}
24596
+ });
24597
+ process.stderr.write(`Challenge ${challenge.id} for ${formatUsdc(challenge.amount)} USDC on ${challenge.network}. Hand the JSON below to the payer; they settle it with \`primitive payments pay\`.\n`);
24598
+ this.log(JSON.stringify(challenge, null, 2));
24599
+ } catch (error) {
24600
+ reportX402Error(error, {
24601
+ auth,
24602
+ baseUrlOverridden,
24603
+ configDir: this.config.configDir
24604
+ });
24605
+ process.exitCode = 1;
24606
+ }
24607
+ });
24608
+ }
24609
+ };
24610
+ //#endregion
24611
+ //#region src/oclif/commands/payments-pay.ts
24612
+ function readChallenge(input) {
24613
+ let raw;
24614
+ if (input.inline !== void 0) raw = input.inline;
24615
+ else if (input.file !== void 0) raw = readFileSync(input.file, "utf8");
24616
+ else raw = readFileSync(0, "utf8");
24617
+ const trimmed = raw.trim();
24618
+ if (!trimmed) throw new Error("no challenge provided; pass --challenge '<json>', --challenge-file <path>, or pipe the challenge JSON on stdin");
24619
+ let parsed;
24620
+ try {
24621
+ parsed = JSON.parse(trimmed);
24622
+ } catch {
24623
+ throw new Error("challenge is not valid JSON");
24624
+ }
24625
+ if (parsed && typeof parsed === "object" && "data" in parsed) return parsed.data;
24626
+ return parsed;
24627
+ }
24628
+ var PaymentsPayCommand = class PaymentsPayCommand extends Command {
24629
+ static description = `Pay an x402 payment challenge.
24630
+
24631
+ Reads the challenge object the payee gave you, derives and signs the
24632
+ interaction-bound EIP-3009 authorization locally with your wallet key (read
24633
+ from ${PRIVATE_KEY_ENV} by default), and submits it for non-custodial
24634
+ on-chain settlement. The key never leaves your machine. Provide the challenge
24635
+ inline with --challenge, from a file with --challenge-file, or piped on stdin.`;
24636
+ static summary = "Sign and settle an x402 payment challenge";
24637
+ static examples = [
24638
+ "<%= config.bin %> payments pay --challenge-file challenge.json",
24639
+ "<%= config.bin %> payments pay --challenge '{\"id\":\"...\",\"network\":\"base-sepolia\",...}'",
24640
+ "cat challenge.json | <%= config.bin %> payments pay"
24641
+ ];
24642
+ static flags = {
24643
+ "api-key": Flags.string({
24644
+ description: "Primitive API key override (defaults to PRIMITIVE_API_KEY or saved OAuth login credentials)",
24645
+ env: "PRIMITIVE_API_KEY"
24646
+ }),
24647
+ "api-base-url": Flags.string({
24648
+ description: API_BASE_URL_FLAG_DESCRIPTION,
24649
+ env: "PRIMITIVE_API_BASE_URL",
24650
+ hidden: true
24651
+ }),
24652
+ "private-key": Flags.string({
24653
+ description: PRIVATE_KEY_FLAG_DESCRIPTION,
24654
+ env: PRIVATE_KEY_ENV
24655
+ }),
24656
+ challenge: Flags.string({
24657
+ description: "The challenge object as a JSON string.",
24658
+ exclusive: ["challenge-file"]
24659
+ }),
24660
+ "challenge-file": Flags.string({
24661
+ description: "Path to a file containing the challenge JSON.",
24662
+ exclusive: ["challenge"]
24663
+ }),
24664
+ json: Flags.boolean({ description: "Print the raw receipt JSON instead of a human summary." }),
24665
+ time: Flags.boolean({ description: TIME_FLAG_DESCRIPTION })
24666
+ };
24667
+ async run() {
24668
+ const { flags } = await this.parse(PaymentsPayCommand);
24669
+ const { auth, baseUrlOverridden, requestConfig } = await createAuthenticatedCliApiClient({
24670
+ apiKey: flags["api-key"],
24671
+ apiBaseUrl: flags["api-base-url"],
24672
+ configDir: this.config.configDir
24673
+ });
24674
+ await runWithTiming(flags.time, async () => {
24675
+ const client = buildX402Client({
24676
+ apiKey: auth.apiKey,
24677
+ resolvedApiBaseUrl: requestConfig.resolvedApiBaseUrl
24678
+ });
24679
+ if (!client) {
24680
+ process.exitCode = 1;
24681
+ return;
24682
+ }
24683
+ try {
24684
+ const challenge = readChallenge({
24685
+ inline: flags.challenge,
24686
+ file: flags["challenge-file"]
24687
+ });
24688
+ const signer = signerFromPrivateKey(flags["private-key"] ?? "");
24689
+ const receipt = await client.pay(challenge, { signer });
24690
+ if (flags.json) {
24691
+ this.log(JSON.stringify(receipt, null, 2));
24692
+ return;
24693
+ }
24694
+ if (receipt.status === "settled" && receipt.settle_tx) {
24695
+ this.log(`Payment settled. Transaction: ${receipt.settle_tx}`);
24696
+ const url = explorerTxUrl(challenge.network, receipt.settle_tx);
24697
+ if (url) this.log(url);
24698
+ } else this.log(`Payment ${receipt.status}.`);
24699
+ } catch (error) {
24700
+ reportX402Error(error, {
24701
+ auth,
24702
+ baseUrlOverridden,
24703
+ configDir: this.config.configDir
24704
+ });
24705
+ process.exitCode = 1;
24706
+ }
24707
+ });
24708
+ }
24709
+ };
24710
+ //#endregion
24711
+ //#region src/oclif/commands/payments-register-payout-address.ts
24712
+ var PaymentsRegisterPayoutAddressCommand = class PaymentsRegisterPayoutAddressCommand extends Command {
24713
+ static description = `Register the default payout address your org receives x402 payments at.
24714
+
24715
+ Proves control of the address by signing an org-bound message locally with
24716
+ your wallet key (read from ${PRIVATE_KEY_ENV} by default), then registers the
24717
+ recovered address as the default for the chosen network. Registering again
24718
+ replaces the existing default. Run this before \`payments create-challenge\`.`;
24719
+ static summary = "Register a payout address for receiving x402 payments";
24720
+ static examples = ["<%= config.bin %> payments register-payout-address", "<%= config.bin %> payments register-payout-address --network base --label treasury"];
24721
+ static flags = {
24722
+ "api-key": Flags.string({
24723
+ description: "Primitive API key override (defaults to PRIMITIVE_API_KEY or saved OAuth login credentials)",
24724
+ env: "PRIMITIVE_API_KEY"
24725
+ }),
24726
+ "api-base-url": Flags.string({
24727
+ description: API_BASE_URL_FLAG_DESCRIPTION,
24728
+ env: "PRIMITIVE_API_BASE_URL",
24729
+ hidden: true
24730
+ }),
24731
+ "private-key": Flags.string({
24732
+ description: PRIVATE_KEY_FLAG_DESCRIPTION,
24733
+ env: PRIVATE_KEY_ENV
24734
+ }),
24735
+ network: Flags.string({
24736
+ description: "Chain the address receives on.",
24737
+ options: ["base", "base-sepolia"],
24738
+ default: "base-sepolia"
24739
+ }),
24740
+ label: Flags.string({ description: "Optional human-readable label for the address." }),
24741
+ "issued-at": Flags.string({ description: "ISO-8601 timestamp embedded in the signed message. Defaults to now. Must be within ~10 minutes of server time." }),
24742
+ json: Flags.boolean({ description: "Print the raw payout-address JSON instead of a human summary." }),
24743
+ time: Flags.boolean({ description: TIME_FLAG_DESCRIPTION })
24744
+ };
24745
+ async run() {
24746
+ const { flags } = await this.parse(PaymentsRegisterPayoutAddressCommand);
24747
+ const { apiClient, auth, baseUrlOverridden, requestConfig } = await createAuthenticatedCliApiClient({
24748
+ apiKey: flags["api-key"],
24749
+ apiBaseUrl: flags["api-base-url"],
24750
+ configDir: this.config.configDir
24751
+ });
24752
+ await runWithTiming(flags.time, async () => {
24753
+ const account = await getAccount({
24754
+ client: apiClient.client,
24755
+ responseStyle: "fields"
24756
+ });
24757
+ if (account.error) {
24758
+ const payload = extractErrorPayload(account.error);
24759
+ writeErrorWithHints(payload);
24760
+ surfaceUnauthorizedHint({
24761
+ auth,
24762
+ baseUrlOverridden,
24763
+ configDir: this.config.configDir,
24764
+ payload
24765
+ });
24766
+ process.exitCode = 1;
24767
+ return;
24768
+ }
24769
+ const org = account.data.data.id;
24770
+ const client = buildX402Client({
24771
+ apiKey: auth.apiKey,
24772
+ resolvedApiBaseUrl: requestConfig.resolvedApiBaseUrl
24773
+ });
24774
+ if (!client) {
24775
+ process.exitCode = 1;
24776
+ return;
24777
+ }
24778
+ try {
24779
+ const signer = signerFromPrivateKey(flags["private-key"] ?? "");
24780
+ const result = await client.registerPayoutAddress({
24781
+ org,
24782
+ network: flags.network,
24783
+ ...flags["issued-at"] ? { issuedAt: flags["issued-at"] } : {},
24784
+ ...flags.label ? { label: flags.label } : {}
24785
+ }, { signer });
24786
+ if (flags.json) this.log(JSON.stringify(result, null, 2));
24787
+ else this.log(`Registered ${result.address} as the default payout address for ${result.network}. You can now run \`primitive payments charge\`.`);
24788
+ } catch (error) {
24789
+ reportX402Error(error, {
24790
+ auth,
24791
+ baseUrlOverridden,
24792
+ configDir: this.config.configDir
24793
+ });
24794
+ process.exitCode = 1;
24795
+ }
24796
+ });
24797
+ }
24798
+ };
24799
+ //#endregion
22327
24800
  //#region src/oclif/message-body-sources.ts
22328
24801
  function defaultReadFile(path) {
22329
24802
  return readFileSync(path, "utf8");
@@ -23754,7 +26227,9 @@ const OVERRIDDEN_OPERATION_IDS = new Set([
23754
26227
  "domains:download-domain-zone-file",
23755
26228
  "functions:test-function",
23756
26229
  "inbox:get-inbox-status",
23757
- "search:semantic-search"
26230
+ "search:semantic-search",
26231
+ "payments:register-payout-address",
26232
+ "payments:pay-challenge"
23758
26233
  ]);
23759
26234
  const generatedCommands = Object.fromEntries(operationManifest.filter((operation) => !OVERRIDDEN_OPERATION_IDS.has(operationId(operation))).map((operation) => [operationId(operation), createOperationCommand(operation)]));
23760
26235
  const COMMANDS = {
@@ -23827,7 +26302,12 @@ const COMMANDS = {
23827
26302
  return [alias, command];
23828
26303
  })),
23829
26304
  ...generatedCommands,
23830
- "functions:logs": FunctionsLogsCommand
26305
+ "functions:logs": FunctionsLogsCommand,
26306
+ "payments:register-payout-address": PaymentsRegisterPayoutAddressCommand,
26307
+ "payments:register-payout": PaymentsRegisterPayoutAddressCommand,
26308
+ "payments:charge": PaymentsChargeCommand,
26309
+ "payments:pay-challenge": PaymentsPayCommand,
26310
+ "payments:pay": PaymentsPayCommand
23831
26311
  };
23832
26312
  //#endregion
23833
26313
  export { CANONICAL_OPERATION_ALIASES, COMMANDS, lookupOperation };