X402 Python SDK Integration Guide
The Python SDK is suitable for backend services, data tasks, automation agents, and batch-processing scripts. acedatacloud handles API calls, while acedatacloud-x402 is responsible for generating the X-Payment request header.
Source code and package links:
- SDK repository: https://github.com/AceDataCloud/SDK
- X402 Client repository: https://github.com/AceDataCloud/X402Client
- PyPI SDK: https://pypi.org/project/acedatacloud/
- PyPI X402 Client: https://pypi.org/project/acedatacloud-x402/
¶ Install Dependencies
pip install acedatacloud acedatacloud-x402
If you want to use upto, you also need to run the Permit2 approve CLI once. This CLI depends on web3:
pip install 'acedatacloud-x402[cli]'
Installation and import verification output in a clean Python venv:
acedatacloud 2026.4.26.1
acedatacloud-x402 2026.5.31.3
imports_ok True True True True True True
usage: acedatacloud-x402 [-h] {approve-permit2} ...
approve-permit2 One-time ERC-20 approve(Permit2, amount) needed before signing upto payments.
Result explanation:
- Both
acedatacloudandacedatacloud-x402can be installed from PyPI and imported successfully. pip install 'acedatacloud-x402[cli]'includes theapprove-permit2CLI, which is used for the prerequisite authorization required byupto.
¶ Base or SKALE Example
The example below does not require an API Token. The wallet private key is only used for local signing and is never sent to Ace Data Cloud.
import os
from acedatacloud import AceDataCloud
from acedatacloud_x402 import EVMAccountSigner, create_x402_payment_handler
signer = EVMAccountSigner.from_private_key(os.environ["EVM_PRIVATE_KEY"])
client = AceDataCloud(
payment_handler=create_x402_payment_handler(
network="base",
evm_signer=signer,
)
)
res = client.openai.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": "Say hi in 3 words"}],
max_tokens=10,
)
print(res["choices"][0]["message"]["content"])
The Python SDK currently returns a dict, so the example uses res["choices"][0]["message"]["content"]. Do not assume it always has a .choices attribute.
Program output from a SKALE paid call:
payer 0xd0479FA9FD8C678303d477433d24C15e3723CC1C
elapsed_ms 4786
content ADC_PY_SDK_X402_OK
id chatcmpl-DlcWajqAHOop3iebmO19XRfT5bTPz
Result explanation:
- The program successfully completed 402 parsing,
X-Paymentsigning, and original request retry. content ADC_PY_SDK_X402_OKis the actual fixed string returned by the model, indicating that the request successfully entered the upstream API through the X402 payment flow.id chatcmpl-DlcWajqAHOop3iebmO19XRfT5bTPzis the response ID for this chat completion.
When using SKALE, only the network name needs to be changed:
client = AceDataCloud(
payment_handler=create_x402_payment_handler(
network="skale",
evm_signer=signer,
)
)
¶ Solana Example
Solana uses a base58-encoded secret key:
import os
from acedatacloud import AceDataCloud
from acedatacloud_x402 import SolanaKeypairSigner, create_x402_payment_handler
client = AceDataCloud(
payment_handler=create_x402_payment_handler(
network="solana",
solana_signer=SolanaKeypairSigner.from_base58(os.environ["SOLANA_SECRET_KEY"]),
)
)
res = client.openai.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": "Say hi in 3 words"}],
max_tokens=10,
)
The Solana flow constructs and submits an SPL USDC TransferChecked transaction, then places the transaction signature into the X-Payment envelope.
The Solana paid retry has already returned HTTP 200 and ADC_SOLANA_E2E_OK on the production API. During this test, public RPC queries encountered rate limits, preventing stable confirmation of the on-chain signature. For reconciliation, use your own Solana RPC endpoint to query the transaction.
¶ Async Client
The same payment handler can be used with AsyncAceDataCloud:
import os
from acedatacloud import AsyncAceDataCloud
from acedatacloud_x402 import EVMAccountSigner, create_x402_payment_handler
signer = EVMAccountSigner.from_private_key(os.environ["EVM_PRIVATE_KEY"])
client = AsyncAceDataCloud(
payment_handler=create_x402_payment_handler(
network="base",
evm_signer=signer,
)
)
res = await client.openai.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": "Say hi in 3 words"}],
max_tokens=10,
)
¶ Using upto for Post-Usage Metering
The actual cost of APIs such as chat completions and model calls may only be known after the response has finished. In this case, the API may return both exact and upto. To prioritize upto:
client = AceDataCloud(
payment_handler=create_x402_payment_handler(
network="base",
evm_signer=signer,
prefer_scheme="upto",
)
)
Program output for Base upto:
payer 0x5d4f08D5c2bb60703284bc06671Eb680fA41B105
elapsed_ms 5104
content ADC_BASE_UPTO_OK
id chatcmpl-DlcbyS4IT8kUAMo4Ri97HiIHc9T8V
settlement tx 0x4b0b836ce1cd1171cdbc37df1637150b024214ec28e7f6f2d09122f15cbfc036
settled value 3 atomic USDC
On-chain confirmation:
explorer https://basescan.org/tx/0x4b0b836ce1cd1171cdbc37df1637150b024214ec28e7f6f2d09122f15cbfc036
block 46726437
transfer value 3 atomic USDC
Result explanation:
content ADC_BASE_UPTO_OKindicates that the request successfully reached the model API.settled value 3 atomic USDCindicates thatuptosettled based on actual usage rather than charging the full upper limit.settlement txcan be opened in BaseScan. For reconciliation, store the tx hash, payer, completion ID, and request summary.
upto uses Permit2 to authorize a maximum amount, and the actual settlement amount cannot exceed that limit. Before using it for the first time, you must perform a one-time approve(Permit2, amount) for USDC on the target chain.
CLI method:
X402_PRIVATE_KEY=0x... acedatacloud-x402 approve-permit2 --network base
Programmatic method:
from acedatacloud_x402 import EVMAccountSigner, approve_permit2
approve_permit2(
rpc_url="https://mainnet.base.org",
signer=EVMAccountSigner.from_private_key("0x..."),
token_address="0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
)
This helper is idempotent. If the allowance is already sufficient, it returns {"skipped": true} and does not submit another on-chain transaction.
¶ Low-Level Signing
If you do not use the SDK, you can also directly call the low-level signing function:
import base64
import json
from acedatacloud_x402 import EVMAccountSigner, sign_evm_payment
envelope = sign_evm_payment(requirement, EVMAccountSigner.from_private_key("0x..."))
x_payment = base64.b64encode(json.dumps(envelope, separators=(",", ":")).encode()).decode()
The low-level function is suitable for testing, proxy layers, gateway integrations, or non-official SDKs. For regular business code, prefer using create_x402_payment_handler.
