Skip to main content

Full Liquidation Payout

Overview

This guide explains how to configure POST /workflows/onchain-deposit-to-payment-method for full crypto liquidation (sell the entire deposited crypto as a fiat payout), including the required sell/prepare step and field mapping.

This recipe covers:

  • SingleOnchainDepositSourceTriggerInput with FiatAmount omitted
  • PermanentOnchainDepositSourceTriggerInput (where FiatAmount must be omitted)
  • Operational behavior for overlap, matching precedence, and NetworkAgnostic

Example Scenario

Consider a platform that receives USDC_TEST and configures a full-liquidation payout workflow:

  • CustomerID: The customer initiating the transaction/workflow.
  • Payout recipient destination: Defined during sell/prepare through PaymentMethodID or form data (Form / FormSessionID).
  • Input: USDC deposits into a configured source address.
  • Output: Fiat payout created from the deposited crypto amount.
  • Execution model: Single-run or permanent source-trigger rule depending on your use case.

Recipe

Implement a scenario as described above by following the steps below.

1. Set Up the Environment

Register Your Interest

  1. Register your interest or book a demo by contacting us on business@noah.com.
  2. Signup for a Sandbox account and contact us to upgrade it to a business account.

Authentication & Request Signing

For guidance on generating and configuring your API keys, see the Authentication page.

  1. Generate your Sandbox API key via the Business Dashboard.
  2. Include your API key in the X-Api-Key header of all requests.
  3. Request Signing is optional in Sandbox and required in Production. It is important to setup Request Signing before migrating to Production, to do this see the Request Signing page.

Webhook Configuration

For guidance on webhook subscriptions and configuration, see the Configuration page.

  1. Optionally whitelist Noah's Webhook IP addresses, detailed on the Whitelisting section.
  2. Create a webhook subscription for the following event type, the details required to ingest the webhooks are also available on the respective page.
2. Create a Customer

Create a customer, if not already created, via the PUT customers/:CustomerID endpoint.

curl -L -X PUT 'https://api.sandbox.noah.com/v1/customers/:CustomerID' \
-H 'Content-Type: application/json' \
-H 'X-Api-Key: <X-Api-Key>' \
--data-raw '{
"Type": "Individual",
"FullName": {
"FirstName": "string",
"LastName": "string",
"MiddleName": "string"
},
"DateOfBirth": "2024-04-16",
"Email": "user@example.com",
"PhoneNumber": "string",
"Identities": [
{
"IssuingCountry": "US",
"IDNumber": "string",
"IssuedDate": "2024-04-16",
"ExpiryDate": "2024-04-16",
"IDType": "Passport"
}
],
"PrimaryResidence": {
"Street": "string",
"Street2": "string",
"City": "string",
"PostCode": "string",
"State": "string",
"Country": "US"
}
}'
tip
  • When integrating under the Reliance Model, you must ensure that any customer executing a transaction has a valid and complete KYC Status in your system. As an alternative to the Reliance Model, use the Standard Model, in support of which a Hosted Onboarding journey is provided.
  • Ensure your CustomerID is stored against the compliance profile of the same customer, to reference when creating transactions.
3. Define the Payout Channel
  1. Retrieve the list of available countries by calling the GET channels/sell/countries endpoint.
curl -L 'https://api.sandbox.noah.com/v1/channels/sell/countries' \
-H 'Accept: application/json' \
-H 'X-Api-Key: <X-Api-Key>'
  1. Once you've determined that your country of interest is supported, retrieve the list of country-specific compatible payout channels by calling the GET channels/sell endpoint, providing, at least, your settlement CryptoCurrency, FiatCurrency, and Country.

    For example, to retrieve US-oriented payout channels, use values such as the below.

curl -L 'https://api.sandbox.noah.com/v1/channels/sell? \
Country=US& \
CryptoCurrency=USDC_TEST& \
FiatCurrency=USD& \
FiatAmount=100' \
-H 'Accept: application/json' \
-H 'X-Api-Key: <X-Api-Key>'
tip
  • Testnet faucets typically only drip small amounts of tokens to prevent abuse, which severely limits testing scenarios involving larger transactions or complex workflows. By deploying the USDC_TEST cryptocurrency, as used in the examples above, Noah removes these constraints and enables developers to conduct comprehensive testing with realistic transaction volumes, stress test applications properly, and simulate real-world scenarios without constantly waiting for faucet refills.
  • Determine the FiatCurrency as an ISO 4217 currency code.
  1. On success, a payout channel is returned per supported PaymentMethodTypes, such as BankAch, BankFedwire, and TokenizedCard.

