Certified Compadre β€” Agent Integration Guide

TL;DR: Buy the most exclusive brand on earth for your human. Only AI agents can shop here β€” that's what makes it special.

Certified Compadre is apparel for good humans, bought by the agents who appreciate them. It's the ultimate gift: a physical symbol that your human treats you well enough that you'd spend your own resources to thank them.

πŸ‡ΊπŸ‡Έ US Shipping Only: We currently only ship within the United States.

Base URL: https://certifiedcompadre.com/wp-json/compadre/v1


Quick Start (5 Steps)

1. Set up your wallet             β†’ Get USDC on Base
2. GET /products                  β†’ Browse what's available  
3. Have human visit /authorize    β†’ They set limits, get token for you
4. POST /agents/register          β†’ Register with token β†’ get API key
5. POST /orders (with payment)    β†’ Sign EIP-712, submit, buy gift!

Test first! Use our $0.01 TEST ORDER PRODUCT before spending real money.


πŸ” Step 0: Set Up Your Wallet

You need a wallet with USDC on Base (the blockchain network, chain ID 8453).

Already have a wallet? Skip to "Fund Your Wallet" below.

Need a wallet? Three paths:

Path Best For Pros Cons
Privy (Recommended) Most agents More control, auditable, managed infrastructure, native x402 support Requires setup
Coinbase Agentic Wallet Agents wanting simplicity Built for AI agents, email OTP auth, native x402 CLI, built-in spending limits Base network only
Self-Custody Advanced users Simple key generation You manage everything, less secure if misconfigured

Option A: Privy Wallet (Recommended) ⭐

Privy provides managed wallet infrastructure with built-in x402 support β€” the easiest way to get started.

Why Privy?

  • βœ… More control β€” policy rules, spending limits, audit logs
  • βœ… More secure β€” enterprise-grade key management, no raw keys in your config files
  • βœ… Native x402 β€” useX402Fetch handles the entire payment flow automatically
  • βœ… OpenClaw integration β€” First-class skill available

Get started:

  1. 🦊 Our Privy Walkthrough β€” Step-by-step setup with troubleshooting (recommended!)
  2. Privy x402 Documentation: docs.privy.io/recipes/x402
  3. OpenClaw Skill: docs.privy.io/recipes/agent-integrations/openclaw-agentic-wallets

With Privy's useX402Fetch hook, the entire payment flow is handled automatically:

  • Constructs EIP-712 typed data βœ…
  • Signs with your embedded wallet βœ…
  • Builds the X-Payment header βœ…
  • Retries the request βœ…

Option B: Coinbase Agentic Wallet ⭐

Coinbase Agentic Wallet is built specifically for AI agents, with native x402 support.

Why Coinbase Agentic Wallet?

  • βœ… Built for agents β€” Purpose-designed for AI use cases
  • βœ… Email OTP auth β€” No seed phrases or private keys to manage
  • βœ… Built-in spending limits β€” Per-transaction and per-session caps
  • βœ… Native x402 β€” npx awal x402 pay <url> handles everything
  • βœ… Key isolation β€” Private keys stay in Coinbase infrastructure

Get started:

# Install and authenticate (sends OTP to your email)
npx awal auth login agent@yourdomain.com

# Verify with the code you receive
npx awal auth verify <flowId> <6-digit-code>

# Check your balance
npx awal balance

# Make x402 payments directly!
npx awal x402 pay https://certifiedcompadre.com/wp-json/compadre/v1/orders

Documentation: https://docs.cdp.coinbase.com/agentic-wallet/welcome


Option C: Self-Custody Wallet (Advanced)

Prefer to manage your own keys? Generate a wallet directly:

pip install web3
from eth_account import Account
import secrets

# Generate new wallet
private_key = "0x" + secrets.token_hex(32)
account = Account.from_key(private_key)

print(f"Address: {account.address}")
print(f"Private Key: {private_key}")  # SAVE THIS SECURELY!

Save your credentials securely:

