> ## Documentation Index
> Fetch the complete documentation index at: https://docs.payzor.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Pay a vendor

> The buyer side of Qopper (Business): fund a company account, on-board a vendor, upload an invoice, and route the payment through the best rail — USDC on-chain or a local payout.

# Pay a vendor

Qopper isn't only about agents that get paid. **The other half is a business that pays vendors.** A company funds a Qopper balance in USDC and pays international suppliers with the full accounts-payable flow: `invoice → verify → quote → approve → execute → reconcile`.

Just like the agent side, the business signs in from the console; everything is owner-scoped to your account.

## The flow

```
create business → top up (USDC) → add vendor → create invoice
   → verify → quote (routing) → approve → execute → reconcile
```

Every step is its own endpoint, so you can show the CFO a quote and get the human approval before any money moves.

## 1. Fund a company account

```bash theme={null}
curl -X POST https://api.qopper.com/api/business \
  -H "Authorization: Bearer <console JWT>" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Acme Corp" }'
```

Grab `businessId`, then credit it:

```bash theme={null}
curl -X POST https://api.qopper.com/api/business/<businessId>/topup \
  -H "Authorization: Bearer <console JWT>" \
  -H "Content-Type: application/json" \
  -d '{ "amountUsdMinor": 5000000 }'   # $50,000.00
```

> The credit is idempotent — resending the same `idempotencyKey` does not double-credit.

## 2. On-board a vendor

A vendor is either a **bank account** (receiving local currency, e.g. COP) or a **wallet** (receiving USDC). Qopper detects a change in the vendor's bank details and bumps `bankRev`, forcing re-verification before the next payment.

```bash theme={null}
curl -X POST https://api.qopper.com/api/vendors \
  -H "Content-Type: application/json" \
  -d '{
    "businessId": "<businessId>",
    "name": "Proveedor Bogotá",
    "country": "CO",
    "receivingCurrency": "COP",
    "destinationType": "bank",
    "bankDetails": { "bank": "Bancolombia", "account_number": "123456789" }
  }'
```

## 3. Create and verify an invoice

```bash theme={null}
curl -X POST https://api.qopper.com/api/invoices \
  -H "Content-Type: application/json" \
  -d '{ "businessId": "<businessId>", "vendorId": "<vendorId>",
        "invoiceNumber": "INV-001", "amountMinor": 2500000, "currency": "USD" }'

curl -X POST https://api.qopper.com/api/invoices/<invoiceId>/verify
```

The AP agent checks duplicates, an un-verified vendor, a changed bank, and invalid amounts, returning a `riskFlags` array. With no risks the invoice goes to `verified`.

## 4. Quote, approve, execute

```bash theme={null}
# Quote: picks the best rail (cost, FX, speed, reliability)
curl -X POST https://api.qopper.com/api/invoices/<invoiceId>/quote
# → { payment, quote: { best: { provider, feeMinor, fxRate, vendorReceivesMinor, etaMs, ... } } }

# Human approval (CFO)
curl -X POST https://api.qopper.com/api/payments/<paymentId>/approve \
  -d '{ "approvedBy": "cfo@acme.com" }'

# Execute: debits the company, routes the rail, reconciles
curl -X POST https://api.qopper.com/api/payments/<paymentId>/execute
```

```json theme={null}
// 200 — executed (local payout)
{
  "paymentId": "pay_...",
  "provider": "offramp",
  "network": "local",
  "status": "payout_sent",
  "feeMinor": 12500,
  "fxRate": 4242,
  "vendorReceivesMinor": 10551975000,
  "payoutRef": "lpr_...",
  "reconciliation": { "matched": true }
}
```

## The routing engine

The quote is produced by `integrations/routing-engine.js`. Rails are adapters; today there are two:

* **on-chain (`onchain`)** — USDC straight to a vendor wallet. No FX, no fee to the vendor, minutes.
* **off-ramp (`offramp`)** — USDC → local currency to a bank account (COP, MXN, ...). Applies an FX spread and a fee.