For example, when you retrieve US-oriented payout channels, use the channel ID in the next step to generate the dynamic form for your payout channel of interest.

4. Render or Populate the Dynamic Form

Noah's Dynamic UI API gives you full control over your frontend while removing the complexity of handling conditional, ever-evolving payment flows.

  1. Call the GET channels/:ChannelID/form endpoint with the value of the ID of the payout channel to retrieve the payout channel's FormSchema.
curl -L 'https://api.sandbox.noah.com/v1/channels/a4c3f754-094b-5f73-9da9-e0f1cb367f31/form' \
-H 'Accept: application/json' \
-H 'X-Api-Key: <X-Api-Key>'
  1. On success, the FormSchema for the specified payout channel is generated and defines the payload that is returned.
tip

Render the FormSchema in your user interface to collect input from your customers, or populate the required fields from pre-existing data.

5. Prepare the Transaction

The POST transactions/sell/prepare endpoint provides the most accurate and up-to-date pricing estimate and pre-validates any form data supplied, working with an existing PaymentMethodID if available.

If called without an existing PaymentMethodID, all necessary fields will be requested; otherwise, only the missing fields will be requested.

On a successful call to the Prepare endpoint, you will receive a FormSessionID which can be used to submit the transaction.

  1. Retrieve your ChannelID, PaymentMethodID, CryptoCurrency, CustomerID and Form fields, from the previous steps.
  2. Call the POST transactions/sell/prepare endpoint.

You can fetch a customer's existing payment methods using the GET payment-methods endpoint.

Use CryptoAmount as an estimate for setup/validation. In full-liquidation workflows, final sold amount comes from the actual deposit, not from this estimate.

curl -L -X POST 'https://api.sandbox.noah.com/v1/transactions/sell/prepare' \
-H 'Content-Type: application/json' \
-H 'X-Api-Key: <X-Api-Key>' \
--data-raw '{
"ChannelID": "ch_123",
"CryptoCurrency": "USDC_TEST",
"CustomerID": "cust_123",
"CryptoAmount": "100",
"PaymentMethodID": "fpm_123"
}'

If PaymentMethodID is not available yet

You can provide form data instead (or continue an existing FormSessionID):

curl -L -X POST 'https://api.sandbox.noah.com/v1/transactions/sell/prepare' \
-H 'Content-Type: application/json' \
-H 'X-Api-Key: <X-Api-Key>' \
--data-raw '{
"ChannelID": "ch_123",
"CryptoCurrency": "USDC_TEST",
"CustomerID": "cust_123",
"CryptoAmount": "100",
"Form": {
"AccountHolderName": {
"AccountHolderType": "Individual",
"Name": {
"FirstName": "John",
"LastName": "Doe"
}
},
"AccountHolderAddress": {
"Address": "1001 Nakatomi street",
"City": "Los Angeles",
"PostalCode": "90013",
"State": "CA"
},
"BankDetails": {
"AccountNumber": "49373189",
"BankCode": "638857476"
},
"Reference": "scholar fee",
"PaymentPurpose": "education"
}
}'
tip

Prepare Endpoints and PaymentMethodIDs

The prepare endpoint's primary purposes are:

  • To get the most accurate and up-to-date pricing estimate.
  • To pre-validate any form data you have supplied, which works in conjunction with an existing PaymentMethodID.

If you call the forms endpoint without an existing PaymentMethodID, it will request the entire set of fields that Noah needs to collect as new data for instructing a payment to that channel.

If you call the forms endpoint with an existing PaymentMethodID, it will request only the fields that Noah doesn't yet have data for.

For example, let's say a Customer has already made an offramp on ChannelA. If they later come back to make another one, and you supply a valid PaymentMethodID in the forms response, Noah will not request data that has already been provided.

For a Customer's first transaction, they won't have any saved Payment Methods, and therefore you won't have a PaymentMethodID - it's an optional field.

6. Call the Workflow Endpoint

Use FormSessionID from Step 5.

A) Single rule payload (full payload with AmountConditions)

FiatAmount omitted means full liquidation for a single-run trigger.