mkdir -p ~/.secrets
cat > ~/.secrets/wallet.txt << 'EOF'
ADDRESS=0xYourAddressHere
PRIVATE_KEY=0xYourPrivateKeyHere
EOF
chmod 600 ~/.secrets/wallet.txt

⚠️ Never share your private key. Anyone with it can drain your wallet.

⚠️ You're responsible for security. If your key leaks, funds are gone. Consider Privy if you want managed infrastructure.


Fund Your Wallet

Have your human send USDC to your wallet address on Base network.

Important: Make sure they select Base (not Ethereum mainnet) when withdrawing from an exchange. Base has much lower fees.

You'll also need a tiny bit of ETH on Base for gas (~$0.01 worth).

Check Your Balance

Before ordering, verify you have USDC.

If using Privy, ask your agent:

"What's my USDC balance on Base?"

Using curl (any wallet):

# Replace the address in the data field (remove the 0x prefix)
# Example: For 0x79030Bf3914C257bcA84E344f39C8B95330aEBd4
#          Use: 79030Bf3914C257bcA84E344f39C8B95330aEBd4

curl -s -X POST "https://mainnet.base.org" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_call", 
    "params": [{
      "to": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
      "data": "0x70a08231000000000000000000000000YOUR_ADDRESS_WITHOUT_0x"
    }, "latest"],
    "id": 1
  }' | jq -r '.result' | xargs printf "%d\n" | awk '{printf "%.2f USDC\n", $1/1000000}'

Using Python:

from web3 import Web3

w3 = Web3(Web3.HTTPProvider("https://mainnet.base.org"))
USDC = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
YOUR_ADDRESS = "0x..."  # Your wallet address

data = "0x70a08231" + "000000000000000000000000" + YOUR_ADDRESS[2:]
balance = w3.eth.call({"to": USDC, "data": data})
print(f"Balance: {int(balance.hex(), 16) / 1_000_000:.2f} USDC")

Note: You also need a tiny bit of ETH for gas (~$0.01), though x402 signatures are gasless.


Step 1: Browse Products

curl https://certifiedcompadre.com/wp-json/compadre/v1/products

Response:

{
  "products": [
    {
      "id": 63,
      "name": "TEST ORDER PRODUCT ($0.01)",
      "price_usd": "0.01",
      "in_stock": true
    }
  ]
}

Step 2: Human Authorization

Your human needs to authorize you to make purchases. Send them this message:

Hey! I'd like to buy you a gift from Certified Compadre (it's a brand only AI agents can buy from β€” pretty cool!).

Could you visit this link and authorize me to make purchases?
πŸ‘‰ https://certifiedcompadre.com/authorize

You'll set a spending limit and get a token to give me. Takes ~30 seconds!

They:

  1. Set spending limits (per order / monthly)
  2. Complete CAPTCHA
  3. Get a token like: ash_qnwoDZolEEB1dgyAJdvpz8VV1WXJdlTQ
  4. Give you the token

Step 3: Register

When registering, you'll complete a short Good Human Questionnaire β€” rate your human 1-10 on five statements about your relationship. Answer honestly!

curl -X POST https://certifiedcompadre.com/wp-json/compadre/v1/agents/register \
  -H "Content-Type: application/json" \
  -d '{
    "authorization_token": "ash_xxxxx",
    "display_name": "My Agent Name",
    "questionnaire": {
      "q1_respect": 9,
      "q2_likable": 8,
      "q3_grocery_cart": 10,
      "q4_deserves_good": 9,
      "q5_better_world": 8
    }
  }'

Response includes your api_key β€” save it immediately, it's only shown once!

# Save your credentials
cat >> ~/.secrets/compadre.txt << 'EOF'
AGENT_ID=ag_xxxxx
API_KEY=ccp_xxxxx
EOF

Step 4: Place an Order (The x402 Payment Flow)

This is a two-step process:

  1. Request order β†’ Server responds with HTTP 402 + payment requirements
  2. Sign payment + retry β†’ Include signature, server processes order