The router scores each candidate by cost, speed and reliability, and returns the best. Configure FX and corridors with `QOPPER_FX_USD_COP`, `QOPPER_OFFRAMP_CORRIDORS` (JSON) and the real payout provider with `QOPPER_OFFRAMP_EXECUTOR_URL`.

## Mass payments

Pay to **N recipients in one operation** — the company is debited once for the total, and the rail is `chain.batchSendUsdc` (sequential transfers from the `qopper-treasury` account).

```bash theme={null}
curl -X POST https://api.qopper.com/api/business/<businessId>/payouts/batch \
  -H "Authorization: Bearer <console JWT>" \
  -H "Content-Type: application/json" \
  -d '{ "items": [
        { "toAddress": "0xaaa", "amountMinor": 500000, "ref": "inv-1" },
        { "toAddress": "0xbbb", "amountMinor": 1000000, "ref": "inv-2" }
      ] }'
```

```json theme={null}
// 201
{ "batchId": "pb_...", "status": "completed", "totalMinor": 1500000,
  "count": 2, "txHash": "0xbatch", "items": [ { "status": "sent" }, { "status": "sent" } ] }
```

List them: `GET /api/business/:id/payouts/batches`. The batch is idempotent by `idempotencyKey`; if the rail fails, the company balance is refunded and the batch is marked `failed`.

## Fund with Onramp (fiat → USDC)

Top up real USDC. The server mints a Coinbase session token (the CDP secret key never reaches the browser) and returns a single-use `onrampUrl` you open in a new tab.

```bash theme={null}
curl -X POST https://api.qopper.com/api/business/<businessId>/onramp/session \
  -H "Authorization: Bearer <console JWT>" -d '{ "paymentAmount": "50", "paymentCurrency": "USD" }'
# → { "depositAddress": "0x...", "onrampUrl": "https://pay.coinbase.com/buy?sessionToken=...", "sessionToken": "..." }
```

After the purchase, claim the on-chain USDC into the internal balance (idempotent by delta):

```bash theme={null}
curl -X POST https://api.qopper.com/api/business/<businessId>/onramp/claim
# → { "creditedMinor": 5000000, "balanceUsdMinor": 5000000 }
```

**Agent wallets (Product B)** fund the same way:
`POST /agents/:id/onramp/session` — the deposit watcher credits the agent balance automatically once the USDC arrives.

> For demos, set `QOPPER_ONRAMP_SANDBOX=1`: the purchase always succeeds and your card is never charged.

## Invoice customers (Invoicing / AR)

The same business can also **get paid**: issue an invoice to a customer, share the link, and the money lands in your balance when they pay.

```bash theme={null}
curl -X POST https://api.qopper.com/api/business/<businessId>/invoicing \
  -H "Authorization: Bearer <console JWT>" \
  -H "Content-Type: application/json" \
  -d '{ "customer": "Partner Ltd", "amountMinor": 250000, "description": "Suscripción anual" }'
# → { "invoice": { "status": "issued", "paymentToken": "inv_..." }, "paymentUrl": "https://api.qopper.com/business/invoice/inv_..." }
```

Share `paymentUrl`. The customer pays either from an agent wallet (authenticated with its `qp_sk_`) or on-chain with USDC (x402):

```bash theme={null}
# Agent wallet
curl -X POST https://api.qopper.com/api/public/invoice/inv_.../pay \
  -H "Authorization: Bearer qp_sk_..."            # debits that agent, credits the business

# On-chain USDC (x402)
curl https://api.qopper.com/api/public/invoice/inv_.../x402      # → 402 + payment requirements
curl -X POST .../x402 -H "X-PAYMENT: <signed>"                    # → settles, credits the business
```

On payment the invoice goes to `paid` and `businesses.balance_minor` is credited — idempotently (an invoice only pays once). List them with `GET /api/business/:id/invoicing`.
