> ## Documentation Index
> Fetch the complete documentation index at: https://docs.portalhq.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Noah virtual accounts and payouts

> Use portal.ramps.noah in the Web SDK for Noah KYC, payins, payouts, and quotes via the Portal iframe and Client API.

The Web SDK exposes [Noah](/integrations/On-Off-Ramp/noah) virtual accounts and global payouts through `portal.ramps.noah`. Each method sends a message to the embedded Portal iframe, which calls Portal’s Noah integration on the [Client API](/apis/quickstart) using your client credentials. You do not call Noah’s servers directly from the browser.

<Note>
  For dashboard setup, signing keys, and supported CAIP-2 networks, see [Noah integration overview](/integrations/On-Off-Ramp/noah). For HTTP shapes and webhooks, see the [Noah workflow guides](/integrations/On-Off-Ramp/noah#workflow-guides) and [Noah Business API / EMM documentation](https://docs.noah.com/).
</Note>

## Prerequisites

* An [initialized Portal client](./getting-started) with the iframe ready (`onReady` or equivalent).
* Noah enabled for your Portal environment and [configured in the dashboard](/integrations/On-Off-Ramp/noah).
* For payins and payouts, the end user must complete [Noah KYC](/integrations/On-Off-Ramp/noah-kyc) with approved status before those flows succeed.

## Architecture

| Layer             | Role                                                                                     |
| ----------------- | ---------------------------------------------------------------------------------------- |
| Your app          | Calls `portal.ramps.noah.*`                                                              |
| Portal Web SDK    | `postMessage` bridge to the Portal iframe (do not call `Mpc` directly)                   |
| Portal iframe     | Forwards to `POST/GET …/api/v3/clients/me/integrations/noah/...` with the Portal session |
| Noah (via Portal) | Hosted KYC, banking rails, settlement                                                    |

Prefer `portal.ramps.noah` over lower-level APIs. The SDK types for requests and responses live in `@portal-hq/web` (see the [Web SDK reference](../reference) section **portal.ramps.noah (Noah)**).

## Types and responses

Successful Client API responses use an envelope `{ data: T, metadata?: Record<string, unknown> }`. Methods on `portal.ramps.noah` return `Promise` of that envelope (for example `NoahInitiateKycResponse` is `{ data: { hostedUrl: string } }`).

Throwing or rejected promises usually indicate network errors, iframe timeouts, or API error payloads surfaced by the SDK—handle them with `try/catch` like other async Portal calls.

## initiateKyc

Starts hosted Noah onboarding. Open `data.hostedUrl` in a new browser context (for example `window.open` with `noopener,noreferrer`). Validate **HTTPS** and the **hostname** against the checkout domains Noah documents for your environment (extend the example allowlist accordingly).

```typescript theme={null}
import Portal from '@portal-hq/web';

const portal = new Portal({
  rpcConfig: { 'eip155:1': 'https://...' },
  apiKey: 'YOUR_API_KEY',
});

portal.onReady(async () => {
  const { data } = await portal.ramps.noah.initiateKyc({
    returnUrl: 'https://yourapp.example/noah/return',
    fiatOptions: [{ fiatCurrencyCode: 'USD' }],
    customerType: 'Individual',
  });

  const url = new URL(data.hostedUrl);
  const allowedHosts = new Set([
    'checkout.noah.com',
    'checkout.sandbox.noah.com',
    'staging-checkout.noah.com',
  ]);
  if (url.protocol !== 'https:' || !allowedHosts.has(url.hostname)) {
    throw new Error('Invalid KYC URL host or scheme');
  }
  window.open(url.toString(), '_blank', 'noopener,noreferrer');
});
```

**Signature**

```typescript theme={null}
public async initiateKyc(data: NoahInitiateKycRequest): Promise<NoahInitiateKycResponse>
```

| Parameter           | Type                             | Required | Description                                             |
| ------------------- | -------------------------------- | -------- | ------------------------------------------------------- |
| `data.returnUrl`    | `string`                         | Yes      | HTTPS URL where Noah returns the user after onboarding. |
| `data.fiatOptions`  | `{ fiatCurrencyCode: string }[]` | No       | Fiat currencies to present in onboarding.               |
| `data.customerType` | `'Individual' \| 'Business'`     | No       | Onboarding flow variant.                                |
| `data.metadata`     | `Record<string, unknown>`        | No       | Opaque metadata forwarded per API rules.                |
| `data.form`         | `Record<string, unknown>`        | No       | Optional prefill payload for hosted forms.              |

**Returns** — `NoahInitiateKycResponse`: `{ data: { hostedUrl: string } }`.

<Note>
  This call only starts onboarding; KYC outcome and status changes arrive asynchronously via Noah **`Customer`** webhooks. See [Noah webhooks](/integrations/On-Off-Ramp/noah-webhooks).
</Note>

See also: [Noah KYC guide](/integrations/On-Off-Ramp/noah-kyc), [Noah hosted flows](https://docs.noah.com/).

## initiatePayin

Creates a fiat-to-stablecoin payin and returns bank instructions and a `payinId`. Use a [supported CAIP-2 network](/integrations/On-Off-Ramp/noah#supported-networks) and the user’s wallet address as `destinationAddress`.

```typescript theme={null}
const { data } = await portal.ramps.noah.initiatePayin({
  fiatCurrency: 'USD',
  cryptoCurrency: 'USDC_TEST',
  network: 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1',
  destinationAddress: 'SoLAddr1111111111111111111111111111111111111',
});

console.log(data.payinId, data.bankDetails);
```

**Signature**

```typescript theme={null}
public async initiatePayin(data: NoahInitiatePayinRequest): Promise<NoahInitiatePayinResponse>
```

| Parameter                 | Type     | Required | Description                                                              |
| ------------------------- | -------- | -------- | ------------------------------------------------------------------------ |
| `data.fiatCurrency`       | `string` | Yes      | Fiat currency code (for example `USD`).                                  |
| `data.cryptoCurrency`     | `string` | Yes      | Noah crypto asset code (for example stablecoin test symbols in sandbox). |
| `data.network`            | `string` | Yes      | CAIP-2 chain identifier.                                                 |
| `data.destinationAddress` | `string` | Yes      | Address that receives crypto after settlement.                           |

**Returns** — `NoahInitiatePayinResponse`: `{ data: { payinId: string; bankDetails: BankDetails } }`.

`BankDetails` includes:

* `paymentMethodId` — payment method identifier
* `paymentMethodType` — payment rail type
* `accountNumber` — bank account number
* `network` — network identifier
* `accountHolderName?` — optional account holder name
* `bankCode?` — optional bank routing/sort code
* `bankName?` — optional bank name
* `bankAddress?` — optional bank address with `city`, `country`, `line1`, `line2`, `postalCode`, `state`
* `reference?` — optional payment reference
* `relatedPaymentMethods?` — optional array of related payment methods

<Note>
  Payin lifecycle updates are asynchronous; track them with Noah **`FiatDeposit`** and **`Transaction`** webhooks, not by polling this SDK response. See [Noah webhooks](/integrations/On-Off-Ramp/noah-webhooks).
</Note>

See also: [Payins](/integrations/On-Off-Ramp/noah-payins), [FiatDeposit webhooks](https://docs.noah.com/api-concepts/webhooks/fiat-deposits/).

## simulatePayin

Sandbox-oriented call to estimate fees or eligibility for a payin without creating a live payin. Typical body includes a Noah `paymentMethodId` and fiat amount.

```typescript theme={null}
await portal.ramps.noah.simulatePayin({
  paymentMethodId: 'pm-1',
  fiatAmount: '10',
  fiatCurrency: 'USD',
});
```

**Signature**

```typescript theme={null}
public async simulatePayin(data: NoahSimulatePayinRequest): Promise<NoahSimulatePayinResponse>
```

| Parameter              | Type     | Required | Description                          |
| ---------------------- | -------- | -------- | ------------------------------------ |
| `data.paymentMethodId` | `string` | Yes      | Payment method identifier from Noah. |
| `data.fiatAmount`      | `string` | Yes      | Fiat amount as a string (decimal).   |
| `data.fiatCurrency`    | `string` | Yes      | Fiat currency code.                  |

**Returns** — `NoahSimulatePayinResponse`: `{ data: { fiatDepositId: string } }`.

## getPayoutCountries

Lists countries available for fiat payouts.

```typescript theme={null}
const { data } = await portal.ramps.noah.getPayoutCountries();
console.log(data.countries);
```

**Signature**

```typescript theme={null}
public async getPayoutCountries(): Promise<NoahGetPayoutCountriesResponse>
```

**Returns** — `NoahGetPayoutCountriesResponse`: `{ data: { countries: Record<string, string[]> } }`.

## getPayoutChannels

Returns payout rails for a country and currency pair. Optional `fiatAmount` can refine channel availability.

```typescript theme={null}
const { data } = await portal.ramps.noah.getPayoutChannels({
  country: 'US',
  cryptoCurrency: 'USDC_TEST',
  fiatCurrency: 'USD',
  fiatAmount: '10',
});
```

**Signature**

```typescript theme={null}
public async getPayoutChannels(data: NoahGetPayoutChannelsRequest): Promise<NoahGetPayoutChannelsResponse>
```

| Parameter             | Type     | Required | Description                                          |
| --------------------- | -------- | -------- | ---------------------------------------------------- |
| `data.country`        | `string` | Yes      | ISO country code (for example `US`).                 |
| `data.cryptoCurrency` | `string` | Yes      | Crypto asset code for the payout leg.                |
| `data.fiatCurrency`   | `string` | Yes      | Fiat currency for the payout.                        |
| `data.fiatAmount`     | `string` | No       | Optional amount string used for filtering or quotes. |

**Returns** — `NoahGetPayoutChannelsResponse`: `{ data: { items: Channel[]; pageToken?: string } }`.

Each `Channel` includes:

* `id` — channel identifier
* `paymentMethodType` — payment rail type
* `fiatCurrency` — fiat currency code
* `country` — ISO country code
* `limits` — `{ minLimit: string; maxLimit?: string }`
* `rate` — exchange rate as a string
* `processingSeconds` — estimated settlement time
* `calculated?` — optional `{ totalFee: string }`

See also: [Payouts](/integrations/On-Off-Ramp/noah-payouts).

## getPayoutChannelForm

Loads the dynamic form schema for a channel so you can collect recipient fields before requesting a quote.

```typescript theme={null}
const { data } = await portal.ramps.noah.getPayoutChannelForm('ch-1');
// Render form fields from `data` per Noah’s schema
```

**Signature**

```typescript theme={null}
public async getPayoutChannelForm(channelId: string): Promise<NoahGetPayoutChannelFormResponse>
```

| Parameter   | Type     | Required | Description                                  |
| ----------- | -------- | -------- | -------------------------------------------- |
| `channelId` | `string` | Yes      | Channel identifier from `getPayoutChannels`. |

**Returns** — `NoahGetPayoutChannelFormResponse`: `{ data: { formSchema?: Record<string, unknown>; formMetadata?: { contentHash: string } } }`.

## getPayoutQuote

Requests fees and crypto amount estimates for a payout. Include `form` when the channel requires recipient data.

```typescript theme={null}
const { data } = await portal.ramps.noah.getPayoutQuote({
  channelId: 'ch-1',
  cryptoCurrency: 'USDC_TEST',
  fiatAmount: '10',
  form: { /* channel-specific fields */ },
});

console.log(data.payoutId, data.formSessionId, data.cryptoAmountEstimate, data.totalFee);
```

**Signature**

```typescript theme={null}
public async getPayoutQuote(data: NoahGetPayoutQuoteRequest): Promise<NoahGetPayoutQuoteResponse>
```

| Parameter              | Type                      | Required | Description                             |
| ---------------------- | ------------------------- | -------- | --------------------------------------- |
| `data.channelId`       | `string`                  | Yes      | Payout channel id.                      |
| `data.cryptoCurrency`  | `string`                  | Yes      | Crypto asset for the quote.             |
| `data.fiatAmount`      | `string`                  | Yes      | Fiat amount as a string.                |
| `data.form`            | `Record<string, unknown>` | No       | Recipient fields from the channel form. |
| `data.fiatCurrency`    | `string`                  | No       | Fiat currency override when needed.     |
| `data.paymentMethodId` | `string`                  | No       | Payment method hint when applicable.    |

**Returns** — `NoahGetPayoutQuoteResponse`: `{ data: { payoutId: string; totalFee: string; cryptoAmountEstimate: string; formSessionId: string; nextStep?: FormNextStep } }`.

When present, `nextStep` includes:

* `stepId` — step identifier
* `stepType` — `'Ack'` or `'DataEntry'`
* `schema` — form schema for the next step

## initiatePayout

Executes a payout after quoting. For crypto-sourced payouts you may need to pass deposit `conditions` from the quote response via a `trigger` payload; align with [Payouts](/integrations/On-Off-Ramp/noah-payouts) and Noah’s on-chain deposit triggers.

```typescript theme={null}
const payoutId = 'p1';
const expiry = new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString().replace(/\.\d{3}Z$/, 'Z');
// Use a stable nonce per payout attempt (max 36 chars; reuse on retries)
const nonce = crypto.randomUUID();

const { data } = await portal.ramps.noah.initiatePayout({
  payoutId,
  sourceAddress: 'SoLAddr1111111111111111111111111111111111111',
  expiry,
  nonce,
  network: 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1',
});

console.log(data.destinationAddress, data.conditions);
```

**Signature**

```typescript theme={null}
public async initiatePayout(data: NoahInitiatePayoutRequest): Promise<NoahInitiatePayoutResponse>
```

| Parameter            | Type                                         | Required | Description                                                                                                                                   |
| -------------------- | -------------------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `data.payoutId`      | `string`                                     | Yes      | Identifier from `getPayoutQuote`.                                                                                                             |
| `data.sourceAddress` | `string`                                     | Yes      | Address funding the crypto leg when applicable.                                                                                               |
| `data.expiry`        | `string`                                     | Yes      | ISO-8601 expiry for the deposit authorization.                                                                                                |
| `data.nonce`         | `string`                                     | Yes      | Stable nonce for this payout attempt; **reuse on retry** so repeated calls stay idempotent. Must be ≤ 36 characters per Noah API constraints. |
| `data.network`       | `string`                                     | Yes      | CAIP-2 network for the deposit leg.                                                                                                           |
| `data.trigger`       | `NoahSingleOnchainDepositSourceTriggerInput` | No       | Structured trigger when Noah requires explicit on-chain deposit conditions.                                                                   |

**Returns** — `NoahInitiatePayoutResponse`: `{ data: { destinationAddress: string | null; conditions: DepositSourceTriggerCondition[] } }`.

Each `DepositSourceTriggerCondition` includes:

* `amountConditions` — array of `{ comparisonOperator: string; value: string }`
* `cryptoCurrency` — crypto asset code
* `network` — CAIP-2 network identifier
* `destinationAddress` — destination address for the deposit

<Note>
  After this call returns `destinationAddress` and `conditions`, submit the onchain transfer to satisfy them. You can do this with any wallet — including Portal's own [send method](/sdks/web/guide/send-tokens) (`portal.sendAsset(...)`) on the same `Portal` instance, which builds, signs, and broadcasts in one call.
</Note>

<Note>
  This call initiates the payout flow; completion and failures are reported asynchronously via Noah **`Transaction`** webhooks. See [Noah webhooks](/integrations/On-Off-Ramp/noah-webhooks).
</Note>

See also: [Transaction events](https://docs.noah.com/api-concepts/webhooks/transactions/), [automated payout recipes](https://docs.noah.com/recipes/payout/automated-payouts).

## getPaymentMethods

Returns payment methods available to the customer (for example cards or bank rails), including pagination tokens when present.

```typescript theme={null}
const { data } = await portal.ramps.noah.getPaymentMethods();
console.log(data.paymentMethods, data.pageToken);
```

**Signature**

```typescript theme={null}
public async getPaymentMethods(): Promise<NoahGetPaymentMethodsResponse>
```

**Returns** — `NoahGetPaymentMethodsResponse`: `{ data: { paymentMethods: PaymentMethod[]; pageToken?: string } }`.

Each `PaymentMethod` includes:

* `id` — payment method identifier
* `paymentMethodType` — payment rail type
* `details` — payment method details with `type`, optional `accountNumber`, `bankCode`, `last4`, `scheme`, `identifierType`, `identifier`
* `accountHolderDetails?` — optional holder info with `name`, `taxId`, `email`, `phoneNumber`, `address`
* `issuerDetails?` — optional issuer info with `name`, `bankCode`, `bankName`

## Error handling

Wrap calls in `try/catch`. Log or surface errors without printing full API responses in production if they might contain sensitive identifiers. Retry only for idempotent reads unless your product team confirms otherwise.

## Related documentation

* [Web SDK reference — Noah](../reference) (section **portal.ramps.noah (Noah)**)
* [Noah integration overview](/integrations/On-Off-Ramp/noah)
* [KYC](/integrations/On-Off-Ramp/noah-kyc), [Payins](/integrations/On-Off-Ramp/noah-payins), [Payouts](/integrations/On-Off-Ramp/noah-payouts), [Webhooks](/integrations/On-Off-Ramp/noah-webhooks)
* [Noah docs — API concepts](https://docs.noah.com/api-concepts/transactions/)
* [Noah docs — authentication & signing](https://docs.noah.com/api-concepts/authentication/signing/)
