# Reconcile Ramp charges against receipts

> Connect Ramp, map each agent's card to the agent, and every charge is reconciled against the receipt that allowed it. Ramp saw the charge; Immiscible says why it happened, and can write that into the Ramp memo.

Source: https://immiscible.fly.dev/docs/guides/ramp

Many companies already give agents (and the people running them) Ramp cards. Ramp sees every charge, but not why it happened. Immiscible holds the why: the action the agent asked for, the mandate or the person who allowed it, and the receipt. Ramp reconciliation puts the two side by side.

## 1. Connect

**Connect Ramp.** Where this server has a Ramp app (the operator registers it once), an owner chooses **Connect** on Ramp under **Settings**, **Connections**, picks the options, and approves at Ramp. Ramp asks for exactly the scopes below and nothing else, and only a Ramp admin or business owner can approve. Nothing is copied. The tokens are sealed and refreshed on their own; turning on an option that needs another scope asks you to approve again.

**Your own Ramp app.** Otherwise, in Ramp, create a Developer API app with the **client credentials** grant and these scopes:

| Scope | For |
|---|---|
| `transactions:read`, `cards:read` | always |
| `memos:write` | writing the receipt and decision into each memo |
| `cards:write`, `funds:write` | locking a card when its agent is frozen |

Under **Ramp** in the console, an owner pastes the client id and secret and chooses the options. Immiscible asks Ramp for a token with exactly those scopes, which checks them, then seals the credentials.

## 2. Map cards to agents

**Sync now** lists Ramp's virtual and physical cards. Map each card an agent uses to that agent. A card mapped later reconciles the charges already imported on it.

## 3. Read the reconciliation

Charges are imported every hour (and on **Sync now**) and each one on a mapped card is checked against the agent's allowed payments from the 30 days before it:

| Result | Meaning |
|---|---|
| **matched** | a receipt for this payee, in this currency, covers the charge |
| **mismatched** | there is a receipt for this payee, but the charge is over it or in another currency |
| **unmatched** | no receipt for this payee at all: money moved that nobody allowed here. Recorded as an incident |
| **no agent** | the card is not mapped |

A receipt reconciles one charge. Payees are matched the way the [card rail](https://immiscible.fly.dev/docs/guides/card-rail.md) matches them: the receipt's merchant as a whole word in the descriptor, so `grocer.example` is GROCER RETAIL LTD and never GREENGROCER BAR.

Open any charge for **Ramp saw this charge; here is why it happened**: Ramp's side (amount, descriptor, card) next to Immiscible's (the action, its summary, the mandate, who approved it, the receipt), with one sentence that says why.

## Memos

With memos on, each reconciled charge gets one memo in Ramp, for example:

```text
Immiscible receipt act_5e2b: Shopper was allowed £42.50 at market.example under mandate mdt_91c2. Weekly shop
```

A memo is written once; a failure is shown on the charge and not retried in a loop.

## Lock on freeze

With lock on freeze, freezing an agent (the [kill switch](https://immiscible.fly.dev/docs/guides/kill-switch.md), an incident, a security hold) locks its Ramp cards at once: a physical card is suspended directly; a virtual card is locked by suspending its fund, because Ramp's API suspends virtual cards through the fund. That suspends every card on the fund, so give each agent a fund of its own. A lock that fails is retried by the sweeper. Drills never lock real cards.

Unlocking is a proposal an owner files once the agent is unfrozen and a **second** owner confirms. Locking narrows what money can move, so it never waits; unlocking widens it, so it does.
