<!--
Sitemap:
- [Welcome to Kakushi 隠し](/index): Kakushi is a private execution layer for institutions building on stablecoin rails.
- [What is Kakushi](/introduction/what-is-kakushi): Money is private.
- [Using Kakushi with AI](/introduction/using-kakushi-with-ai): Every page in these docs is available as plain markdown for use with language models.
- [Quickstart](/quickstart): This is the ten minute path.
- [Zones and the trust model](/concepts/zones-and-trust): A zone is a private blockchain only you can see inside, with a public chain's proofs underneath.
- [The portal](/concepts/the-portal): Money walks in as public USDC and becomes private the moment it crosses.
- [Accounts and custody](/concepts/accounts-and-custody): Your existing wallet address is already a Kakushi account. Nothing to deploy, nothing to enroll.
- [Bring your own address](/concepts/bring-your-own-address): A zone account is just an address, the one an auth key recovers to, with nothing deployed.
- [Virtual addresses](/concepts/virtual-addresses): Hand every customer their own address, the way a bank hands out virtual account numbers.
- [Private transfers](/concepts/private-transfers): Pay fifty thousand people and publish zero salaries.
- [Settlement and composability](/concepts/settlement-and-composability): Two institutions settle in real time without sharing a ledger or seeing each other's books.
- [Private deposits and withdrawals](/concepts/private-deposits-and-withdrawals): Soon, even the edges go dark.
- [Proofs and the verifier](/concepts/proofs-and-the-verifier): You cannot fake a balance, and you can prove you are solvent without showing a single customer.
- [Fees and gas](/concepts/fees-and-gas): Your users never hold ETH and never see gas. They pay in the dollars they are already sending.
- [Privacy and disclosure](/concepts/privacy-and-disclosure): The public sees nothing, you see everything, the regulator sees what the law entitles them to.
- [Zone policies](/concepts/zone-policies): Compliance is built into the zone. You configure your program; the substrate enforces it on every transfer.
- [Onboard a customer](/guides/onboard-a-customer): Two calls and a webhook, and your customer has a private on-chain account.
- [Accept deposits](/guides/accept-deposits): Anyone with funds on the host chain can pay into your zone, and it lands as a private balance for your user.
- [Make private transfers](/guides/private-transfers): One call moves money privately. One call pays a whole payroll.
- [Process withdrawals](/guides/withdrawals): Burn inside, release canonical USDC outside, in one call.
- [Settle between zones](/guides/settle-between-zones): Send money to another institution's zone like it is a withdrawal. It is interbank settlement.
- [Handle webhooks](/guides/webhooks): React to money moving. Do not poll for it.
- [Reconcile](/guides/reconcile): Two numbers that must always match. Assert it on a schedule.
- [Non-custodial integration](/guides/non-custodial-integration): The user signs on their device. You never hold the key, and you still cannot move their money.
- [Compliance and disclosure](/guides/compliance): You hold the whole record. Disclosure is an export, not a negotiation with the protocol.
- [SDK reference](/sdk-reference): The look-it-up layer.
- [Connect and EVM reference](/connect-and-evm-reference): The chain-level integration detail.
- [Run a zone](/run-a-zone): Most operators never run any infrastructure.
- [Protocol spec](/protocol-spec): The deep technical layer, for auditors and engineers integrating below the SDK.
- [Resources](/resources): See Key concepts for the working vocabulary, expanded throughout Core concepts.
-->

# Onboard a customer

This is the whole onboarding flow, end to end. By the time you finish reading it, you have given a customer a private on-chain account and a way to fund it. There is no wallet for them to install and no chain for them to learn.

![The onboarding flow: create account, hand out a virtual address, receive a deposit webhook](/images/guides/onboard-a-customer.svg)

Create the account with a viem account you hold for the customer. It costs nothing and writes nothing to the zone until money arrives.

```ts
import { privateKeyToAccount } from "viem/accounts";

// load the key from your own secret store / env; the SDK never sees the raw key
const aliceAccount = privateKeyToAccount(process.env.ALICE_PRIVATE_KEY as `0x${string}`);

// the account is its address; tag it with your own labels in metadata
const { address, virtualAddress } = await kakushi.accounts.create({
  account: aliceAccount,
  metadata: { customerId: "alice" },
});
// show `virtualAddress` to the customer, or to whoever is paying them
```

The payer sends USDC to that address from any wallet, with no awareness of Kakushi. When it lands, you get a webhook and the balance appears in the zone. The `customerId` you put in `metadata` comes back on the event, stored by the node against the account, so you need no lookup table of your own.

```ts
// your webhook handler
if (event.type === "deposit.credited") {
  // event.metadata.customerId is the label you attached at claim time
  creditCustomer(event.metadata.customerId);
}
```

```ts
import { privateKeyToAccount } from "viem/accounts";

// alice's account; the key lives in your secret store, the SDK never sees it
const aliceAccount = privateKeyToAccount(process.env.ALICE_PRIVATE_KEY as `0x${string}`);

const balance = await kakushi.balances.get(aliceAccount, { token: "USDC" });
```

:::tip
The account materializes on first deposit, so you can hand out a virtual address before the customer has ever touched the zone. The sender does not need to know whether the recipient "exists" yet.
:::