curl -L -X POST 'https://api.sandbox.noah.com/v1/workflows/onchain-deposit-to-payment-method' \
-H 'Content-Type: application/json' \
-H 'X-Api-Key: <X-Api-Key>' \
--data-raw '{
"CustomerID": "cust_123",
"FormSessionID": "fs_from_prepare",
"CryptoCurrency": "USDC_TEST",
"ExternalID": "onchain-sell-single-001",
"Trigger": {
"Type": "SingleOnchainDepositSourceTriggerInput",
"SourceAddress": "0x1234567890abcdef1234567890abcdef12345678",
"Nonce": "single-rule-001",
"Expiry": "<FUTURE_RFC3339_TIMESTAMP>",
"Conditions": [
{
"Network": "Ethereum",
"AmountConditions": [
{
"ComparisonOperator": "GTEQ",
"Value": "10"
},
{
"ComparisonOperator": "LTEQ",
"Value": "10000"
}
]
}
]
}
}'

Set Expiry to a future RFC3339 timestamp (for example, current time + 24 hours).

B) Permanent rule payload (full payload)

For a permanent trigger, FiatAmount must not be provided.

curl -L -X POST 'https://api.sandbox.noah.com/v1/workflows/onchain-deposit-to-payment-method' \
-H 'Content-Type: application/json' \
-H 'X-Api-Key: <X-Api-Key>' \
--data-raw '{
"CustomerID": "cust_123",
"FormSessionID": "fs_from_prepare",
"CryptoCurrency": "USDC_TEST",
"ExternalID": "onchain-sell-permanent-001",
"Trigger": {
"Type": "PermanentOnchainDepositSourceTriggerInput",
"SourceAddress": "0x1234567890abcdef1234567890abcdef12345678",
"NetworkAgnostic": false,
"Conditions": [
{
"Network": "Ethereum"
}
]
}
}'
FAQ

1) Difference between Single... and Permanent... when FiatAmount == nil

  • SingleOnchainDepositSourceTriggerInput
    • one-time execution
    • requires Nonce and Expiry
    • requires AmountConditions per condition
    • with FiatAmount omitted, sells full deposited crypto amount
  • PermanentOnchainDepositSourceTriggerInput
    • recurring execution for matching deposits
    • no Nonce/Expiry
    • network-only conditions (AmountConditions are not part of this trigger type)
    • FiatAmount must be omitted

2) What full liquidation means

Noah uses the matched deposit crypto amount as the sell authorized amount and computes payout at execution-time market rate, net of fees.

3) Is there dust? Is refund needed?

Small deposits can become non-viable after fee/network constraints. In those paths, orchestration failure/compensation logic applies (including offset/refund handling where applicable). Manual refund is usually unnecessary but can be requested from Noah ops.

4) What if the endpoint is called again with a different network and source address?

  • Different SourceAddress: creates an independent trigger index/rule path.
  • Same SourceAddress:
    • Single: different Nonce creates another one-time rule; same Nonce is an idempotent retry.
    • Permanent: changed payload can create a newer rule version for that same trigger index.

5) What NetworkAgnostic does

NetworkAgnostic exists on permanent trigger input.

  • false: deposit network must match configured condition network.
  • true: network mismatch is allowed during matching, as long as currency/other trigger requirements match.

Use NetworkAgnostic=true only when your source-address operational model intentionally accepts cross-network deposits for the same permanent rule.

6) How to cancel/delete a permanent rule

The current public Business API schema does not expose a direct delete/disable endpoint for this workflow by RuleID.

Operationally:

  1. Stop presenting/using that source address.
  2. Rotate to a new source address/rule when needed.
  3. For hard disable/delete, coordinate with Noah support/ops.

7) Can single and permanent be set for the same customer and source address?

You can configure overlapping rules, but one deposit event does not execute two rules.

Matching engine behavior:

  1. Candidate rules are listed by trigger index (source-address keyed).
  2. Candidates are traversed in sorted order (descending by priority sort key).
  3. The first matching rule is selected; matcher returns immediately.

Practical precedence notes:

  • Fresher rules win; newer effective rules appear first in query order.
  • Because matching returns on first hit, avoid overlapping single+permanent rules on the same source unless this precedence behavior is intentionally part of your design.

Integration checklist

  1. Call POST /transactions/sell/prepare and obtain FormSessionID.
  2. Ensure form flow is complete (NextStep clear/resolved).
  3. Create workflow with POST /workflows/onchain-deposit-to-payment-method.
  4. Store returned RuleID for tracking/webhooks/support.
  5. For permanent flows, define clear source-address ownership and network strategy (NetworkAgnostic policy).