Skip to content

Payments on behalf of a user

A programmatic client can pay for purchases on a user's behalf when the user has pre-authorized a spending limit. This is common for AI assistants or automated systems that act on behalf of a user. It uses the same checkout flow as API payments, but links each payment to a specific user account.


Flow

User         →  Authorizes agent with spending limit (your app)
Agent        →  POST /payments/requests (with customer_id)
Agent        →  GET /payments/public/{request_id}
Agent        →  Sends XRP on-chain from agent wallet
Agent        →  POST /payments/{request_id}/verify
DropPay      →  Sends payment.confirmed webhook (includes customer_id)
Your server  →  Logs purchase against user's account
Agent        →  Informs user of completed purchase

Pre-authorization model

Store the user's spending limit in your database. The agent checks this before creating a payment.

agent_auth.py
# Schema: user_authorizations(user_id, agent_id, max_per_tx, max_total, spent_total)

def check_authorization(user_id: str, agent_id: str, amount_xrp: float) -> bool:
    auth = db.get_authorization(user_id, agent_id)
    if not auth:
        return False
    if amount_xrp > auth["max_per_tx"]:
        return False
    if auth["spent_total"] + amount_xrp > auth["max_total"]:
        return False
    return True
agentAuth.js
// Schema: user_authorizations(user_id, agent_id, max_per_tx, max_total, spent_total)

async function checkAuthorization(userId, agentId, amountXrp) {
  const auth = await db.getAuthorization(userId, agentId);
  if (!auth) return false;
  if (amountXrp > auth.maxPerTx) return false;
  if (auth.spentTotal + amountXrp > auth.maxTotal) return false;
  return true;
}

Create the payment

Pass customer_id so your webhook handler can link the payment to the user's account.

agent_pay.py
import requests

BASE = "https://droppayxrp.com"
API_KEY = "dp_live_your_api_key_here"

def agent_purchase(user_id: str, agent_id: str, item: dict) -> dict:
    if not check_authorization(user_id, agent_id, item["price_xrp"]):
        raise PermissionError(f"Exceeds spending limit for user {user_id}")

    response = requests.post(
        f"{BASE}/payments/requests",
        headers={"Authorization": f"Bearer {API_KEY}"},
        json={
            "amount": item["price_xrp"],
            "currency": "XRP",
            "description": item["name"],
            "customer_id": user_id,
            "order_id": item["order_id"]
        }
    )

    payment = response.json()

    # Get locked amount and wallet from public endpoint
    pub = requests.get(
        f"{BASE}/payments/public/{payment['request_id']}"
    ).json()

    return {"payment": payment, "pub": pub}
agentPay.js
const BASE = "https://droppayxrp.com";
const API_KEY = "dp_live_your_api_key_here";

async function agentPurchase(userId, agentId, item) {
  const authorized = await checkAuthorization(userId, agentId, item.priceXrp);
  if (!authorized) {
    throw new Error(`Exceeds spending limit for user ${userId}`);
  }

  const response = await fetch(`${BASE}/payments/requests`, {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${API_KEY}`,
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      amount: item.priceXrp,
      currency: "XRP",
      description: item.name,
      customer_id: userId,
      order_id: item.orderId
    })
  });

  const payment = await response.json();

  const pub = await fetch(
    `${BASE}/payments/public/${payment.request_id}`
  ).then(r => r.json());

  return { payment, pub };
}

Send XRP and verify

After creating the payment, send XRP on-chain and call the verify endpoint. The steps are identical to those in API payments - step 2 onwards.


Log the purchase in your webhook

customer_id is returned in the webhook payload under data.customer_id.

webhook.py
event = request.json
if event["event"] == "payment.confirmed":
    data = event["data"]
    user_id = data["customer_id"]
    amount = float(data.get("amount", 0))

    db.log_purchase(
        user_id=user_id,
        order_id=data["order_id"],
        amount=amount,
        currency=data["currency"],
        request_id=data["request_id"]
    )

    db.update_spending_total(user_id, amount)
webhook.js
if (event.event === "payment.confirmed") {
  const { customer_id, order_id, amount, currency, request_id } = event.data;

  await db.logPurchase({
    userId: customer_id,
    orderId: order_id,
    amount: parseFloat(amount),
    currency,
    requestId: request_id
  });

  await db.updateSpendingTotal(customer_id, parseFloat(amount));
}

Notes

  • The agent wallet sends the XRP, not the user's wallet. Pre-load the agent wallet with enough XRP to cover purchases.
  • Keep a per-user spending ledger. If the webhook never arrives (network issue), reconcile later via GET /payments/public/{request_id}.
  • Notify the user after each purchase via push notification, email, or the next agent reply.

Next steps