<a id="withdraw-pathusd-from-a-tempo-zone-on-testnet" />

# Withdraw OUSD from a Tempo Zone on testnet

Withdraw tokens from a private Zone back to your public Tempo balance. This example uses `OUSD` test tokens in **Zone A**, the example Zone on Tempo Testnet.

A signed Zone A outbox request reduces the private balance. Tempo accepts the batch, then processes the withdrawal to deliver OUSD to the public recipient.

Direct withdrawals exit through `ZoneOutbox` on the zone chain. You submit the withdrawal request in the zone first, then wait for the public balance to increase after the batch settles.

<a id="withdrawing-pathusd-from-zone-a" />

## Withdrawing OUSD from Zone A

By the end of this guide you will have withdrawn `OUSD` from `Zone A` and confirmed the balance update on the public chain.

**Interactive demo: Withdraw from Zone A**

1. Withdraw from zone

## Code examples

These snippets assume you already have a signed-in `rootClient` on the public chain, a derived `zoneAClient`, and the usual token constants in scope.

These calls target the shared testnet deployment's SDK interfaces. Check the [testnet compatibility notes](https://tempo.xyz/developers/docs/guide/private-zones#testnet-compatibility) before using them with another Zone.

Standard withdrawals omit an encrypted sender disclosure. Authenticated withdrawals attach sender details encrypted to the holder of the `revealTo` public key. The public recipient and amount remain visible in both flows.

### Standard

```ts
import { parseUnits } from 'viem'
import { Actions } from 'viem/tempo'

const withdrawalAmount = parseUnits('100', 6)

await zoneAClient.zone.signAuthorizationToken()

const { receipt } = await Actions.zone.requestWithdrawalSync(zoneAClient, {
  account: rootClient.account,
  feeToken: ousd,
  amount: withdrawalAmount,
  token: ousd,
  to: rootClient.account.address,
})

console.log(receipt.blockNumber)
```

### Authenticated

```ts
import { parseUnits } from 'viem'
import { Actions } from 'viem/tempo'

const withdrawalAmount = parseUnits('100', 6)
const revealTo = '0x031dc147467e8f106eb22850fef549dc74b8f6634aeac554ebdd4ab896b67cdf68' // [!code focus]

await zoneAClient.zone.signAuthorizationToken()

const { receipt } = await Actions.zone.requestVerifiableWithdrawalSync(zoneAClient, { // [!code focus]
  account: rootClient.account,
  feeToken: ousd,
  amount: withdrawalAmount,
  revealTo, // [!code focus]
  token: ousd,
  to: rootClient.account.address,
})

console.log(receipt.blockNumber)
```

## What a Direct Withdrawal Does

A direct withdrawal is the simplest way to exit a zone. You ask `ZoneOutbox` on the zone to burn the zone balance, include the request in the next withdrawal batch, and settle the amount back to a public Tempo address.

Like deposits, withdrawals settle in phases. The request is accepted on the zone first, and the public balance changes later when the sequencer submits and processes the corresponding batch on Tempo.

If Tempo-side processing fails, the withdrawal does not stay stuck in limbo. The protocol re-deposits the withdrawal amount back into the zone to the request's `fallbackRecipient`. The fee is still consumed.

:::warning
Even with `gas: 0n`, a direct withdrawal can still fail on Tempo—for example because of token transfer or policy checks. In that case, the amount bounces back to `fallbackRecipient` on the zone instead of increasing the public balance.
:::
