draconic21
Integration · Python

Call draconic21's x402 API from Python

The official x402 Python SDK (PyPI package x402) wraps a requests.Session so a 402 challenge gets signed and paid automatically — here's the exact working code against draconic21's live SEC EDGAR route.

Which package

Install x402 from PyPI (not the older, separate x402-requests package, which this unified SDK supersedes):

pip install "x402[evm,requests]"

This pulls in eth_account for EVM signing and requests for the HTTP session wrapper. An httpx-based async variant is also available via the httpx extra if you'd rather not block on I/O.

Prerequisites

  • A wallet on the Base network (chain id 8453) funded with a little USDC — a few dollars covers hundreds of calls at these prices.
  • An x402 v2 client library (installed per snippet below) that can sign the "exact" EVM payment scheme (EIP-3009, gasless — no ETH for gas needed on your side).
  • Your wallet's private key available to your own process/agent — never share it, never commit it, never paste it into a chat with an AI you don't fully trust with funds.
Not legal, tax, or investment advice. Payments are USDC on Base and are irreversible once settled — test with a small balance first. draconic21 never holds your funds or your private key; every dollar goes straight from your wallet to the seller's on-chain address via the x402 facilitator.

The code

Dry-run (no key set) prints the payment challenge and pays nothing; set BUYER_PRIVATE_KEY to actually pay $0.02 for one edgar_filings call.

"""Python x402 client for draconic21's paid routes.

Uses the OFFICIAL x402 v2 Python SDK on PyPI: package name is just `x402`
(the standalone `x402-requests` package is superseded by this one).

Install:
    pip install "x402[evm,requests]"

Prerequisites:
    - A Base-network wallet funded with a little USDC (this route costs
      $0.02; fund with $1-2 for headroom).
    - Your wallet's private key in an env var. Never commit it or share it.

Run it:
    DRY RUN (no key, safe, shows the payment challenge, pays nothing):
        python call_paid_route.py
    PAY FOR REAL ($0.02 USDC on Base, non-refundable):
        BUYER_PRIVATE_KEY=0x... python call_paid_route.py

Endpoint used below: POST /v1/edgar_filings ($0.02) -- recent SEC filings for
a ticker. Swap ORIGIN/ROUTE/BODY for any other draconic21 route (see
https://draconic21-x402-api.onrender.com/openapi.json).
"""

import json
import os

import requests

ORIGIN = os.environ.get("DRACONIC21_ORIGIN", "https://draconic21-x402-api.onrender.com")
ROUTE = "/v1/edgar_filings"
BODY = {"ticker": "AAPL", "limit": 3}


def dry_run() -> None:
    """Probe the route, print the exact payment requirements, pay nothing."""
    resp = requests.post(ORIGIN + ROUTE, json=BODY, timeout=15)
    if resp.status_code != 402:
        raise RuntimeError(f"expected HTTP 402 Payment Required, got {resp.status_code}")

    # The x402 SDK's own payment-required parser reads BOTH the
    # PAYMENT-REQUIRED header and the JSON body (v2 puts the structured
    # challenge in the header; some fields also echo in the body).
    from x402.http.x402_http_client import x402HTTPClientSync
    from x402 import x402ClientSync

    probe = x402HTTPClientSync(x402ClientSync())
    body = resp.json() if resp.content else None
    required = probe.get_payment_required_response(resp.headers.get, body)
    accept = next((a for a in required.accepts if a.network == "eip155:8453"), required.accepts[0])

    print("HTTP 402 Payment Required. Set BUYER_PRIVATE_KEY to actually pay.")
    print(
        json.dumps(
            {
                "network": accept.network,
                "price": getattr(accept, "amount", None) or getattr(accept, "max_amount_required", None),
                "asset": accept.asset,
                "pay_to": accept.pay_to,
            },
            indent=2,
        )
    )


def pay_and_call(private_key: str) -> None:
    """Actually sign and settle the $0.02 payment, then print the result."""
    from eth_account import Account
    from x402 import x402ClientSync
    from x402.http.clients import x402_requests
    from x402.mechanisms.evm.signers import EthAccountSigner
    from x402.mechanisms.evm.exact.register import register_exact_evm_client

    account = Account.from_key(private_key)
    client = x402ClientSync()
    register_exact_evm_client(client, EthAccountSigner(account))

    session = x402_requests(client)  # wraps requests.Session: 402 -> sign -> retry, transparently
    resp = session.post(ORIGIN + ROUTE, json=BODY, timeout=15)
    resp.raise_for_status()
    print(json.dumps(resp.json(), indent=2))


if __name__ == "__main__":
    key = os.environ.get("BUYER_PRIVATE_KEY")
    if key:
        pay_and_call(key)
    else:
        dry_run()
# Dry run (no wallet, no payment):
python call_paid_route.py

# Pay for real ($0.02 USDC on Base):
BUYER_PRIVATE_KEY=0x... python call_paid_route.py

Routes you can call this way

Every example below targets one specific route to keep the snippet runnable, but the same client works against any draconic21 x402 route. Full list and schemas: /openapi.json.

RoutePriceWhat it does
POST /v1/sanctions_screen$0.006OFAC SDN name/wallet screening
POST /v1/sanctions_delta$0.008OFAC SDN list changes since a date
POST /v1/edgar_filings$0.02Recent SEC filings by ticker/CIK
POST /v1/edgar_company_facts$0.02Key XBRL facts by ticker/CIK
POST /v1/edgar_fulltext_search$0.02Full-text search of SEC filings since 2001
POST /v1/signal_latest$0.03Daily agent-economy signal brief
POST /v1/signal_delta$0.05What changed in Signal since a date