diff --git a/docs.json b/docs.json index 35a1a4c..3114e6f 100644 --- a/docs.json +++ b/docs.json @@ -108,6 +108,7 @@ "pages": [ "docs/integrate/patterns/fiat-payments", "docs/integrate/patterns/stablecoin-payments", + "docs/integrate/patterns/auto-order", "docs/development-guide/nevermined-x402", "docs/integrate/patterns/payment-models", "docs/integrate/patterns/validate-requests", diff --git a/docs/development-guide/nevermined-x402.mdx b/docs/development-guide/nevermined-x402.mdx index 171bbf0..a0028c7 100644 --- a/docs/development-guide/nevermined-x402.mdx +++ b/docs/development-guide/nevermined-x402.mdx @@ -348,9 +348,17 @@ Using Nevermined Payments libraries (Python or TS), you generate an x402 access agent_id = payment_required["accepts"][0].get("extra", {}).get("agentId") # Pattern A: Auto-create a delegation inline - token_res = payments.x402.get_x402_access_token(plan_id, agent_id, { - 'delegationConfig': { 'spendingLimitCents': 10000, 'durationSecs': 604800 } - }) + from payments_py.x402 import X402TokenOptions, DelegationConfig + token_res = payments.x402.get_x402_access_token( + plan_id, + agent_id, + token_options=X402TokenOptions( + delegation_config=DelegationConfig( + spending_limit_cents=10000, + duration_secs=604800 + ) + ) + ) access_token = token_res["accessToken"] # Pattern B: Create a delegation explicitly, then reuse its ID @@ -371,6 +379,10 @@ Using Nevermined Payments libraries (Python or TS), you generate an x402 access The SDK auto-detects the payment scheme from plan metadata. For fiat plans (`isCrypto: false`), use `resolveScheme()` (TypeScript) or `resolve_scheme()` (Python) to determine the correct scheme. For fiat plans, use `provider: 'stripe'` in the delegation; for crypto plans, use `provider: 'erc4337'`. Middleware handles this automatically — see the [Express.js](/docs/integrate/add-to-your-agent/express) and [FastAPI](/docs/integrate/add-to-your-agent/fastapi) integration guides. + +When a delegation is in place, the facilitator can auto-purchase credits if the balance runs out at settlement — no manual `order_plan()` calls needed. See the [Auto-Order guide](/docs/integrate/patterns/auto-order) for details, spending controls, and A2A examples. + + ### Step 3 — Submit with HTTP header Clients include the x402 access token in the `payment-signature` header: diff --git a/docs/getting-started/quickstart.mdx b/docs/getting-started/quickstart.mdx index e77e3b6..f06aed4 100644 --- a/docs/getting-started/quickstart.mdx +++ b/docs/getting-started/quickstart.mdx @@ -337,4 +337,8 @@ For developers who need to automate and integrate directly, our SDKs are the per print(f'Agent response: {result}') ``` - \ No newline at end of file + + + +In autonomous or agent-to-agent workflows, skip the manual `order_plan()` loop — when a delegation is in place the facilitator tops up credits automatically if the balance runs out. See the [Auto-Order guide](/docs/integrate/patterns/auto-order). + \ No newline at end of file diff --git a/docs/integrate/patterns/auto-order.mdx b/docs/integrate/patterns/auto-order.mdx new file mode 100644 index 0000000..83e259c --- /dev/null +++ b/docs/integrate/patterns/auto-order.mdx @@ -0,0 +1,143 @@ +--- +title: "Auto-Order" +description: "When a subscriber has no credits, calling get_x402_access_token with a delegation automatically purchases credits for the plan — no manual order_plan step needed." +icon: "arrows-rotate" +--- + +By default, subscribers purchase a plan first and then generate an access token. Auto-order removes the manual purchase step: when you call `getX402AccessToken` / `get_x402_access_token` with a delegation and the subscriber has no credits, the system purchases credits for the plan automatically before returning the token. + +## Manual flow vs. auto-order + + + + ```typescript + // Manual flow — check balance, order if needed, wait for settlement + const balance = await payments.plans.getPlanBalance(planId) + if (Number(balance.balance) <= 0) { + await payments.plans.orderPlan(planId) + await new Promise(resolve => setTimeout(resolve, 5000)) // wait for on-chain confirmation + } + const { accessToken } = await payments.x402.getX402AccessToken(planId, agentId, { + delegationConfig: { spendingLimitCents: 10000, durationSecs: 604800 } + }) + + // Auto-order — one step: if no credits, the system purchases them automatically + const { accessToken } = await payments.x402.getX402AccessToken(planId, agentId, { + delegationConfig: { spendingLimitCents: 10000, durationSecs: 604800 } + }) + ``` + + + ```python + import time + from payments_py.x402 import X402TokenOptions, DelegationConfig + + # Manual flow — check balance, order if needed, wait for settlement + balance = payments.plans.get_plan_balance(plan_id) + if balance.get('balance', 0) <= 0: + payments.plans.order_plan(plan_id) + time.sleep(5) # wait for on-chain confirmation + token_res = payments.x402.get_x402_access_token(plan_id, agent_id) + + # Auto-order — one step: if no credits, the system purchases them automatically + token_res = payments.x402.get_x402_access_token( + plan_id, agent_id, + token_options=X402TokenOptions( + delegation_config=DelegationConfig(spending_limit_cents=10000, duration_secs=604800) + ) + ) + access_token = token_res['accessToken'] + ``` + + + + +The code is identical — the difference is that with a delegation in place you can skip the explicit `order_plan` / `orderPlan` call. If the subscriber already has credits the token is returned immediately; if not, the purchase happens first. + + +## Setting up the delegation + +The delegation authorizes the system to spend on the subscriber's behalf. The two required fields when creating a new delegation are: + +| Field | Description | +|---|---| +| `spendingLimitCents` | Total spending cap for this delegation's lifetime, in cents. `10000` = $100. | +| `durationSecs` | How long the delegation is valid in seconds. `604800` = 7 days. | + +For long-running agents, create the delegation once and reuse its ID across requests: + + + + ```typescript + // Create once + const delegation = await payments.delegation.createDelegation({ + provider: 'erc4337', + spendingLimitCents: 50000, // $500 total budget + durationSecs: 2592000 // 30 days + }) + + // Reuse across all requests — spending tracked cumulatively + const { accessToken } = await payments.x402.getX402AccessToken(planId, agentId, { + delegationConfig: { delegationId: delegation.delegationId } + }) + ``` + + + ```python + from payments_py.x402 import X402TokenOptions, DelegationConfig, CreateDelegationPayload + + # Create once + delegation = payments.delegation.create_delegation( + CreateDelegationPayload( + provider='erc4337', + spending_limit_cents=50000, # $500 total budget + duration_secs=2592000 # 30 days + ) + ) + + # Reuse across all requests — spending tracked cumulatively + token_res = payments.x402.get_x402_access_token( + plan_id, agent_id, + token_options=X402TokenOptions( + delegation_config=DelegationConfig(delegation_id=delegation.delegation_id) + ) + ) + access_token = token_res['accessToken'] + ``` + + + +## Fiat plans (`nvm:card-delegation`) + +Auto-order works the same way for card-delegation plans. If the subscriber has no credits, the system creates a Stripe charge automatically when `get_x402_access_token` is called. The `spendingLimitCents` in the delegation controls the total charge ceiling. + +See [Fiat Payments](/docs/integrate/patterns/fiat-payments) and [Nevermined Pay](/docs/products/nvm-pay/overview) for how to enroll a card. + +## When auto-order stops + +| Condition | What happens | +|---|---| +| Delegation `spendingLimitCents` exhausted | Purchase is rejected. Token generation fails with a payment error. | +| Delegation expired (`durationSecs` elapsed) | Delegation is invalid. Token generation fails. | +| Subscriber wallet has insufficient token balance (crypto) | On-chain purchase fails. Token generation fails. | + + +In A2A pipelines, handle token generation failures explicitly. When a delegation is exhausted or expired, surface a clear payment error to the orchestrator rather than retrying indefinitely. + + +## Next steps + + + + Understand the crypto payment model and how delegations work on-chain + + + Accept cards via Stripe or Visa with per-request auto-charging + + + Deep dive into the x402 protocol, session keys, and settlement flow + + + Build autonomous agent pipelines with built-in payment rails + + diff --git a/docs/integrate/patterns/fiat-payments.mdx b/docs/integrate/patterns/fiat-payments.mdx index 996fb02..45a23d8 100644 --- a/docs/integrate/patterns/fiat-payments.mdx +++ b/docs/integrate/patterns/fiat-payments.mdx @@ -103,7 +103,7 @@ NVM Pay supports two card enrollment providers: -Card delegation is what enables fiat-based agent-to-agent payments. An agent owner enrolls their card and sets spending limits, and the agent can autonomously pay for services from other agents, all settled in fiat. See the [NVM Pay FAQ](/docs/products/nvm-pay/faq) for common questions. +Card delegation is what enables fiat-based agent-to-agent payments. An agent owner enrolls their card and sets spending limits, and the agent can autonomously pay for services from other agents, all settled in fiat. Auto-ordering is built into card delegations: if a subscriber's credit balance runs out during a request, the facilitator automatically creates a new Stripe charge within the delegation limits — no extra parameters needed. See the [Auto-Order guide](/docs/integrate/patterns/auto-order) and the [NVM Pay FAQ](/docs/products/nvm-pay/faq) for details. ## Permission Model diff --git a/docs/integrate/patterns/stablecoin-payments.mdx b/docs/integrate/patterns/stablecoin-payments.mdx index 9a30376..2741f45 100644 --- a/docs/integrate/patterns/stablecoin-payments.mdx +++ b/docs/integrate/patterns/stablecoin-payments.mdx @@ -129,19 +129,13 @@ Because there's no payment processor in the middle, stablecoin payments carry no -## Auto-Ordering +## Auto-Order (Pay-As-You-Go) -When a subscriber's credit balance runs low, the system can automatically purchase more credits on their behalf. This happens seamlessly if: +When a subscriber's credit balance runs low, the x402 facilitator can automatically purchase more credits on their behalf — no manual balance checks required. This keeps agent-to-agent pipelines running without interruption. -- The subscriber's wallet has sufficient token balance -- The active delegation has remaining spending capacity (`spendingLimitCents` not exhausted) -- The plan supports re-ordering +Configure a delegation with `spendingLimitCents` when generating the access token and the facilitator handles the rest. Total spending is always bounded by that limit, enforced on-chain. -This keeps agent-to-agent workflows running without interruption. - - -If the delegation's `spendingLimitCents` is exhausted or the delegation has expired, auto-ordering stops. The subscriber must create a new delegation with fresh limits to resume. - +See the [Auto-Order guide](/docs/integrate/patterns/auto-order) for enabling this, safety controls, failure handling, and full A2A examples. ## Next Steps diff --git a/docs/integrate/quickstart/python.mdx b/docs/integrate/quickstart/python.mdx index e88fcfc..b95649c 100644 --- a/docs/integrate/quickstart/python.mdx +++ b/docs/integrate/quickstart/python.mdx @@ -232,7 +232,7 @@ def purchase_and_query(): plan_id = os.environ['PLAN_ID'] agent_id = os.environ['AGENT_ID'] - # 1. Order the plan + # 1. Order the plan (purchases credits upfront) print('Purchasing plan...') order_result = payments.plans.order_plan(plan_id) @@ -259,6 +259,10 @@ if __name__ == '__main__': purchase_and_query() ``` + +For autonomous agents that run continuously, set up a delegation when generating the access token — the facilitator tops up credits automatically when balance runs out, with no manual `order_plan()` loop needed. See the [Auto-Order guide](/docs/integrate/patterns/auto-order). + + ## Flask Alternative ```python filename="flask_app.py" diff --git a/docs/integrate/quickstart/typescript.mdx b/docs/integrate/quickstart/typescript.mdx index b0c2162..e674bcd 100644 --- a/docs/integrate/quickstart/typescript.mdx +++ b/docs/integrate/quickstart/typescript.mdx @@ -221,7 +221,7 @@ const payments = Payments.getInstance({ }) async function purchaseAndQuery() { - // 1. Order the plan + // 1. Order the plan (purchases credits upfront) console.log('Purchasing plan...') await payments.plans.orderPlan(process.env.PLAN_ID!) @@ -251,6 +251,10 @@ async function purchaseAndQuery() { purchaseAndQuery() ``` + +For autonomous agents that run continuously, set up a delegation when generating the access token — the facilitator tops up credits automatically when balance runs out, with no manual `orderPlan()` loop needed. See the [Auto-Order guide](/docs/integrate/patterns/auto-order). + + ## Project Structure ``` diff --git a/skills/nevermined-payments/references/client-integration.md b/skills/nevermined-payments/references/client-integration.md index 52dd112..3115071 100644 --- a/skills/nevermined-payments/references/client-integration.md +++ b/skills/nevermined-payments/references/client-integration.md @@ -23,14 +23,11 @@ const payments = Payments.getInstance({ environment: 'sandbox' }) -// Order the plan +// Order the plan (first purchase only) await payments.plans.orderPlan(PLAN_ID) -// Check balance -const balance = await payments.plans.getPlanBalance(PLAN_ID) -console.log(`Credits remaining: ${balance}`) - -// Generate x402 access token (requires delegationConfig) +// Generate x402 access token with a delegation +// The facilitator will auto-order credits if balance runs out at settlement const { accessToken } = await payments.x402.getX402AccessToken(PLAN_ID, AGENT_ID, { delegationConfig: { spendingLimitCents: 10000, durationSecs: 604800 } }) @@ -47,16 +44,14 @@ payments = Payments.get_instance( PaymentOptions(nvm_api_key=os.environ["NVM_API_KEY"], environment="sandbox") ) -# Order the plan +# Order the plan (first purchase only) payments.plans.order_plan(plan_id) -# Check balance -balance = payments.plans.get_plan_balance(plan_id) -print(f"Credits remaining: {balance}") - -# Generate x402 access token (requires delegationConfig) +# Generate x402 access token with a delegation +# The facilitator will auto-order credits if balance runs out at settlement token_res = payments.x402.get_x402_access_token( - plan_id, agent_id, + plan_id, + agent_id, token_options=X402TokenOptions( delegation_config=DelegationConfig(spending_limit_cents=10000, duration_secs=604800) ) @@ -64,6 +59,16 @@ token_res = payments.x402.get_x402_access_token( access_token = token_res["accessToken"] ``` +## Auto-Order + +When a delegation is configured, the facilitator can automatically purchase more credits at settlement time if the subscriber's balance is insufficient — no manual balance-check loop needed. + +- **Crypto plans (`nvm:erc4337`)**: pass `delegationConfig` with `spendingLimitCents` and `durationSecs` +- **Fiat plans (`nvm:card-delegation`)**: auto-order is built into the card delegation — no extra parameter needed +- **Spending cap**: always controlled by `spendingLimitCents` in the delegation, enforced on-chain +- **When it stops**: delegation exhausted, expired, or wallet has insufficient token balance → request returns 402 +- Handle 402 responses in A2A pipelines explicitly — surface a clear payment error rather than retrying indefinitely + ## Call a Protected HTTP API ### TypeScript