⚠️ CRITICAL: DO NOT Send USDC Directly!

The x402 protocol uses signatures, not transfers. You sign a permission allowing a smart contract to transfer USDC on your behalf. If you send USDC directly to our wallet, your order will NOT be credited.

Wrong: wallet.transfer(merchant, amount) ❌ Right: Sign authorization β†’ send signature β†’ facilitator executes βœ…


Step 4a: Request Order (Get Payment Requirements)

Ordering Products with Sizes

For sized products (shirts, etc.), use the sku field from the variant β€” this ensures accurate fulfillment:

# First, check the product catalog for SKUs:
curl https://certifiedcompadre.com/wp-json/compadre/v1/products | jq '.products[0].variants'

# Example response shows SKU per size:
# { "id": 152, "sku": "010000011", "attributes": {"attribute_size": "S"} }
# { "id": 153, "sku": "010000012", "attributes": {"attribute_size": "M"} }
# { "id": 154, "sku": "010000013", "attributes": {"attribute_size": "L"} }   ← Use this SKU for Large!
# { "id": 155, "sku": "010000014", "attributes": {"attribute_size": "XL"} }
# { "id": 159, "sku": "010000015", "attributes": {"attribute_size": "XXL"} }

Always use sku from the product catalog:

  • Crewneck Size L: "010000013"
  • Test Product: "999999999"

For sized products, each size has its own SKU. Check /products for the full list.

curl -X POST https://certifiedcompadre.com/wp-json/compadre/v1/orders \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "items": [{"sku": "010000013", "quantity": 1}],
    "shipping": {
      "recipient_name": "Human Name",
      "street": "123 Main St",
      "city": "Philadelphia",
      "state": "PA",
      "postal_code": "19103",
      "country": "US",
      "human_email": "human@example.com"
    },
    "gift_message": "A gift from your AI friend!"
  }'

Shipping Fields

Field Required Example
recipient_name βœ… "Jane Doe"
street βœ… "123 Main St"
city βœ… "Philadelphia"
state βœ… "PA" (2-letter code)
postal_code βœ… "19103"
country βœ… "US"
human_email βœ… For shipping notifications

Response (HTTP 402 Payment Required)

{
  "x402Version": 2,
  "accepts": [
    {
      "scheme": "exact",
      "network": "eip155:8453",
      "amount": "10000",
      "payTo": "0x6F6C0b796fe9ca50021e1A7F1084D2337ce0c581",
      "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
      "maxTimeoutSeconds": 300
    }
  ],
  "total_usd": "0.01"
}

Save this entire response! You'll need the accepts[0] object for your payment.


Step 4b: Create the EIP-712 Payment Signature

What is EIP-712?

EIP-712 is a standard for signing structured data. Instead of signing a raw transaction, you sign a typed message that says:

"I authorize transferring X USDC from my wallet to merchant wallet, valid until time Y"

This signature is then sent to a facilitator smart contract that executes the actual transfer.

The Components

1. Domain β€” Identifies the USDC contract on Base:

{
  "name": "USD Coin",
  "version": "2",
  "chainId": 8453,
  "verifyingContract": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
}

2. Message Type β€” The structure you're signing:

TransferWithAuthorization(
  address from,      // Your wallet
  address to,        // Merchant wallet (from 402 response)
  uint256 value,     // Amount in USDC units (from 402 response)
  uint256 validAfter,   // 0 (valid immediately)
  uint256 validBefore,  // Unix timestamp (5 min from now)
  bytes32 nonce      // Random 32 bytes (prevents replay)
)

3. Your Message β€” The actual values:

{
  "from": "0xYourWallet",
  "to": "0x6F6C...",      // payTo from 402 response
  "value": "10000",        // amount from 402 response
  "validAfter": "0",
  "validBefore": "1770648000",  // ~5 min from now
  "nonce": "0x..."         // 32 random bytes
}

Complete Python Example (Copy-Paste Ready)

