This specification allows AI Agents (using LLMs, function calling, or custom scripts) to programmatically schedule future on-chain payments using the PayWhen protocol.
PayWhen consists of:
- Solidity Smart Contract (
Scheduler.sol): Handles the locking of assets (USDC/EURC) and safe release or cancellation on-chain. - Relayer Service (Backend): Periodically checks scheduled orders and automatically executes them on-chain (paying gas fees on behalf of users).
- REST API: Tracks scheduled orders, monitors status, and acts as the interface for AI Agents.
- Network: ARC Testnet (Chain ID:
5042002) - Scheduler Contract Address:
0x0e13299e56724Ce459e621b370f89552F87ede8B - Supported Tokens:
- USDC:
0x3600000000000000000000000000000000000000(6 Decimals) - EURC:
0x3700000000000000000000000000000000000000(6 Decimals)
- USDC:
[
"function scheduleOrder(address token, address receiver, uint256 amount, uint256 executeAt) external returns (uint256)",
"function cancelOrder(uint256 orderId) external",
"function orders(uint256) external view returns (uint256 id, address sender, address receiver, address token, uint256 amount, uint256 executeAt, uint256 createdAt, bool executed, bool cancelled)"
]The backend provides a live endpoint showing full tool specs at:
GET https://api.paywhen.xyz/api/agent-spec
GET /api/status- Retrieve contract address, active state, and relayer gas balance.
GET /api/orders?address={sender_address}- List all scheduled orders for a specific sender cüzdan.
POST /api/orders- Register a newly scheduled order in the backend database.
- Body format:
{ "id": 12, "sender": "0xSenderAddress...", "receiver": "0xReceiverAddress...", "amount": 25.5, "token_symbol": "USDC", "token_address": "0x3600000000000000000000000000000000000000", "execute_at": 1783260000, "created_at": 1783173600, "status": "pending" }
POST /api/orders/{id}/cancel- Cancel the order inside the database (should be done alongside the on-chain cancellation).
Here is a complete example showing how an AI Agent can write a tool to schedule a future token transfer:
import time
import requests
from web3 import Web3
# 1. Setup Configurations
RPC_URL = "https://rpc.testnet.arc.network"
SCHEDULER_ADDRESS = "0x0e13299e56724Ce459e621b370f89552F87ede8B"
API_BASE_URL = "https://api.paywhen.xyz"
USDC_ADDRESS = "0x3600000000000000000000000000000000000000"
DECIMALS = 6
w3 = Web3(Web3.HTTPProvider(RPC_URL))
# ABI definitions
SCHEDULER_ABI = [...]
ERC20_ABI = [...]
def schedule_payment_agent_tool(private_key, receiver, amount, delay_seconds):
"""
AI Agent Tool: Schedules a future token payment.
"""
account = w3.eth.account.from_key(private_key)
sender = account.address
# Calculate execution timestamp
execute_at = int(time.time()) + delay_seconds
token_amount_raw = int(amount * (10 ** DECIMALS))
# 2. Token Approval
token_contract = w3.eth.contract(address=USDC_ADDRESS, abi=ERC20_ABI)
allowance = token_contract.functions.allowance(sender, SCHEDULER_ADDRESS).call()
if allowance < token_amount_raw:
print("Approving token spend...")
tx = token_contract.functions.approve(SCHEDULER_ADDRESS, token_amount_raw).build_transaction({
'from': sender,
'nonce': w3.eth.get_transaction_count(sender),
'gasPrice': w3.eth.gas_price
})
signed_tx = w3.eth.account.sign_transaction(tx, private_key)
w3.eth.send_raw_transaction(signed_tx.rawTransaction)
w3.eth.wait_for_transaction_receipt(signed_tx.hash)
# 3. Schedule Order on Smart Contract
scheduler_contract = w3.eth.contract(address=SCHEDULER_ADDRESS, abi=SCHEDULER_ABI)
tx = scheduler_contract.functions.scheduleOrder(
USDC_ADDRESS,
receiver,
token_amount_raw,
execute_at
).build_transaction({
'from': sender,
'nonce': w3.eth.get_transaction_count(sender),
'gasPrice': w3.eth.gas_price
})
signed_tx = w3.eth.account.sign_transaction(tx, private_key)
tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
receipt = w3.eth.wait_for_transaction_receipt(signed_tx.hash)
# 4. Extract generated orderId from logs
# Retrieve the orderId from the OrderScheduled log events...
order_id = 1 # (Extract from receipt.logs)
# 5. Sync to PayWhen database via REST API
payload = {
"id": order_id,
"sender": sender.lower(),
"receiver": receiver.lower(),
"amount": amount,
"token_symbol": "USDC",
"token_address": USDC_ADDRESS,
"execute_at": execute_at,
"created_at": int(time.time()),
"status": "pending"
}
response = requests.post(f"{API_BASE_URL}/api/orders", json=payload)
if response.status_code == 201:
print(f"Payment scheduled successfully! Order ID: #{order_id}")
return True
return False