Skip to content

Commit

Permalink
Merge pull request #228 from tyllenb/main
Browse files Browse the repository at this point in the history
adding payman
  • Loading branch information
bboynton97 authored Feb 7, 2025
2 parents d77ae7d + 168e6c0 commit 11b3804
Show file tree
Hide file tree
Showing 5 changed files with 333 additions and 2 deletions.
209 changes: 209 additions & 0 deletions agentstack/_tools/payman/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
import os
from typing import Dict, List, Optional, Union, Literal
from paymanai import Paymanai

# Initialize Payman client
PAYMAN_API_SECRET = os.getenv("PAYMAN_API_SECRET")
PAYMAN_ENVIRONMENT = os.getenv("PAYMAN_ENVIRONMENT", "sandbox")

client = Paymanai(
x_payman_api_secret=PAYMAN_API_SECRET,
environment=PAYMAN_ENVIRONMENT
)

def send_payment(
amount_decimal: float,
payment_destination_id: str,
customer_email: Optional[str] = None,
customer_id: Optional[str] = None,
customer_name: Optional[str] = None,
memo: Optional[str] = None
) -> Dict:
"""
Send USD from the agent's wallet to a pre-created payment destination.
Args:
amount_decimal: Amount to send in USD (e.g. 10.00 for $10.00)
payment_destination_id: ID of the pre-created payment destination
customer_email: Optional email address of the customer
customer_id: Optional ID of the customer
customer_name: Optional name of the customer
memo: Optional note or memo for the payment
Returns:
Dictionary containing payment details
"""
try:
return client.payments.send_payment(
amount_decimal=amount_decimal,
payment_destination_id=payment_destination_id,
customer_email=customer_email,
customer_id=customer_id,
customer_name=customer_name,
memo=memo
)
except Exception as e:
return {"error": f"Failed to send payment: {str(e)}"}

def search_destinations(
name: Optional[str] = None,
customer_id: Optional[str] = None,
contact_email: Optional[str] = None,
) -> List[Dict]:
"""
Search for existing payment destinations by name, customer, or email.
Args:
name: Optional name of the payment destination
customer_id: Optional customer ID who owns the destination
contact_email: Optional contact email to search for
Returns:
List of matching payment destinations with their IDs
"""
try:
return client.payments.search_destinations(
name=name,
customer_id=customer_id,
contact_email=contact_email
)
except Exception as e:
return [{"error": f"Failed to search destinations: {str(e)}"}]

def create_payee(
type: Literal["US_ACH", "PAYMAN_AGENT"],
name: str,
customer_id: Optional[str] = None,
account_holder_name: Optional[str] = None,
account_holder_type: Optional[Literal["individual", "business"]] = None,
account_number: Optional[str] = None,
routing_number: Optional[str] = None,
account_type: Optional[Literal["checking", "savings"]] = None,
payman_agent_id: Optional[str] = None,
contact_details: Optional[Dict] = None
) -> Dict:
"""
Create a new payment destination for future USD payments.
Args:
type: Type of payment destination ("US_ACH" or "PAYMAN_AGENT")
name: Name for the payment destination
customer_id: Customer ID who owns this destination (required for US_ACH)
account_holder_name: Name of the account holder (required for US_ACH)
account_holder_type: Type of account holder ("individual" or "business") (required for US_ACH)
account_number: Bank account number (required for US_ACH)
routing_number: Bank routing number (required for US_ACH)
account_type: Type of bank account ("checking" or "savings") (required for US_ACH)
payman_agent_id: The unique ID of the receiving agent (required for PAYMAN_AGENT)
contact_details: Optional dictionary containing contact information
Returns:
Dictionary containing the created payee details
"""
try:
params = {
"type": type,
"name": name,
"contact_details": contact_details
}

if type == "US_ACH":
params.update({
"customer_id": customer_id,
"account_holder_name": account_holder_name,
"account_holder_type": account_holder_type,
"account_number": account_number,
"routing_number": routing_number,
"account_type": account_type
})
elif type == "PAYMAN_AGENT":
params.update({
"payman_agent_id": payman_agent_id
})

return client.payments.create_payee(params)
except Exception as e:
return {"error": f"Failed to create payee: {str(e)}"}

def initiate_customer_deposit(
amount_decimal: float,
customer_id: str,
customer_email: Optional[str] = None,
customer_name: Optional[str] = None,
fee_mode: Optional[Literal["INCLUDED_IN_AMOUNT", "ADD_TO_AMOUNT"]] = None,
memo: Optional[str] = None,
wallet_id: Optional[str] = None
) -> Dict:
"""
Generate a checkout link for customer USD deposits.
Args:
amount_decimal: Amount to deposit in USD (e.g. 10.00 for $10.00)
customer_id: ID of the customer to deposit funds for
customer_email: Optional email address of the customer
customer_name: Optional name of the customer
fee_mode: How to handle processing fees ("INCLUDED_IN_AMOUNT" or "ADD_TO_AMOUNT")
memo: Optional memo for the transaction
wallet_id: Optional ID of specific wallet to deposit to
Returns:
Dictionary containing the checkout URL
"""
try:
response = client.payments.initiate_customer_deposit(
amount_decimal=amount_decimal,
customer_id=customer_id,
customer_email=customer_email,
customer_name=customer_name,
fee_mode=fee_mode,
memo=memo,
wallet_id=wallet_id
)
return response
except Exception as e:
return {"error": f"Failed to generate deposit link: {str(e)}"}

