Skip to content

feat(agents): amend experimental agent API for agent-operated wallets - #1161

Draft
kphurley7 wants to merge 8 commits into
mainfrom
kph/agent-spec-amendments
Draft

kphurley7 wants to merge 8 commits into
mainfrom
kph/agent-spec-amendments

Conversation

@kphurley7

@kphurley7 kphurley7 commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

Amends the experimental Agents API so an agent can operate a customer's embedded wallet with Grid enforcing its policy.

  • Agent execute no longer takes Grid-Wallet-Signature; Grid signs with the agent's delegated key (403 when the agent has none).
  • DelegatedKeyCreateRequest takes exactly one of cardId or agentId (both or neither is a 400). Card requests are unchanged.
  • AgentAction gains failureReason (QUOTE_EXPIRED, POLICY_DENIED, ...) and expiresAt; a pending action expires with its quote and is never re-quoted on approval.
  • AgentActionWebhook adds PENDING_APPROVAL, APPROVED, REJECTED, FAILED.
  • Policy currency is immutable; approval-threshold currency must equal the limits currency; account-rule limits are in that currency.
  • AgentPermission adds RECEIVE_FUNDS, MANAGE_IDENTITY, MANAGE_CARDS.
  • New experimental routes: /agents/me/customer, /agents/me/verifications, /agents/me/kyc-link, /agents/me/deposits.
  • Agent cards: /agents/me/cards (list; issue a SINGLE_USE or MERCHANT_LOCKED purchase card, 201 or 202 pending approval), /agents/me/cards/{cardId} (get; tighten-only PATCH and freeze; close a purchase card) and /agents/me/cards/{cardId}/reveal. Each response is an AgentCard: the platform's Card nested under card, beside agentId, agentCardKind, spendLimit, reservedAmount, effectiveBlockedMccs and expiresAt. AgentAction adds the ISSUE_PURCHASE_CARD type with purchaseCard/card fields and the CARD_ISSUANCE_FAILED and APPROVAL_EXPIRED failure reasons.
  • Cards gain allowedMccs and blockedMccs (create, update, read), agentId (issue a standard card for an agent) and defaultMccBlocksLifted (the platform may lift Grid's default agent merchant-category blocks on a standard agent card only; an agent's blockedMccs must cover the card's effective blocks).
  • PasskeyAuthChallenge gains optional payloadToSign: the exact canonical JSON of the Turnkey session request whose lowercase-hex SHA-256 is challenge, so a client can check what a passkey authorizes before signing. Additive; existing clients are unaffected.
  • Agent quotes to another chain: POST /agents/me/quotes takes AgentQuoteRequest, whose destination is ACCOUNT (another embedded wallet) or CHAIN_ADDRESS (network, currency USDC/USDT, address). A chain quote sends USDB with lockedCurrencySide SENDING and commits to a minimumReceivingAmount; Grid re-prices at execution and fails the action with the new PRICE_MOVED reason rather than send for less. Create/get responses and AgentAction.quote are AgentQuote (Quote plus minimumReceivingAmount).

Validation: make build, make lint (0 errors; no new warnings), npm run validate pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019XW8sx8DuMs7wsDg5hHJck
@vercel

vercel Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

3 Skipped Deployments
Project Deployment Actions Updated
grid-cards-demo Ignored Ignored Preview Oct 10, 2026 9:52am UTC
grid-flow-builder Ignored Ignored Preview Oct 10, 2026 9:52am UTC
grid-wallet-demo Ignored Ignored Preview Oct 10, 2026 9:52am UTC

Request Review

@mintlify

mintlify Bot commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated
Grid 🟢 Ready View Preview Oct 10, 2026, 9:52 AM

@greptile-apps

greptile-apps Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

This PR does not match any of the 3 configured review trigger rules.

@github-actions github-actions Bot added the breaking-change Introduces a breaking change to the OpenAPI spec label Oct 9, 2026
@github-actions

github-actions Bot commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

⚠️ Breaking OpenAPI changes detected

oasdiff reports 39 error / 49 warning changes to openapi.yaml.
This PR will need approval from an API reviewer before merge.

Errors (39)

  • POST /agents/device-codes/{code}/redeem — api path removed without deprecation [api-path-removed-without-deprecation].
  • GET /agents/device-codes/{code}/status — api path removed without deprecation [api-path-removed-without-deprecation].
  • POST /agents/me/quotes — removed #/components/schemas/UmaAddressDestination from the destination request property oneOf list [request-property-one-of-removed].
  • POST /agents/me/quotes — the response's body type/format changed from object/to/`` for status 201 [response-body-type-changed].
  • POST /agents/me/quotes — removed the required property createdAt from the response with the 201 status [response-required-property-removed].
  • POST /agents/me/quotes — removed the required property destination from the response with the 201 status [response-required-property-removed].
  • POST /agents/me/quotes — removed the required property exchangeRate from the response with the 201 status [response-required-property-removed].
  • POST /agents/me/quotes — removed the required property expiresAt from the response with the 201 status [response-required-property-removed].
  • POST /agents/me/quotes — removed the required property feesIncluded from the response with the 201 status [response-required-property-removed].
  • POST /agents/me/quotes — removed the required property id from the response with the 201 status [response-required-property-removed].
  • POST /agents/me/quotes — removed the required property receivingCurrency from the response with the 201 status [response-required-property-removed].
  • POST /agents/me/quotes — removed the required property sendingCurrency from the response with the 201 status [response-required-property-removed].
  • POST /agents/me/quotes — removed the required property source from the response with the 201 status [response-required-property-removed].
  • POST /agents/me/quotes — removed the required property status from the response with the 201 status [response-required-property-removed].
  • POST /agents/me/quotes — removed the required property totalReceivingAmount from the response with the 201 status [response-required-property-removed].
  • POST /agents/me/quotes — removed the required property totalSendingAmount from the response with the 201 status [response-required-property-removed].
  • POST /agents/me/quotes — removed the required property transactionId from the response with the 201 status [response-required-property-removed].
  • GET /agents/me/quotes/{quoteId} — the response's body type/format changed from object/to/`` for status 200 [response-body-type-changed].
  • GET /agents/me/quotes/{quoteId} — removed the required property createdAt from the response with the 200 status [response-required-property-removed].
  • GET /agents/me/quotes/{quoteId} — removed the required property destination from the response with the 200 status [response-required-property-removed].
  • GET /agents/me/quotes/{quoteId} — removed the required property exchangeRate from the response with the 200 status [response-required-property-removed].
  • GET /agents/me/quotes/{quoteId} — removed the required property expiresAt from the response with the 200 status [response-required-property-removed].
  • GET /agents/me/quotes/{quoteId} — removed the required property feesIncluded from the response with the 200 status [response-required-property-removed].
  • GET /agents/me/quotes/{quoteId} — removed the required property id from the response with the 200 status [response-required-property-removed].
  • GET /agents/me/quotes/{quoteId} — removed the required property receivingCurrency from the response with the 200 status [response-required-property-removed].
  • GET /agents/me/quotes/{quoteId} — removed the required property sendingCurrency from the response with the 200 status [response-required-property-removed].
  • GET /agents/me/quotes/{quoteId} — removed the required property source from the response with the 200 status [response-required-property-removed].
  • GET /agents/me/quotes/{quoteId} — removed the required property status from the response with the 200 status [response-required-property-removed].
  • GET /agents/me/quotes/{quoteId} — removed the required property totalReceivingAmount from the response with the 200 status [response-required-property-removed].
  • GET /agents/me/quotes/{quoteId} — removed the required property totalSendingAmount from the response with the 200 status [response-required-property-removed].
  • GET /agents/me/quotes/{quoteId} — removed the required property transactionId from the response with the 200 status [response-required-property-removed].
  • GET /auth/delegated-keys — the response property data/items/cardId became optional for the status 200 [response-property-became-optional].
  • GET /auth/delegated-keys — the response property data/items/fundingSourceId became optional for the status 200 [response-property-became-optional].
  • POST /auth/delegated-keys — the response property cardId became optional for the status 201 [response-property-became-optional].
  • POST /auth/delegated-keys — the response property fundingSourceId became optional for the status 201 [response-property-became-optional].
  • GET /auth/delegated-keys/{id} — the response property cardId became optional for the status 200 [response-property-became-optional].
  • GET /auth/delegated-keys/{id} — the response property fundingSourceId became optional for the status 200 [response-property-became-optional].
  • POST webhook:agent-action — added the new required request property allOf[subschema #2]/data/expiresAt [new-required-request-property].
  • POST webhook:agent-action — added #/components/schemas/AgentQuote to the allOf[subschema #2]/data/quote request property allOf list [request-property-all-of-added].

Warnings (49)

Show sample
  • GET /agents — added the new MANAGE_CARDS enum value to the data/items/policy/permissions/items/ response property for the response status 200 [response-property-enum-value-added]. Adding new enum values to response could be unexpected for clients, use x-extensible-enum instead.
  • GET /agents — added the new MANAGE_IDENTITY enum value to the data/items/policy/permissions/items/ response property for the response status 200 [response-property-enum-value-added]. Adding new enum values to response could be unexpected for clients, use x-extensible-enum instead.
  • GET /agents — added the new RECEIVE_FUNDS enum value to the data/items/policy/permissions/items/ response property for the response status 200 [response-property-enum-value-added]. Adding new enum values to response could be unexpected for clients, use x-extensible-enum instead.
  • POST /agents — added the new MANAGE_CARDS enum value to the agent/policy/permissions/items/ response property for the response status 201 [response-property-enum-value-added]. Adding new enum values to response could be unexpected for clients, use x-extensible-enum instead.
  • POST /agents — added the new MANAGE_IDENTITY enum value to the agent/policy/permissions/items/ response property for the response status 201 [response-property-enum-value-added]. Adding new enum values to response could be unexpected for clients, use x-extensible-enum instead.
  • POST /agents — added the new RECEIVE_FUNDS enum value to the agent/policy/permissions/items/ response property for the response status 201 [response-property-enum-value-added]. Adding new enum values to response could be unexpected for clients, use x-extensible-enum instead.
  • GET /agents/approvals — added the new ISSUE_PURCHASE_CARD enum value to the data/items/type response property for the response status 200 [response-property-enum-value-added]. Adding new enum values to response could be unexpected for clients, use x-extensible-enum instead.
  • GET /agents/me — added the new MANAGE_CARDS enum value to the policy/permissions/items/ response property for the response status 200 [response-property-enum-value-added]. Adding new enum values to response could be unexpected for clients, use x-extensible-enum instead.
  • GET /agents/me — added the new MANAGE_IDENTITY enum value to the policy/permissions/items/ response property for the response status 200 [response-property-enum-value-added]. Adding new enum values to response could be unexpected for clients, use x-extensible-enum instead.
  • GET /agents/me — added the new RECEIVE_FUNDS enum value to the policy/permissions/items/ response property for the response status 200 [response-property-enum-value-added]. Adding new enum values to response could be unexpected for clients, use x-extensible-enum instead.
  • GET /agents/me/actions — added the new ISSUE_PURCHASE_CARD enum value to the data/items/type response property for the response status 200 [response-property-enum-value-added]. Adding new enum values to response could be unexpected for clients, use x-extensible-enum instead.
  • GET /agents/me/actions/{actionId} — added the new ISSUE_PURCHASE_CARD enum value to the type response property for the response status 200 [response-property-enum-value-added]. Adding new enum values to response could be unexpected for clients, use x-extensible-enum instead.
  • POST /agents/me/quotes — removed the request property description [request-property-removed].
  • POST /agents/me/quotes — removed the request property documentIds [request-property-removed].
  • POST /agents/me/quotes — removed the request property immediatelyExecute [request-property-removed].
  • POST /agents/me/quotes — removed the request property lookupId [request-property-removed].
  • POST /agents/me/quotes — removed the request property platformFeeOverride [request-property-removed].
  • POST /agents/me/quotes — removed the request property purposeOfPayment [request-property-removed].
  • POST /agents/me/quotes — removed the request property remittanceInformation [request-property-removed].
  • POST /agents/me/quotes — removed the request property scaFactor [request-property-removed].
  • POST /agents/me/quotes — removed the request property senderCustomerInfo [request-property-removed].
  • POST /agents/me/quotes — removed the optional property counterpartyInformation from the response with the 201 status [response-optional-property-removed].
  • POST /agents/me/quotes — removed the optional property documentIds from the response with the 201 status [response-optional-property-removed].
  • POST /agents/me/quotes — removed the optional property paymentInstructions from the response with the 201 status [response-optional-property-removed].
  • POST /agents/me/quotes — removed the optional property platformFeesIncluded from the response with the 201 status [response-optional-property-removed].
  • …and 24 more warnings.

Detected by oasdiff. Full report: job summary or the oasdiff-report artifact.

Move device-code status and redemption inputs into JSON request bodies, distinguish terminal device-code states, and document agent route feature-gate errors.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019XW8sx8DuMs7wsDg5hHJck
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019XW8sx8DuMs7wsDg5hHJck
Add /agents/me/cards (list, issue purchase card), /agents/me/cards/{cardId}
(get, tighten or freeze, close purchase card) and its reveal, the
MANAGE_CARDS permission, the ISSUE_PURCHASE_CARD action with its
CARD_ISSUANCE_FAILED and APPROVAL_EXPIRED failure reasons, and allowedMccs,
blockedMccs and agentId on cards.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019XW8sx8DuMs7wsDg5hHJck
The passkey challenge response gains an optional payloadToSign: the exact
canonical JSON of the Turnkey session request whose lowercase-hex SHA-256 is
the challenge. A client can now parse and check what the passkey authorizes
(activity type, its own clientPublicKey) and recompute the digest before
calling navigator.credentials.get(). Additive: existing clients that only read
challenge are unaffected, and Grid still forwards the stored request.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019XW8sx8DuMs7wsDg5hHJck
POST /agents/me/quotes takes AgentQuoteRequest, whose destination is
either another embedded wallet (ACCOUNT) or CHAIN_ADDRESS: network
(BASE, ETHEREUM, SOLANA, POLYGON, ARBITRUM, TRON), currency (USDC or
USDT; TRON is USDT only, BASE is USDC only) and address. Grid records
the address as an external account of the customer, reused when one
exists for the same network, currency and address, and screens it
before quoting.

A CHAIN_ADDRESS quote sends USDB with lockedCurrencySide SENDING and
commits to the USDB amount, the destination and a
minimumReceivingAmount. Grid prices the conversion again when the quote
executes, after any approval, and fails the action with the new
PRICE_MOVED failure reason rather than send for less.

The create and get responses, and AgentAction.quote, are AgentQuote:
Quote plus minimumReceivingAmount.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019XW8sx8DuMs7wsDg5hHJck
Grid's default agent merchant-category blocks stay on top of blockedMccs and
are lifted only by the platform on a standard agent card
(defaultMccBlocksLifted); an agent's blockedMccs must cover the card's
effective blocks. Purchase-card currency is an enum of USD, allowedMccs has at
least one code, closing a card that is not an open purchase card is a 409 like
reveal, spending limits on a purchase card are a 400, and reusing an
Idempotency-Key with a different body is a 400.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019XW8sx8DuMs7wsDg5hHJck
AgentCard carries the Card as `card` beside the agent fields instead of
merging them with allOf, which kept generated clients from reading the card's
nullable limits.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019XW8sx8DuMs7wsDg5hHJck

This branch was successfully deployed

1 active deployment
staging - mintlify — 21949901 Deployed Oct 10, 2026 by mintlify[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

breaking-change Introduces a breaking change to the OpenAPI spec

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant