Skip to content

CrewAI Integration Guide

This guide shows how to give your CrewAI agents payment capabilities using PQSafe’s ML-DSA-65 spend envelopes. In a multi-agent setup, each agent gets its own envelope with scoped permissions — preventing any single agent from overspending or paying unauthorized recipients.

Prerequisites

  • Node.js ≥ 18 (or Python ≥ 3.10 for the Python SDK)
  • @pqsafe/agent-pay installed (installation)
  • CrewAI installed:
    Terminal window
    pip install crewai pqsafe-agent-pay
  • PQSafe issuer key configured in environment

Multi-agent payment architecture

In a CrewAI crew, multiple agents collaborate on a task. PQSafe allows you to issue separate envelopes per agent role — giving tighter control than a single shared payment credential:

Crew
├── ResearchAgent (no payment envelope — read-only)
├── ProcurementAgent (envelope: $500/day, recipients: [vendor-a.com, vendor-b.com])
├── FinanceApproverAgent (approval oracle — resolves PQSafe approval gates)
└── AuditAgent (reads ledger — no payment capability)

Python SDK example

  1. Install dependencies

    Terminal window
    pip install crewai pqsafe-agent-pay python-dotenv
  2. Define spend envelopes per agent role

    import os
    from pqsafe import generate_key_pair, create_spend_envelope, create_signed_envelope
    from datetime import datetime, timedelta
    # Generate per-agent key pairs at startup
    procurement_keys = generate_key_pair()
    # Procurement agent: can pay approved vendors up to $500/day
    procurement_envelope = create_spend_envelope(
    agent_id='crewai-procurement-agent',
    max_amount=500.00,
    currency='USD',
    allowed_rails=['airwallex', 'wise'],
    allowed_recipients=[
    'vendor-a.com',
    'vendor-b.com',
    'stripe.com',
    ],
    valid_until=datetime.utcnow() + timedelta(hours=24),
    require_approval=True,
    approval_threshold=200.00, # Require human approval above $200
    memo='CrewAI procurement run — automated vendor payments',
    )
    signed_procurement_envelope = create_signed_envelope(
    procurement_envelope,
    procurement_keys['secret_key']
    )
  3. Build the PQSafe payment tool

    from crewai.tools import BaseTool
    from pydantic import BaseModel, Field
    from pqsafe import execute_agent_payment, build_ledger_record, submit_to_ledger
    import json
    class PaymentInput(BaseModel):
    recipient: str = Field(description="Payment recipient domain (e.g. vendor-a.com)")
    amount: float = Field(description="Payment amount in USD")
    memo: str = Field(description="Payment memo — appears in ledger and bank statement")
    rail: str = Field(default="airwallex", description="Payment rail: airwallex | wise | stripe")
    class PQSafePaymentTool(BaseTool):
    name: str = "pqsafe_execute_payment"
    description: str = """Execute a post-quantum-authorized payment via PQSafe AgentPay.
    All payments are cryptographically bounded by the spend envelope.
    Allowed recipients: vendor-a.com, vendor-b.com, stripe.com
    Max amount: $500 USD per envelope
    Requires human approval for payments above $200."""
    def _run(self, recipient: str, amount: float, memo: str, rail: str = "airwallex") -> str:
    try:
    result = execute_agent_payment(
    signed_procurement_envelope,
    recipient=recipient,
    amount=amount,
    memo=memo,
    rail=rail,
    )
    # Log to immutable ledger
    record = build_ledger_record(signed_procurement_envelope, result)
    ledger_entry = submit_to_ledger(record)
    return json.dumps({
    "status": result.status,
    "tx_id": result.tx_id,
    "rail": result.rail,
    "ledger_hash": ledger_entry.hash,
    "amount_paid": amount,
    "recipient": recipient,
    })
    except Exception as e:
    return f"Payment failed: {str(e)}"
  4. Define the crew with payment-capable agent

    from crewai import Agent, Task, Crew, Process
    payment_tool = PQSafePaymentTool()
    # Procurement agent — the only agent with payment capability
    procurement_agent = Agent(
    role='Procurement Specialist',
    goal='Execute vendor payments efficiently and within approved budget limits',
    backstory="""You are an autonomous procurement agent with access to
    post-quantum-authorized payment rails. You can pay approved vendors up to
    $500 per envelope, with human approval required above $200.""",
    tools=[payment_tool],
    verbose=True,
    allow_delegation=False,
    )
    # Finance approver — resolves PQSafe approval gates
    finance_agent = Agent(
    role='Finance Approver',
    goal='Review and approve vendor payments above threshold',
    backstory="""You review payment requests forwarded by the procurement agent.
    You approve payments that align with the quarterly budget.""",
    tools=[], # No payment tools — approval-only
    verbose=True,
    )
    # Define tasks
    procurement_task = Task(
    description="""
    Pay the following outstanding invoices:
    1. Vendor A: $150 for cloud hosting (invoice #VA-2026-042)
    2. Vendor B: $300 for data pipeline services (invoice #VB-2026-017)
    For each payment:
    - Verify the recipient is in the allowlist
    - Execute payment via the most appropriate rail
    - Confirm the ledger hash
    """,
    agent=procurement_agent,
    expected_output='Payment confirmations with transaction IDs and ledger hashes for all invoices',
    )
    crew = Crew(
    agents=[procurement_agent, finance_agent],
    tasks=[procurement_task],
    process=Process.sequential,
    verbose=True,
    )
  5. Run the crew

    result = crew.kickoff()
    print(result)