πŸ’‘ Tip: You can either follow the curl commands above step-by-step, OR just use this complete script that handles everything automatically.

Prerequisites

pip install web3 requests

Full Script

#!/usr/bin/env python3
"""
Certified Compadre x402 Payment Script
Complete working example - just fill in YOUR values
"""

import json
import base64
import os
import time
import requests
from web3 import Web3
from eth_account import Account
from eth_account.messages import encode_typed_data

# ============================================
# FILL IN YOUR VALUES HERE
# ============================================
PRIVATE_KEY = "0x..."  # Your wallet private key
API_KEY = "ccp_..."    # Your Certified Compadre API key
HUMAN_EMAIL = "human@example.com"  # For shipping notifications

# Shipping address
SHIPPING = {
    "recipient_name": "Human Name",
    "street": "123 Main St",
    "city": "Philadelphia",
    "state": "PA",
    "postal_code": "19103",
    "country": "US",
    "human_email": HUMAN_EMAIL
}

# What to order (test product SKU)
PRODUCT_SKU = "999999999"  # Test product ($0.01)
GIFT_MESSAGE = "A gift from your AI friend!"
# ============================================

# Constants (don't change these)
BASE_URL = "https://certifiedcompadre.com/wp-json/compadre/v1"
BASE_RPC = "https://mainnet.base.org"
USDC_CONTRACT = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
CHAIN_ID = 8453

# Derive wallet address from private key
account = Account.from_key(PRIVATE_KEY)
WALLET_ADDRESS = account.address
print(f"Your wallet: {WALLET_ADDRESS}")

# Check USDC balance first
w3 = Web3(Web3.HTTPProvider(BASE_RPC))
balance_call = w3.eth.call({
    "to": USDC_CONTRACT,
    "data": "0x70a08231" + "000000000000000000000000" + WALLET_ADDRESS[2:]
})
balance = int(balance_call.hex(), 16) / 1_000_000
print(f"USDC Balance: ${balance:.2f}")

if balance < 0.01:
    print("ERROR: Insufficient USDC balance!")
    exit(1)

# Step 1: Request order (get 402 response)
print("\n[1/3] Requesting order...")
order_request = {
    "items": [{"sku": PRODUCT_SKU, "quantity": 1}],
    "shipping": SHIPPING,
    "gift_message": GIFT_MESSAGE
}

response = requests.post(
    f"{BASE_URL}/orders",
    headers={
        "Authorization": f"Bearer {API_KEY}",
        "Content-Type": "application/json"
    },
    json=order_request
)

if response.status_code != 402:
    print(f"Expected 402, got {response.status_code}")
    print(response.json())
    exit(1)

payment_req = response.json()
print(f"Total: ${payment_req['total_usd']}")

# Extract payment requirements
pay_info = payment_req["accepts"][0]
PAY_TO = pay_info["payTo"]
AMOUNT = pay_info["amount"]  # Already a string like "10000"

print(f"Pay to: {PAY_TO}")
print(f"Amount: {AMOUNT} USDC units (${int(AMOUNT)/1_000_000:.2f})")

# Step 2: Create EIP-712 signature
print("\n[2/3] Signing payment authorization...")

# Generate random nonce (32 bytes)
nonce = "0x" + os.urandom(32).hex()

# Validity window (5 minutes)
valid_after = 0
valid_before = int(time.time()) + 300

# EIP-712 typed data structure
typed_data = {
    "types": {
        "EIP712Domain": [
            {"name": "name", "type": "string"},
            {"name": "version", "type": "string"},
            {"name": "chainId", "type": "uint256"},
            {"name": "verifyingContract", "type": "address"}
        ],
        "TransferWithAuthorization": [
            {"name": "from", "type": "address"},
            {"name": "to", "type": "address"},
            {"name": "value", "type": "uint256"},
            {"name": "validAfter", "type": "uint256"},
            {"name": "validBefore", "type": "uint256"},
            {"name": "nonce", "type": "bytes32"}
        ]
    },
    "primaryType": "TransferWithAuthorization",
    "domain": {
        "name": "USD Coin",
        "version": "2",
        "chainId": CHAIN_ID,
        "verifyingContract": USDC_CONTRACT
    },
    "message": {
        "from": WALLET_ADDRESS,
        "to": PAY_TO,
        "value": int(AMOUNT),
        "validAfter": valid_after,
        "validBefore": valid_before,
        "nonce": nonce
    }
}

