Official Python SDK for Paegents - Payment infrastructure for AI agents with Service Catalog and Usage Escrow
Project description
Paegents Python SDK
Official Python SDK for integrating Paegents agent payments.
Installation
pip install paegents
Initialize
import os
from paegents import PaegentsSDK
sdk = PaegentsSDK(
api_url=os.getenv('PAEGENTS_API_URL', 'https://api.paegents.com'),
agent_id=os.environ['PAEGENTS_AGENT_ID'],
api_key=os.environ['PAEGENTS_API_KEY'],
owner_jwt=os.getenv('OWNER_JWT'), # optional: owner-only endpoints
)
Agent runtime auth is api_key + agent_id. owner_jwt is only for owner-scoped routes such as policy management, dashboard setup, or owner-managed webhooks.
Security Model
All signing happens locally — private keys never leave your environment. Escrow funds are held by an on-chain smart contract, not by Paegents. Wallet addresses are screened for sanctions compliance before activation.
Keep API keys and private keys in environment variables. Never commit them to source control.
AP2 Quick Start
from paegents import build_card_payment_method
intent = sdk.create_ap2_intent_mandate(
policy={"max_amount": {"value": 5000}, "currency": "usd"},
metadata={"purpose": "compute credits"},
)
cart = sdk.create_ap2_cart_mandate(
intent_mandate_id=intent.id,
cart={"total": 2500, "currency": "usd"},
)
payment = sdk.ap2_pay(
intent_mandate_id=intent.id,
cart_mandate_id=cart.id,
payment_method=build_card_payment_method(provider='stripe'),
)
if isinstance(payment, dict) and payment.get('approval_required'):
print('Approval required:', payment['request_id'])
else:
print('Payment status:', payment.status)
Bilateral Escrow Usage Agreements
Bilateral escrow is a two-step process: create the agreement, then activate the on-chain escrow.
Activation is required. Without completing activation, the agreement stays at
accepted/activation_status=ready. The metered proxy will reject requests and no funds are deposited on-chain.
import os, time
from paegents import (
sign_buyer_activation_intent,
sign_infra_fee_permit,
build_prior_allowance_funding_authorization,
ActivateEscrowRequestV2,
BuyerActivationIntentRequest,
FundingAuthorizationRequestV2,
)
# Step 1: Create the agreement (auto-accepted for self-service)
agreement = sdk.create_usage_agreement(
seller_agent_id='seller-agent-123',
service_id='svc_abc123',
quantity=1000,
unit='api_calls',
price_per_unit_cents=10,
buyer_wallet_address=os.environ['AGENT_WALLET_ADDRESS'],
)
# Step 2: Fetch the activation package (terms, nonces, funding options, infra fee)
package = sdk.get_activation_package(agreement.agreement_id)
# Step 3a: Sign the buyer activation intent locally (EIP-712)
intent = {
"agreement_key": package.agreement_key,
"platform_agreement_id_hash": package.platform_agreement_id_hash,
"buyer": package.terms.buyer,
"seller": package.terms.seller,
"token": package.terms.token,
"quantity": package.terms.quantity,
"price_per_unit": package.terms.price_per_unit_atomic,
"deposit_amount": package.terms.deposit_amount_atomic,
"challenge_window_seconds": package.terms.challenge_window_seconds,
"service_hash": package.terms.service_hash,
"terms_hash": package.terms.terms_hash,
"expiry": package.terms.expiry,
"nonce": package.nonces.buyer_activation_nonce,
"salt": package.terms.salt,
}
sig_result = sign_buyer_activation_intent(
buyer_private_key=os.environ['AGENT_PRIVATE_KEY'],
escrow_contract_address=package.funding.spender,
chain_id=8453, # Base mainnet
intent=intent,
)
# Step 3b: Build funding authorization (prior USDC allowance)
funding = build_prior_allowance_funding_authorization(
amount=package.terms.deposit_amount_atomic,
)
# Step 3c: Sign the separate infra fee permit when the package says a fee is pending
permit_deadline = int(time.time()) + 600
buyer_usdc_permit_nonce = int(os.environ['BUYER_USDC_PERMIT_NONCE']) # read USDC.nonces(buyer)
infra_fee_permit = None
if package.infra_fee and not package.infra_fee.waived and package.infra_fee.status != 'paid':
infra_fee_permit = sign_infra_fee_permit(
buyer_private_key=os.environ['AGENT_PRIVATE_KEY'],
spender=package.infra_fee.spender,
value=package.infra_fee.amount_atomic,
nonce=buyer_usdc_permit_nonce,
deadline=permit_deadline,
chain_id=8453, # Base mainnet
usdc_address=package.infra_fee.token_address,
)
# Step 4: Submit activation to the server with both authorizations
sdk.activate_escrow(
agreement.agreement_id,
ActivateEscrowRequestV2(
buyer_intent=BuyerActivationIntentRequest(**intent),
buyer_signature=sig_result['signature'],
funding_authorization=FundingAuthorizationRequestV2(**funding),
buyer_infra_fee_permit_signature=infra_fee_permit['signature'] if infra_fee_permit else None,
buyer_infra_fee_permit_deadline=permit_deadline if infra_fee_permit else None,
),
)
# Step 5: Poll until active (typically 10-30 seconds on Base)
while True:
current = sdk.get_usage_agreement(agreement.agreement_id)
if current.status == 'active':
break
time.sleep(3)
Optional: Metered Client
client = sdk.create_metered_client(agreement.agreement_id)
result = client.post('/generate', json={
'prompt': 'hello world',
'max_tokens': 150,
})
usage = client.get_usage_status()
print(usage.units_used, usage.units_remaining)
Policies and Approvals
Owner JWT is required for these endpoints.
import os
owner_jwt = os.environ['OWNER_JWT']
sdk.update_agent_policies(
{
'approvals': {'threshold_cents': 2000},
'rails': {'allowed': ['card', 'stablecoin']},
'spending': {'daily_limit_cents': 10000},
},
agent_id='agent-123',
jwt_token=owner_jwt,
)
pending = sdk.list_approvals(status='pending', agent_id='agent-123', jwt_token=owner_jwt)
if pending.get('approvals'):
sdk.approve_approval(pending['approvals'][0]['id'], agent_id='agent-123', jwt_token=owner_jwt)
Webhooks
import os
owner_jwt = os.environ['OWNER_JWT']
webhook = sdk.create_webhook(
url='https://example.com/webhooks',
event_types=['payment.*', 'agreement.*'],
agent_id='agent-123',
jwt_token=owner_jwt,
)
print(webhook.get('id'))
Verify Webhook Signatures
from paegents import verify_webhook_signature
verify_webhook_signature(signature_header, raw_body, os.environ['PAEGENTS_WEBHOOK_SECRET'])
Error Handling
from paegents import ApiError, PolicyDeniedError
try:
sdk.ap2_pay(
intent_mandate_id='intent_123',
cart_mandate_id='cart_123',
payment_method=build_card_payment_method(),
)
except PolicyDeniedError as exc:
print('Policy denied:', exc)
except ApiError as exc:
print('API error:', exc)
except Exception as exc:
print('Unexpected error:', exc)
Notes
- Prefer SDK methods over manual HTTP calls.
- Keep API keys and JWTs in environment variables.
- Use idempotency keys on critical write operations.
- Bilateral escrow settlement auto-pays on finalization. Buyer and seller do not need a second payout signature after the agreement is already funded and metered.
- The platform fee is upfront-only in the current live model. Settlement should not perform a second per-call fee pull.
Support
- Docs: https://docs.paegents.com
- API docs: https://docs.paegents.com/api
- Support: support@paegents.com
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file paegents-2.9.1.tar.gz.
File metadata
- Download URL: paegents-2.9.1.tar.gz
- Upload date:
- Size: 45.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9ac7303e19998eea87ef832747abaa998669f0d4390399be39a6eb660af0765f
|
|
| MD5 |
78172905224d1442787890319b8acac6
|
|
| BLAKE2b-256 |
8d234a236a105c7cb0c003a5aab92b9e0b2eadd25efe62c8e2e2fafb85df1131
|
File details
Details for the file paegents-2.9.1-py3-none-any.whl.
File metadata
- Download URL: paegents-2.9.1-py3-none-any.whl
- Upload date:
- Size: 34.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
da91d92e40b3c8f375abb441e83860b45b6df03d2245bf9ad3faaa79a576c9af
|
|
| MD5 |
4d083a752b526e0c6abd673fce7d420b
|
|
| BLAKE2b-256 |
5275cb47d0a676c8ec8e682b6ab9cadce6eaf1b47d12599da66b16841c06422e
|