<!-- tempo-docs-context -->
> Source: [/docs/accounts/policies/receive-policies](https://tempo.xyz/developers/docs/accounts/policies/receive-policies.md)
> Section: [Accounts](https://tempo.xyz/developers/docs/accounts.md). Create accounts, set up signing methods, policies, access keys, key rotation, and fees, and follow guides for users, automations, agents, and teams.
> [Documentation index](https://tempo.xyz/developers/llms.txt) · [Docs skill](https://tempo.xyz/developers/SKILL.md)

> Tempo MCP: Use `search`, `find_pages`, `read_page`, and `code` at `https://mcp.tempo.xyz` for Tempo and related documentation.
> If an indexed page is missing or reflects an older site, read this site’s [documentation index](https://tempo.xyz/developers/llms.txt) and Markdown pages directly.

<span id="configure-receive-policies" />

<span id="control-incoming-payments" />

# Receive Policies

Controls which stablecoins an address accepts and who can pay it.

## Overview

A receive policy controls which stablecoins an address accepts and who can pay it. It's one of a Tempo account's two [policies](https://tempo.xyz/developers/docs/accounts/policies), and it works on any account on mainnet and testnet.

A regulated business uses one to accept payments only from verified senders. An exchange uses one to accept only the stablecoins it lists. A blocked payment doesn't fail. Tempo holds the funds until the recovery authority you name claims them.

<span id="receive-policies" />

<span id="when-to-configure-a-receive-policy" />

<span id="what-a-receive-policy-checks" />

<span id="what-it-checks" />

<span id="how-it-works" />

## Policy Parts

Each address sets its policy in the [TIP-403](https://tempo.xyz/developers/docs/protocol/tip403/spec) registry. Tokens use the same registry of allowlists and blocklists to restrict transfers. The policy has three parts:

| Part | Decides | Set it to |
| --- | --- | --- |
| Token filter | Which stablecoins the address accepts | Built-in policy `1` (allow all) or `0` (reject all), or a `WHITELIST` or `BLACKLIST` policy of token contract addresses |
| Sender policy | Who can pay the address | The same options, with sender addresses as members |
| Recovery authority | Who can claim held payments | `address(0)` for the payment's sender or minter, the receiver's own address, or another address |

Neither the token filter nor the sender policy can be a `COMPOUND` policy. An address with no receive policy accepts every transfer and mint the token itself allows.

<span id="account-level-receive-policies" />

<span id="understand-receive-policy-behavior" />

<span id="how-tempo-enforces-receive-policies" />

<span id="what-happens-to-a-blocked-payment" />

## Blocked Payments

Every TIP-20 transfer and mint to the address runs through its receive policy:

* **The Token's Own Policy Rejects It:** The call reverts and nothing moves.
* **The Receive Policy Rejects It:** The transaction succeeds, but Tempo holds the funds in `ReceivePolicyGuard`, a system contract, instead of crediting the receiver. The recovery authority can [claim them](https://tempo.xyz/developers/docs/accounts/policies/receive-policies#claim-blocked-receipts).
* **Both Accept It:** Tempo credits the receiver.

<span id="virtual-address-behavior" />

A payment to a [virtual address](https://tempo.xyz/developers/docs/accounts/virtual-addresses) is checked against its master address's policy. A virtual address can't set its own, so set the policy on the master.

<span id="monitor-blocked-receipts" />

<span id="blocked-receipts" />

<span id="check-the-recipient-before-you-credit-a-payment" />

<span id="check-the-recipient" />

A held payment looks like a success. The token still emits its usual `Transfer` event, but that event's recipient is `ReceivePolicyGuard`, not the receiver. Credit a payment only when the confirmed event names the receiver.

<span id="try-receive-policies" />

<span id="configure-the-policy" />

## Set a Receive Policy

**Interactive demo: Hold and recover a payment**

1. Create a temporary Tempo Accounts devnet account, accept AlphaUSD, hold BetaUSD, and recover the blocked payment.

The demo and the steps in this section run on the Tempo Accounts devnet. The steps set the same policy in code: accept only one stablecoin, from any sender, and let the receiver claim held payments. `client.ts` connects to the devnet ([set up the devnet key](https://tempo.xyz/developers/docs/accounts/create#connect-to-the-devnet)).

`account` is the receiving account, such as one from [Create an account](https://tempo.xyz/developers/docs/accounts/create). `receiver` is its address. `stablecoin` is `0x20c0000000000000000000000000000000000001`, a test stablecoin on the devnet. Fund the receiver from the [devnet faucet](https://tempo.xyz/developers/docs/accounts/create#fund-an-account-on-devnet) first, because each transaction pays a network fee.

The steps use Viem. From Wagmi, create the allowlist with `Hooks.policy.useCreateSync` from `wagmi/tempo`. Make the other calls with `useWriteContract` or `useReadContract`, using `Abis` and `Addresses` from `viem/tempo`. From the CLI, call the TIP-403 registry at `0x403c000000000000000000000000000000000000` with `cast`:

* `createPolicyWithAccounts(address,uint8,address[])`. Policy type `0` is whitelist, and the new policy ID is `topics[1]` of the `PolicyCreated` log.
* `setReceivePolicy(uint64,uint64,address)`.
* `validateReceivePolicy(address,address,address)(bool,uint8)`.

Claim with `claim(address,bytes)` on `ReceivePolicyGuard`.

<span id="create-or-choose-a-token-filter" />

::::steps
### Create a Token Allowlist

Create a `WHITELIST` policy whose only member is the stablecoin's token contract address:

:::code-group
```ts [token-filter.ts]
import { client } from './client'

const { policyId: tokenPolicyId } = await client.policy.createSync({
  account,
  type: 'whitelist', // [!code hl]
  addresses: [stablecoin], // [!code hl]
})
```

```ts [client.ts]
import { http } from 'viem'
import { tempoDevnet } from 'viem/chains'
import { createClient } from 'viem/tempo'

// The Tempo Accounts devnet. Its RPC needs a key, which Tempo gives you.
const rpcKey = process.env.TEMPO_DEVNET_RPC_KEY

export const client = createClient({
  chain: tempoDevnet,
  transport: http('https://rpc-t14-checkpoint.devnet.tempoxyz.dev', {
    fetchOptions: { headers: { Authorization: `Basic ${btoa(`previews:${rpcKey}`)}` } },
  }),
})
```
:::

[`policy.create`](https://viem.sh/tempo/actions/policy.create) also creates `blacklist` policies and policies with no members.

<span id="create-or-choose-a-sender-policy" />

<span id="choose-a-recovery-authority" />

### Set the Receive Policy

Call `setReceivePolicy` from the receiving account with the sender policy, token filter, and recovery authority, in that order:

```ts [set-policy.ts]
import { client } from './client'

await client.receivePolicy.setSync({
  account,
  senderPolicyId: 'allow-all', // [!code hl]
  tokenPolicyId, // [!code hl]
  claimer: 'self', // [!code hl]
})
```

The sender policy here is built-in policy `1` (`'allow-all'` in Viem), so anyone can pay. To limit who can pay, create a sender allowlist the same way as the token allowlist. Give it sender addresses as members, and pass its ID instead.

Viem's [`receivePolicy.set`](https://viem.sh/tempo/actions/receivePolicy.set) calls the token filter `tokenPolicyId` and the recovery authority `claimer`. Set `claimer` to `'self'` for the signing account, `'sender'` for `address(0)`, or another address.

Changing the [recovery authority](https://tempo.xyz/developers/docs/protocol/tip403/receive-policies#receive-policy-configuration) affects only payments held afterward. Existing receipts keep the authority they were held under.
::::

<span id="check-a-payment-before-sending" />

## Check Before Sending

Ask whether the receiver's policy accepts a token from a sender. `sender` is the paying address:

```ts [validate.ts]
import { client } from './client'

const { authorized, blockedReason } = await client.receivePolicy.validate({ // [!code hl]
  token: stablecoin, sender, receiver, // [!code hl]
}) // [!code hl]
```

The answer covers only the receive policy. It doesn't cover the token's own policy, the sender's balance, or the rest of the transaction. The policy can also change before the payment executes, so a passing check isn't a credited payment.

<span id="claim-blocked-receipts" />

## Claim a Held Payment

The recovery authority claims a held payment by passing a destination and the `receipt` bytes from its `TransferBlocked` event. You can't list held payments onchain, so index the guard's events. This query finds the `TransferBlocked` events for an address and marks each payment `held`, `claimed`, or `burned`:

Save this query as `query.sql` and run it against the public Tempo mainnet indexer (chain ID 4217).

```sql
SELECT
multiIf(
  (token, blockedNonce) IN (SELECT token, blockedNonce FROM ReceiptClaimed), 'claimed',
  (token, blockedNonce) IN (SELECT token, blockedNonce FROM ReceiptBurned), 'burned',
  'held'
) AS status,
token, blockedNonce, amount, block_num, tx_hash
FROM TransferBlocked
WHERE receiver = '0xec0eca588024e2d0091e74bd9034ff581111ea7f'
ORDER BY block_num DESC
LIMIT 10
```

```bash
curl --get "https://indexer.tempo.xyz/query" \
  --data-urlencode "chainId=4217" \
  --data-urlencode "engine=clickhouse" \
  --data-urlencode "signature=TransferBlocked(address indexed token, address indexed receiver, uint64 indexed blockedNonce, uint256 amount, uint8 receiptVersion, bytes receipt)" \
  --data-urlencode "signature=ReceiptClaimed(address indexed token, address indexed receiver, uint64 indexed blockedNonce, uint64 blockedAt, uint8 receiptVersion, address originator, address recipient, address recoveryAuthority, address caller, address to, uint256 amount)" \
  --data-urlencode "signature=ReceiptBurned(address indexed token, address indexed receiver, uint64 indexed blockedNonce, uint64 blockedAt, uint8 receiptVersion, address originator, address recipient, address recoveryAuthority, address caller, uint256 amount)" \
  --data-urlencode "sql@query.sql"
```

Here the receiver claims a held payment to itself. `blockedReceipt` holds those `receipt` bytes:

```ts [claim.ts]
import { client } from './client'

await client.receivePolicy.claimSync({ account, to: receiver, receipt: blockedReceipt }) // [!code hl]
```

A claim releases the receipt's full amount. Partial claims aren't supported. When a recovery authority other than `address(0)` claims back to the receiver, Tempo doesn't recheck the receive policy. The payment completes under the token's own policy. Claim only payments your application has approved. Every other claim, including any claim under an `address(0)` recovery authority, is a reroute with extra checks.

<span id="burn-blocked-receipts" />

<span id="receive-policy-limits" />

The token's issuer can instead [burn a held payment](https://tempo.xyz/developers/docs/protocol/tip403/receive-policies#claims). It calls `burnBlockedReceipt` from an account with the token's `BURN_BLOCKED_ROLE`. The burn works only while the token's own policy bars the receipt's subject from sending. The subject is the payment's sender or minter under an `address(0)` recovery authority, and the receiver otherwise.

<span id="learn-more-about-receive-policies" />

## Related

[Account Policies](https://tempo.xyz/developers/docs/accounts/policies): Covers how receive policies and signing thresholds work together.

[TIP-403 Receive Policies](https://tempo.xyz/developers/docs/protocol/tip403/receive-policies): Covers receive policy configuration, claims, and burns in the protocol.

[Tempo Policy Registry (TIP-403) Specification](https://tempo.xyz/developers/docs/protocol/tip403/spec): Covers the registry of allowlists and blocklists.

[Virtual Addresses](https://tempo.xyz/developers/docs/accounts/virtual-addresses): Covers addresses that use their master address's receive policy.