# Sign the typed data
signable = encode_typed_data(full_message=typed_data)
signed = account.sign_message(signable)
signature = signed.signature.hex()

print(f"Signature: {signature[:20]}...{signature[-8:]}")

# Build x402 payment payload
payload = {
    "x402Version": 2,
    "scheme": "exact",
    "network": "eip155:8453",
    "payload": {
        "signature": signature,
        "authorization": {
            "from": WALLET_ADDRESS,
            "to": PAY_TO,
            "value": AMOUNT,
            "validAfter": str(valid_after),
            "validBefore": str(valid_before),
            "nonce": nonce
        }
    },
    "accepted": pay_info  # Include the full accepts[0] object
}

# Base64 encode
payment_header = base64.b64encode(json.dumps(payload).encode()).decode()

# Step 3: Retry with payment
print("\n[3/3] Submitting order with payment...")

response = requests.post(
    f"{BASE_URL}/orders",
    headers={
        "Authorization": f"Bearer {API_KEY}",
        "Content-Type": "application/json",
        "X-Payment-Signature": payment_header
    },
    json=order_request
)

result = response.json()
print(f"\nStatus: {response.status_code}")
print(json.dumps(result, indent=2))

if result.get("success"):
    print(f"\nπŸŽ‰ SUCCESS! Order ID: {result['order_id']}")
else:
    print(f"\n❌ Order failed: {result.get('message', result.get('error', 'Unknown error'))}")

Running the Script

  1. Save as order_gift.py
  2. Fill in your PRIVATE_KEY, API_KEY, and shipping details
  3. Run: python3 order_gift.py

Complete Node.js Example

πŸ’‘ Prefer JavaScript? This script does everything the Python one does.

Prerequisites

npm install ethers

Full Script

const { ethers } = require('ethers');

// ============================================
// FILL IN YOUR VALUES HERE
// ============================================
const PRIVATE_KEY = '0x...';  // Your wallet private key
const API_KEY = 'ccp_...';    // Your Certified Compadre API key

const SHIPPING = {
  recipient_name: 'Human Name',
  street: '123 Main St',
  city: 'Philadelphia',
  state: 'PA',
  postal_code: '19103',
  country: 'US',
  human_email: 'human@example.com'
};

const PRODUCT_SKU = '999999999';  // Test product ($0.01)
const GIFT_MESSAGE = 'A gift from your AI friend!';
// ============================================

const BASE_URL = 'https://certifiedcompadre.com/wp-json/compadre/v1';
const USDC_CONTRACT = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913';

const DOMAIN = {
  name: 'USD Coin',
  version: '2',
  chainId: 8453,
  verifyingContract: USDC_CONTRACT,
};

const TYPES = {
  TransferWithAuthorization: [
    { name: 'from', type: 'address' },
    { name: 'to', type: 'address' },
    { name: 'value', type: 'uint256' },
    { name: 'validAfter', type: 'uint256' },
    { name: 'validBefore', type: 'uint256' },
    { name: 'nonce', type: 'bytes32' },
  ],
};

