Skip to main content

Overview

Noah payouts let your client convert crypto to fiat and disburse through local payout rails.

1. Prerequisite: approved KYC

Ensure the client has completed Noah onboarding and has APPROVED status. See Noah KYC onboarding.

2. Get supported payout countries

curl --request GET \
  --url https://api.portalhq.io/api/v3/clients/me/integrations/noah/payouts/countries \
  --header 'Authorization: Bearer [token]'
The countries map includes many additional country/currency combinations based on Noah support.

3. Get payout channels

Call GET /payouts/channels with country, cryptoCurrency, and fiatCurrency.
curl --request GET \
  --url 'https://api.portalhq.io/api/v3/clients/me/integrations/noah/payouts/channels?country=BR&cryptoCurrency=USDC_TEST&fiatCurrency=BRL' \
  --header 'Authorization: Bearer [token]'
fiatAmount is optional on channels lookup and can improve quote context. pageToken is also optional and can be used to fetch the next page when returned.

4. (Optional) Get saved payment methods

Call GET /payouts/payment-methods to list saved payout destinations for the approved customer. If you want to use a saved payout destination, you can pass its id as paymentMethodId in POST /payouts/quote.
curl --request GET \
  --url https://api.portalhq.io/api/v3/clients/me/integrations/noah/payouts/payment-methods \
  --header 'Authorization: Bearer [token]'
Example response (truncated to key fields):
{
  "data": {
    "paymentMethods": [
      {
        "id": "Bank/Ach/USD/021000021/123456789/cmmw6tzqc00003saqzbgwueb5",
        "paymentMethodCategory": "Bank",
        "customerId": "cmmw6tzqc00003saqzbgwueb5",
        "country": "US",
        "capabilities": {
          "payinTo": false,
          "payoutFrom": false,
          "payoutTo": true
        },
        "displayDetails": {
          "type": "FiatPaymentMethodBankDisplay",
          "accountNumber": "123456789",
          "bankCode": "021000021"
        },
        "accountHolderDetails": {
          "name": {
            "firstName": "John",
            "lastName": "Mock-Doe"
          }
        },
        "issuerDetails": {}
      }
    ]
  }
}
pageToken may also be present when pagination is returned.

5. Get dynamic form for selected channel

Use GET /payouts/channels/:channelId/form and render the returned formSchema.
curl --request GET \
  --url https://api.portalhq.io/api/v3/clients/me/integrations/noah/payouts/channels/[channelId]/form \
  --header 'Authorization: Bearer [token]'
Example response (truncated to key fields):
{
  "data": {
    "formMetadata": {
      "contentHash": "eda5d74d98e3e7429644fd7f74d4979638eca0e9aa7422091a600d85c1f3422a"
    },
    "formSchema": {
      "$schema": "http://json-schema.org/draft-07/schema#",
      "type": "object",
      "properties": {
        "AccountHolderName": {
          "type": "object",
          "title": "Account Holder Name"
        },
        "AccountHolderAddress": {
          "type": "object",
          "title": "Account Holder Address"
        },
        "BankDetails": {
          "type": "object",
          "title": "Bank Details"
        },
        "PaymentPurpose": {
          "type": "string",
          "title": "Payment Purpose"
        }
      },
      "required": [
        "AccountHolderName",
        "AccountHolderAddress",
        "BankDetails",
        "PaymentPurpose"
      ]
    }
  }
}
formSchema can include additional nested validation rules (allOf, if/then, minLength, maxLength, pattern) that should be rendered and validated in your form UI.

6. Quote payout

Call POST /payouts/quote to validate form data and get fee + estimate. paymentMethodId is optional and is only needed when quoting against a saved payment method from step 4.
curl --request POST \
  --url https://api.portalhq.io/api/v3/clients/me/integrations/noah/payouts/quote \
  --header 'Authorization: Bearer [token]' \
  --header 'Content-Type: application/json' \
  --data '{
    "channelId": "214eab50-e22b-5e0f-b487-37dc1addee90",
    "cryptoCurrency": "USDC_TEST",
    "fiatAmount": "0.01",
    "fiatCurrency": "USD",
    "form": {
      "AccountHolderName": {
        "AccountHolderType": "Individual",
        "Name": {
          "FirstName": "John",
          "LastName": "Mock-Doe"
        }
      },
      "AccountHolderAddress": {
        "Address": "123 Main St",
        "City": "Miami",
        "PostalCode": "33139",
        "State": "FL"
      },
      "BankDetails": {
        "AccountNumber": "900711447286",
        "BankCode": "101019644",
        "AccountType": "Checking"
      },
      "PaymentPurpose": "Personal transfer",
      "Reference": "Optional reference"
    }
  }'
Example response (truncated to key fields):
{
  "data": {
		"payoutId": "cmmyatsdk0000wy2en3lof5jj",
		"formSessionId": "d5f81409-5306-476b-84d6-6be2b5656a5a",
		"cryptoAmountEstimate": "0.010004",
		"totalFee": "0.01"
	}
}

7. Initiate payout

Call POST /payouts using payoutId returned from quote. nonce must be unique per transaction attempt (max 36 characters). Reuse the same nonce only when retrying the same payout request for idempotency.
curl --request POST \
  --url https://api.portalhq.io/api/v3/clients/me/integrations/noah/payouts \
  --header 'Authorization: Bearer [token]' \
  --header 'Content-Type: application/json' \
  --data '{
    "payoutId":"cmmyatsdk0000wy2en3lof5jj",
    "sourceAddress":"DEeUjZtzWWiM6sJPBFsR5iL9AeSEtvtuh4ycHM4LHyTK",
    "expiry":"2026-03-24T23:59:59Z",
    "nonce":"nonce-20260320-02388933",
    "network":"solana:devnet"
  }'
Example response:
{
	"data": {
		"destinationAddress": "4dguFohaa8F9MvRtZecGsHCvnGqzYPyGyusP6BWu4zLK",
		"conditions": [
			{
				"amountConditions": [
					{
						"comparisonOperator": "EQ",
						"value": "0.010004"
					}
				],
				"cryptoCurrency": "USDC_TEST",
				"destinationAddress": "4dguFohaa8F9MvRtZecGsHCvnGqzYPyGyusP6BWu4zLK",
				"network": "SolanaDevnet"
			}
		]
	}
}
After receiving this response, submit the onchain transfer to the returned destinationAddress and ensure it satisfies the returned conditions (network and amount constraints).

8. Configure Noah webhooks for payout updates

Set up Noah webhooks in Noah Dashboard to receive payout lifecycle and transaction updates directly from Noah.
  • Subscribe to Transaction events for payout execution and completion updates.
  • Noah Webhooks

9. Monitor payout progress

Use Transaction webhook events and Noah Dashboard delivery logs to track payout execution and reconciliation.
POST /payouts only works for payout intents in PREPARED status (created by POST /payouts/quote).