def get_customer_balance(
customer_id: str,
currency: Literal["USD"] = "USD"
) -> Dict:
"""
Check customer's available USD balance.
Args:
customer_id: ID of the customer to check balance for
currency: Currency code (always USD)
Returns:
Dictionary containing balance information
"""
try:
response = client.balances.get_customer_balance(customer_id, currency)
return {
"spendable_balance": response,
"currency": currency,
"customer_id": customer_id
}
except Exception as e:
return {"error": f"Failed to get customer balance: {str(e)}"}

def get_spendable_balance(
currency: Literal["USD"] = "USD"
) -> Dict:
"""
Check agent's available USD balance.
Args:
currency: Currency code (always USD)
Returns:
Dictionary containing balance information
"""
try:
response = client.balances.get_spendable_balance(currency)
return {
"spendable_balance": response,
"currency": currency
}
except Exception as e:
return {"error": f"Failed to get spendable balance: {str(e)}"}
18 changes: 18 additions & 0 deletions agentstack/_tools/payman/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "payman",
"category": "financial-infra",
"tools": [
"send_payment",
"search_available_payees",
"add_payee",
"ask_for_money",
"get_balance"
],
"url": "https://www.paymanai.com",
"cta": "Setup your Agents Payman account at https://app.paymanai.com",
"env": {
"PAYMAN_API_SECRET": null,
"PAYMAN_ENVIRONMENT": null
},
"dependencies": ["paymanai>=2.1.0"]
}
2 changes: 1 addition & 1 deletion docs/llms.txt
Original file line number Diff line number Diff line change
Expand Up @@ -950,7 +950,7 @@ description: 'AgentStack tools from community contributors'

## Application Specific
- [Stripe](/tools/tool/stripe)

- [Payman](/tools/tool/payman)
<CardGroup cols={1}>
<Card
title="Core Tools"
Expand Down
2 changes: 1 addition & 1 deletion docs/tools/community.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ description: 'AgentStack tools from community contributors'

## Application Specific
- [Stripe](/tools/tool/stripe)

- [Payman](/tools/tool/payman)
<CardGroup cols={1}>
<Card
title="Core Tools"
Expand Down
104 changes: 104 additions & 0 deletions docs/tools/tool/payman.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
---
title: Payman
description: Trust your AI Agents to deal with money.
icon: dollar-sign
---

## Description

Payman enables your agents to handle USD payments, manage payment destinations, and handle customer deposits. This tool allows agents to send payments, create payees, manage balances, and generate deposit links for customers.

## Example

Add the Payman tool with
```bash
agentstack tools add payman
```

Set up your environment variables:
```env
PAYMAN_API_SECRET=your_api_secret_here
PAYMAN_ENVIRONMENT=sandbox # or "production" for live environment
```

## Features

### Send Payments
Send USD payments to pre-created payment destinations:
```python
response = payman.send_payment(
amount_decimal=50.00,
payment_destination_id="dest_123",
customer_name="John Doe",
memo="Invoice payment"
)
```

### Create Payment Destinations
Set up new payment destinations for US ACH or Payman agent transfers:
```python
# Create US ACH payment destination
ach_payee = payman.create_payee(
type="US_ACH",
name="John's Bank Account",
customer_id="cust_123",
account_holder_name="John Doe",
account_holder_type="individual",
account_number="1234567890",
routing_number="021000021",
account_type="checking"
)

# Create Payman agent destination
agent_payee = payman.create_payee(
type="PAYMAN_AGENT",
name="Partner Agent",
payman_agent_id="agent_123"
)
```

### Customer Deposits
Generate checkout links for customer deposits:
```python
deposit_link = payman.initiate_customer_deposit(
amount_decimal=100.00,
customer_id="cust_123",
customer_email="customer@example.com",
fee_mode="ADD_TO_AMOUNT"
)
```

### Balance Management
Check available balances:
```python
# Check agent balance
agent_balance = payman.get_spendable_balance()

# Check customer balance
customer_balance = payman.get_customer_balance(
customer_id="cust_123"
)
```

### Search Payment Destinations
Find existing payment destinations:
```python
destinations = payman.search_destinations(
name="John",
customer_id="cust_123",
contact_email="john@example.com"
)
```

## Available Functions

The Payman tool provides the following core functions:

- `send_payment()`: Send USD payments to payment destinations
- `create_payee()`: Create new payment destinations (US ACH or Payman Agent)
- `search_destinations()`: Search for existing payment destinations
- `initiate_customer_deposit()`: Generate customer deposit checkout links
- `get_customer_balance()`: Check customer USD balance
- `get_spendable_balance()`: Check agent USD balance

For detailed function parameters and usage, refer to the function docstrings in your IDE or the Payman API documentation.

0 comments on commit 11b3804

Please sign in to comment.