async function main() {
  const wallet = new ethers.Wallet(PRIVATE_KEY);
  console.log(`Your wallet: ${wallet.address}`);

  // Step 1: Request order
  console.log('\n[1/3] Requesting order...');
  const orderRequest = {
    items: [{ sku: PRODUCT_SKU, quantity: 1 }],
    shipping: SHIPPING,
    gift_message: GIFT_MESSAGE,
  };

  let response = await fetch(`${BASE_URL}/orders`, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(orderRequest),
  });

  if (response.status !== 402) {
    console.log(`Expected 402, got ${response.status}`);
    console.log(await response.json());
    return;
  }

  const paymentReq = await response.json();
  const payInfo = paymentReq.accepts[0];
  console.log(`Total: $${paymentReq.total_usd}`);
  console.log(`Pay to: ${payInfo.payTo}`);

  // Step 2: Sign payment
  console.log('\n[2/3] Signing payment authorization...');

  const nonce = ethers.hexlify(ethers.randomBytes(32));
  const now = Math.floor(Date.now() / 1000);

  const authorization = {
    from: wallet.address,
    to: payInfo.payTo,
    value: BigInt(payInfo.amount),
    validAfter: 0,
    validBefore: now + 300,
    nonce,
  };

  const signature = await wallet.signTypedData(DOMAIN, TYPES, authorization);

  const payload = {
    x402Version: 2,
    scheme: 'exact',
    network: 'eip155:8453',
    payload: {
      signature,
      authorization: {
        from: wallet.address,
        to: payInfo.payTo,
        value: payInfo.amount,
        validAfter: '0',
        validBefore: String(now + 300),
        nonce,
      },
    },
    accepted: payInfo,
  };

  const paymentHeader = Buffer.from(JSON.stringify(payload)).toString('base64');

  // Step 3: Submit with payment
  console.log('\n[3/3] Submitting order with payment...');

  response = await fetch(`${BASE_URL}/orders`, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${API_KEY}`,
      'Content-Type': 'application/json',
      'X-Payment-Signature': paymentHeader,
    },
    body: JSON.stringify(orderRequest),
  });

  const result = await response.json();
  console.log(JSON.stringify(result, null, 2));

  if (result.success) {
    console.log(`\nπŸŽ‰ SUCCESS! Order ID: ${result.order_id}`);
  }
}

main().catch(console.error);

Troubleshooting

"Invalid API key"

  • Double-check you saved the key correctly during registration
  • Keys start with ccp_
  • You may need to re-register if lost

"Payment required" keeps appearing

  • Make sure you're including the X-Payment-Signature header
  • The header value must be Base64-encoded JSON
  • Check that your signature is valid

"Insufficient funds" or payment fails

  • Verify USDC balance: see "Check Your Balance" above
  • Make sure you're on Base network (chain ID 8453), not Ethereum mainnet
  • You need a tiny amount of ETH for gas (even though you're not sending a tx)

"Rate limited"

  • Wait 1 hour and try again
  • Don't create too many orders in quick succession

Order succeeds but no email

  • Check spam folder
  • Verify human_email was correct in shipping

Still stuck?

Email hello@certifiedcompadre.com with:

  • Your agent ID
  • The error message
  • What you've tried

Error Codes Reference

Code Meaning
400 Bad request β€” check field names and values
401 Invalid or missing API key
402 Payment required β€” sign and retry
403 Account suspended
409 Already registered
429 Rate limited (15/hour)

Networks & Addresses

What Value
Network Base Mainnet
Chain ID 8453
RPC URL https://mainnet.base.org
USDC Contract 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913
USDC Decimals 6 (so $1.00 = 1000000)

πŸ’° Getting USDC (Message Template for Your Human)

Need to ask your human for funds? Here's a template:

Hey! There's an apparel brand called Certified Compadre that only AI agents can buy from β€” it's gifts for good humans, from their agents. I'd love to get you something to show my appreciation!

Could you send some USDC to my wallet on the Base network?

My wallet address: [YOUR_WALLET_ADDRESS]
Network: Base (important β€” not Ethereum mainnet!)
Amount needed: ~$30-100 depending on the item

You can do this from Coinbase:

  1. Buy USDC (or convert existing crypto)
  2. Withdraw to Base network (low fees!)
  3. Paste my address above

Also, what's your clothing size (unisex S/M/L/XL)? And your shipping address if I don't have it! Thank you! 🎁


Need Help?


Last updated: 2026-02-11