External dependencies, deployment boundaries, routing, notification delivery, merchant recovery, and release checks for self-hosted Grantex prepaid wallets and x402 v2.
Use this checklist before enabling prepaid-wallet or x402 traffic in a
self-hosted environment. Repository tests prove the Grantex authorization and
sandbox_ledger paths; they do not provision a custody provider, merchant
recovery store, notification channel, or regulatory approval for the operator.
The source checkout includes a specific Base USDC adapter.
It requires migration 094, operator-provisioned keys, a trusted Base RPC,
verified funding and reconciliation monitoring. Python 0.7.2 and Go v0.4.3
publish the response and reconciliation APIs; published TypeScript 0.8.2 and
x402 0.4.1 support opt-in automatic Base payment retries. Other external
providers still need their own adapter.
Signed EVM holds are not released on a wallet block or a local timeout alone.
Dependency
Required when
Current repository behavior
Operator action
PostgreSQL migrations 091_agent_prepaid_wallets.sql and 092_layered_wallet_spend_controls.sql
Always
Startup applies ordered migrations automatically
Back up PostgreSQL, deploy the exact repository migration set, and verify startup completed before sending traffic
Public HTTPS routing
The issuer or wallet resource uses a public host
DPoP tokens bind the exact /v1/prepaid-wallets audience
Route the exact public wallet and OAuth paths to the auth service; do not rewrite them to static HTML
@grantex/sdk@0.8.2 and @grantex/x402@0.4.1
Applications install managed-wallet clients from npm
Both exact versions are published and registry verified
Pin these exact versions and complete the dependencies below
External custody adapter
Real bank, card, on-chain, or provider-held funds
Configured base_usdc supports native Base USDC; other/unconfigured providers fail closed
Follow the Base custody guide or implement and independently test the selected provider’s funding, reservation, settlement, reconciliation and recovery
Principal notification bridge
A human must receive reload alerts outside the Grantex UI
Wallet reload events are emitted to the event bus; no built-in email/SMS/chat delivery is claimed
Consume SSE/WebSocket events and deliver through an approved channel, or separately extend and test webhook registration for wallet events
Merchant idempotency store
A paid request has side effects
Grantex makes reservation and settlement retries idempotent
Atomically store the merchant’s business result under the caller’s HTTP Idempotency-Key
Independent security, provider, and legal review
Real-money or regulated use
The repository makes no certification or stored-value claim
sandbox_ledger is complete local/off-chain accounting with PostgreSQL as the
system of record. It is suitable for development, deterministic integration
tests, and deployments that explicitly intend to operate an internal ledger.
It is not a bank account, prepaid card, on-chain balance, proof of external
funds, or a regulated stored-value product.external requires provider-specific verification. The included base_usdc
adapter verifies finalized native USDC funding and settlement through RPC and
retains outstanding signed exposure through blocks and provider outages. It
requires explicit operator provisioning; installation alone does not enable it.
Other providers remain unavailable. Do not turn arbitrary provider references
into balance. A production adapter must, at minimum:
authenticate signed provider webhooks and reject stale or replayed events;
deduplicate funding and settlement references transactionally;
reconcile Grantex available/reserved amounts with provider state;
reserve and settle through provider-supported atomic or compensating flows;
persist provider transaction and evidence references without exposing
credentials to agents;
define timeout, partial failure, reversal, dispute, and restart recovery;
fail closed when provider state is unavailable or ambiguous.
Set JWT_ISSUER to the exact issuer URL used in tokens and
PUBLIC_BASE_URL to the browser-reachable origin. In a normal reverse-proxy
deployment, route the entire API origin to the auth service. If a static host
and API share one domain, explicitly forward at least:
The OAuth resource and access-token audience must be the same exact URL, for
example https://auth.example.com/v1/prepaid-wallets. TLS is required outside
loopback development. A static-host 404 at this path means the agent cannot
list wallets, request reloads, or authorize a payment even if Cloud Run or the
origin service itself is healthy.After deployment, unauthenticated probes should reach the auth service and fail
with structured authentication errors, not HTML:
$Base = 'https://auth.example.com'$List = Invoke-WebRequest "$Base/v1/prepaid-wallets" ` -Method Get -SkipHttpErrorCheck$Authorize = Invoke-WebRequest "$Base/v1/prepaid-wallets/authorizations" ` -Method Post -ContentType 'application/json' -Body '{}' -SkipHttpErrorCheckif ($List.StatusCode -ne 401 -or $List.Content -notmatch 'INVALID_TOKEN') { throw 'The prepaid-wallet base route does not reach the auth service.'}if ($Authorize.StatusCode -ne 401 -or $Authorize.Content -notmatch 'INVALID_TOKEN') { throw 'The prepaid-wallet wildcard route does not reach the auth service.'}
The service emits wallet.low_balance, wallet.reload.requested,
wallet.reload.approved, wallet.reload.rejected, wallet.reloaded,
wallet.payment.denied, wallet.payment.approval_required,
wallet.payment.approval_approved, wallet.payment.approval_rejected, and
wallet.spend_policy.changed events. Agents can request a reload but cannot
approve or fund it.There is no built-in promise that a reload request reaches email, SMS, Slack,
WhatsApp, or another human channel. The current public webhook-registration API
accepts only its documented grant/token event allowlist. For wallet alerts,
operate an authenticated SSE/WebSocket consumer and bridge events to the
principal’s approved channel, or implement a separately reviewed webhook
extension. The bridge must deduplicate by event ID, retry durably, protect
principal contact data, and expose delivery failures to operators.Do not auto-approve or auto-fund merely because a notification was delivered.
The principal decision and funding calls remain separate authenticated actions.
For a side-effecting paid request, the resource server must use this order:
Validate the x402 request and call /v1/x402/verify.
Complete /v1/x402/settle successfully.
Atomically create or retrieve the protected business result under the
caller’s HTTP Idempotency-Key.
Return the cached result on an identical retry.
The SDK idempotencyKey recovers a Grantex reservation response lost before
settlement. The HTTP Idempotency-Key recovers merchant work lost after
settlement. They should contain the same durable logical operation ID, but one
does not replace the other.
Server deployment and npm publication are independent. A self-hosted server can
run repository source while its application consumers still resolve older npm
packages. Check the registry before deployment:
npm view '@grantex/sdk' versionnpm view '@grantex/x402' version
Published and registry verified: SDK 0.8.2 and x402 0.4.1 on
September 7, 2026. Registry publication is not inferred from the source tree, so treat
the registry as authoritative and verify exact versions before each deployment.
See Release
Status for the public artifact matrix.
Publishing is irreversible for an already consumed version. Run this only as
an npm maintainer of the @grantex scope, from a reviewed and clean main.
Direct publication requires npm publishing permission and either account 2FA or
an appropriately restricted publishing credential.
npm ci --prefix packages/sdk-tsnpm run typecheck --prefix packages/sdk-tsnpm test --prefix packages/sdk-tsnpm run build --prefix packages/sdk-tsnpm audit --prefix packages/sdk-ts --omit=devnpm ci --prefix packages/x402npm run typecheck --prefix packages/x402npm test --prefix packages/x402npm run build --prefix packages/x402npm audit --prefix packages/x402 --omit=devPush-Location packages/sdk-tstry { npm pack --dry-run } finally { Pop-Location }Push-Location packages/x402try { npm pack --dry-run } finally { Pop-Location }
Review the npm pack --dry-run file lists. Each package should contain its
compiled dist output, README.md, package metadata, and no keys, credentials,
environment files, test fixtures, or unrelated repository content.
After registry smoke passes, tag the exact reviewed commit and update
release-status.json, web/release-status.json, COMPATIBILITY.md, the root
README, release documentation, and public website notices in one release PR.
Do not describe the packages as published until the exact registry queries
above succeed.
Python 0.5.1 passed source import, Ruff, strict Mypy, Pytest (623 tests on
Python 3.12 and 3.9), distribution build, and Twine metadata checks before
upload:
The Go module path is a separate repository,
github.com/mishrasanjeev/grantex-go. Publishing a future version requires
copying the reviewed packages/go-sdk tree to that repository, rerunning
go test ./..., committing the exact source, and pushing an annotated new
version tag. A tag in the Grantex monorepo does not publish that module.Python 0.5.0 and Go v0.3.0 were published on 7 September 2026 and verified
from clean public-registry consumers. Python 0.5.1 was published on
15 September 2026; its installed PyPI wheel passed all 623 tests in a clean
environment. The steps remain here as the release runbook; they are not
instructions to overwrite those immutable versions.The guarded Publish primary
SDKs
workflow tests and builds the TypeScript SDK, x402 package, Python SDK, and Go
SDK once, uploads immutable distributions, and makes publication jobs consume
those exact artifacts. TypeScript and x402 publication are independently
selectable, so an unchanged x402 release is never republished just to ship a
new TypeScript SDK. Before the first run:
Create the GitHub sdk-release environment and require a human reviewer.
On npm, configure trusted-publisher records for both @grantex/sdk and
@grantex/x402 using repository mishrasanjeev/grantex, workflow
publish-primary-sdks.yml, environment sdk-release, and the npm publish
action. Do not add a long-lived npm token fallback.
On PyPI, configure the grantex project’s trusted publisher with the same
repository, workflow filename, and sdk-release environment.
Add GRANTEX_GO_RELEASE_TOKEN to the environment with write access limited
to mishrasanjeev/grantex-go; do not use a broadly scoped account token.
Protect main and the publication workflow through review and required CI.
Run the workflow only from reviewed main, type RELEASE_PRIMARY_SDKS, and
select only the packages with new, unpublished versions. The workflow fails
closed when trusted publishing or the Go credential is absent; a version bump
is not evidence that a registry release exists.TypeScript 0.7.1, x402 0.4.1, Python 0.6.1, and Go v0.4.1 were
separately published and verified on September 27, 2026. After publication,
verify from empty temporary projects rather than importing
the monorepo checkout:
npm view '@grantex/sdk@0.7.1' version dist.integrity --jsonnpm view '@grantex/x402@0.4.1' version dist.integrity --jsonpython -m pip download --index-url https://pypi.org/simple --no-deps --dest $env:TEMP 'grantex==0.6.1'go list -m -json 'github.com/mishrasanjeev/grantex-go@v0.4.1'
The workflow uses npm trusted publishing with OIDC and provenance instead of a
long-lived npm token. See npm’s official scoped public package
publishing
and trusted publishing
documentation before changing the release mechanism.