<!-- tempo-docs-context -->
> Source: [/docs/accounts/automations/pay-out-from-a-backend](https://tempo.xyz/developers/docs/accounts/automations/pay-out-from-a-backend.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.

# Pay Out From a Backend

Sends payouts from your backend with a key that can pay only approved payees, up to a daily limit.

## Overview

This guide builds a payout service that pays contractors, vendors, or sellers in stablecoins without holding the account's key. Nobody approves each payment.

The account's signers, your approvers or your customer's, approve an [access key](https://tempo.xyz/developers/docs/accounts/access-keys) once. Your backend keeps it in its KMS. Tempo lets that key pay only the [payees they list](https://tempo.xyz/developers/docs/accounts/access-keys/scopes), up to a [daily limit](https://tempo.xyz/developers/docs/accounts/access-keys/spending-limits). The key works until it [expires](https://tempo.xyz/developers/docs/accounts/access-keys/expiry) or is revoked. Until then, a leaked key still sends up to the limit each day, but only to those payees.

<span id="backend-services" />

<span id="automations" />

The demo and the code run on the Tempo Accounts devnet, a test network whose stablecoins have no value. The demo's customer account is a configurable account whose one signer is a device key in this browser. On mainnet and testnet, a single-key account authorizes a payout key the same way. Its key can be the customer's passkey.

In the interactive web page, a demo runs the steps that follow on the Tempo Accounts devnet with the reader's own signers: a passkey on their device, or keys the page generates. Each step that changes the account sends a devnet transaction and shows its hash, next to what changed in the app and on the account. It runs only where the page can reach Tempo Accounts devnet.

The code pays out a test stablecoin. You supply the undefined names:

* `account` and `address` are the customer's account and its address.
* `payees` are the addresses the key may pay, and `payee` is one of them.
* `payoutKeyAddress` is the KMS key's address.
* `kms`, `kmsKeyId`, and `kmsPublicKey` are your KMS client, key ID, and public key.

`client.ts` connects to the devnet ([set up the devnet key](https://tempo.xyz/developers/docs/accounts/create#connect-to-the-devnet)).

## Setup

::::steps
### Authorize a Scoped, Limited Key

Create one secp256k1 key per customer in your KMS. To pay contractors from your company's own account, create one key per payout service instead. Its address, derived from the public key, is the key's ID on Tempo. Send that address to the customer's app, where the customer's signers authorize it.

:::code-group
```ts [app/approve-payouts.ts]
import { parseUnits } from 'viem'
import { Expiry } from 'viem/tempo'
import { client } from '../client'

// A test stablecoin on the devnet
const stablecoin = '0x20c0000000000000000000000000000000000001'

await client.accessKey.authorizeSync({
  accessKey: { accessKeyAddress: payoutKeyAddress, keyType: 'secp256k1' },
  account, // the customer's account, signed by its signers, such as a passkey
  expiry: Expiry.days(90), // [!code hl]
  // 1,000 of the stablecoin a day
  limits: [{ token: stablecoin, limit: parseUnits('1000', 6), period: 86_400 }], // [!code hl]
  scopes: [ // [!code hl]
    { address: stablecoin, selector: 'transfer(address,uint256)', recipients: payees }, // [!code hl]
    { address: stablecoin, selector: 'transferWithMemo(address,uint256,bytes32)', recipients: payees }, // [!code hl]
  ], // [!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}`)}` } },
  }),
})
```
:::

Authorizing is one transaction the customer approves, for example with their passkey. Payouts then go out without prompting them. Show the customer the payees, daily limit, and expiry before they approve.

Limits are in base units. The stablecoin has 6 decimals, so `parseUnits('1000', 6)` is 1,000 OUSD. Size the limit to your largest payout day plus fees. Fees count against the limit unless a [fee payer](https://tempo.xyz/developers/docs/accounts/fees/fee-sponsorship) sponsors them.

### Keep the Key in Your KMS

The private key never leaves the KMS. Tempo stores only the key's address, payees, limit, and expiry. Wrap the key in a Viem account that asks the KMS for each signature.

```ts [backend/payout-key.ts]
import { PublicKey, Signature } from 'ox'
import { Account } from 'viem/tempo'

export const payoutKey = Account.from({ // [!code hl]
  access: address, // the customer's account address
  keyType: 'secp256k1',
  publicKey: PublicKey.fromHex(kmsPublicKey), // read once from your KMS
  async sign({ hash }) { // [!code hl]
    // your KMS client returns { r, s, yParity }
    return Signature.toHex(await kms.sign(kmsKeyId, hash)) // [!code hl]
  }, // [!code hl]
}) // [!code hl]
```

Anyone who can sign with the KMS key can send payouts within its bounds. In your KMS, allow only the payout service to sign with the key. Log each signing request so you can match it to a payout.

### Send Payouts

```ts [backend/send-payout.ts]
import { parseUnits, stringToHex } from 'viem'
import { client } from '../client'
import { payoutKey } from './payout-key'

// A test stablecoin on the devnet
const stablecoin = '0x20c0000000000000000000000000000000000001'

await client.token.transferSync({ // [!code hl]
  // the key signs for the customer's account
  account: payoutKey, // [!code hl]
  amount: parseUnits('250', 6), // [!code hl]
  // the fee counts against the key's daily limit
  feeToken: stablecoin, // [!code hl]
  // your payout ID, for reconciliation
  memo: stringToHex('payout-1042', { size: 32 }), // [!code hl]
  to: payee, // [!code hl]
  token: stablecoin, // [!code hl]
}) // [!code hl]
```

The customer isn't prompted. Tempo rejects three kinds of payout:

* To an address outside `payees`.
* Over what's left of today's limit.
* After the key expires.

To stop payouts, have the signers [revoke the key](https://tempo.xyz/developers/docs/accounts/access-keys/revocation#revoke-an-access-key).
::::

<span id="recommended-limits-for-common-automations" />

<span id="recommended-limits-for-backend-automations" />

<span id="troubleshoot-backend-payments" />

<span id="payout-limits" />

<span id="before-you-go-live" />

## Production Checklist

* **Concurrent Payouts:** An account's transactions share one nonce, a counter that orders them, so payouts confirm one at a time by default. To send them concurrently, use [expiring nonces or nonce keys](https://tempo.xyz/developers/docs/guide/payments/send-parallel-transactions).
* **New Payees:** To add a payee, the signers or an [admin key](https://tempo.xyz/developers/docs/accounts/access-keys/admin-access-keys) update the key's [scopes](https://tempo.xyz/developers/docs/accounts/access-keys/scopes#change-allowed-calls).
* **Expiry:** An expiry can't be extended. [Authorize a replacement key](https://tempo.xyz/developers/docs/accounts/access-keys/expiry#renew-an-expiring-key) before it passes.

## Move Idle Funds Into Earn

Balances waiting for the next payout run can sit in an [Earn](https://tempo.xyz/developers/docs/earn) vault. Use a separate key scoped to the vault's `approve` and `deposit` calls, so the payout key still pays only payees. Follow [Deposit](https://tempo.xyz/developers/docs/earn/integrate) for the vault checks.

## Related

[Access Keys](https://tempo.xyz/developers/docs/accounts/access-keys): Covers the keys an account authorizes with limits, scopes, and expiry.

[Scopes](https://tempo.xyz/developers/docs/accounts/access-keys/scopes): Covers which contracts, functions, and recipients a key can use.

[Spending Limits](https://tempo.xyz/developers/docs/accounts/access-keys/spending-limits): Covers budgets per stablecoin and how they renew.

[Revocation](https://tempo.xyz/developers/docs/accounts/access-keys/revocation): Covers ending an access key's access for good.