TypeScript CrewAI example

CrewAI has an experimental TypeScript port. The pattern is the same:

import {
generateKeyPair,
createSpendEnvelope,
createSignedEnvelope,
executeAgentPayment,
buildLedgerRecord,
submitToLedger,
} from '@pqsafe/agent-pay'
// Setup envelope (done at crew initialization)
const { secretKey } = await generateKeyPair()
const signedEnvelope = createSignedEnvelope(
createSpendEnvelope({
agentId: 'crewai-ts-agent',
maxAmount: 500,
currency: 'USD',
allowedRails: ['airwallex'],
allowedRecipients: ['vendor-a.com', 'vendor-b.com'],
validUntil: new Date(Date.now() + 86_400_000),
requireApproval: true,
approvalThreshold: 200,
}),
secretKey
)
// PQSafe payment function (pass to your CrewAI tool definition)
async function pqsafePay(recipient: string, amount: number, memo: string) {
const result = await executeAgentPayment(signedEnvelope, { recipient, amount, memo })
const ledgerEntry = await submitToLedger(buildLedgerRecord(signedEnvelope, result))
return { status: result.status, txId: result.txId, ledgerHash: ledgerEntry.hash }
}

Per-agent envelope scoping

A key security benefit of multi-agent PQSafe integration is per-agent envelope isolation:

Agent rolemaxAmountallowedRecipientsrequireApproval
ProcurementAgent$500vendor-a.com, vendor-b.comYes (>$200)
DevOpsAgent$100cloudflare.com, aws.amazon.comNo
MarketingAgent$200mailchimp.com, meta.com/adsYes (>$50)
AuditAgent$0(none — read-only)n/a

Each agent can only spend what it’s been authorized for. A compromised ProcurementAgent cannot pay meta.com/ads — that’s cryptographically enforced by the envelope’s allowedRecipients list.

Expected output

[Crew] Starting procurement run...
[ProcurementAgent] Executing payment: $150 to vendor-a.com via airwallex...
[PQSafe] Signature valid. Envelope bounds: OK. Dispatching...
[PQSafe] Payment settled. TX: txn_airwallex_abc123
[ProcurementAgent] Ledger hash: 0xf7a3c2...
[ProcurementAgent] Executing payment: $300 to vendor-b.com...
[PQSafe] approvalThreshold exceeded ($300 > $200). Awaiting human approval...
[Telegram] Sent approval request to @your-handle
[PQSafe] Approval received. Dispatching...
[PQSafe] Payment settled. TX: txn_airwallex_def456
Payments complete.
- Invoice VA-2026-042: settled | TX: txn_airwallex_abc123 | Ledger: 0xf7a3c2...
- Invoice VB-2026-017: settled | TX: txn_airwallex_def456 | Ledger: 0x91e4b8...

Next steps