Crypto-as-a-Service
Fund Go Accounts
Overview
Crypto-as-a-Service (CaaS) enables you and your clients to move fiat between bank accounts and Go Accounts. BitGo supports multiple fiat payments rails to accommodate different client preferences, use cases, and regulatory environments.
Fiat Support
| Jurisdiction | Currency | Payment Rails |
|---|---|---|
| United States | USD | ACH debit, domestic and international wire transfers, CUBIX transfers, Go Network |
| Europe | EUR | SEPA Instant, SEPA, BLINC transfers, Go Network |
Prerequisites
Cookbooks
Need just the steps? Expand a cookbook below to get started:
Fund Go Account with FiatOpen Cookbook Fund Go Account (Go Network)Open CookbookDeposit Instructions
You can fetch your enterprise deposit instructions using the Get deposit info endpoint which returns the memo ID and available deposit bank accounts based on your enterprise jurisdiction. This information is useful when depositing with any of the payment rails we support. Some funding rails require memo ID and bank account details to match your deposit.
BitGo-Approved Bank Accounts
Fiat withdrawals to bank accounts require the use of BitGo-approved bank accounts. You can use the Add bank account endpoint to add a bank account.
When you add a bank account to an enterprise it goes through a screening process. BitGo approves most bank accounts within 48 hours and they can use them for fiat operations immediately after approval. You can see the status of the bank account by calling the Get bank account endpoint and checking the verificationState field.
Approval Requirements
To ensure BitGo approves your bank account, verify the following requirements:
| Requirement | Description |
|---|---|
| Valid Routing Number | For US bank accounts, provide a valid 9-digit ABA routing number. BitGo validates routing numbers against the Federal Reserve directory. Invalid routing numbers result in rejection. |
| Owner Name Match | The ownerName must match the name of your end user. For example, if your enterprise is "John Doe", the bank account owner should be "John Doe". |
| Account Type | You must specify the accountType field as checking or saving. This field is required for both ACH and wire transactions to process correctly. |
(Optional) Add Bank Account
Endpoint: Add bank account
export ACCESS_TOKEN="<SERVICE_USER_ACCESS_TOKEN>"
export ENTERPRISE_ID="<CHILD_ENTERPRISE_ID>"
# Note: 021000021 is a valid sample routing number (JPMorgan Chase Bank)
curl -X POST \
https://app.bitgo-test.com/api/v2/bankaccounts \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d '{
"type": "ach",
"name": "JPMorgan Chase Bank",
"accountNumber": "123456789012",
"routingNumber": "021000021",
"currency": "tfiatusd",
"enterpriseId": "'"$ENTERPRISE_ID"'",
"ownerName": "John Doe",
"accountType": "checking",
"description": "ACH deposits and withdrawals",
"ownerAddressLine1": "123 Main Street",
"ownerAddressLine2": "Suite 400",
"ownerAddressCityLocality": "New York",
"ownerAddressStateProvince": "NY",
"ownerAddressPostalCode": "10001",
"ownerAddressCountryCode": "US",
"bankAddressLine1": "456 Financial Plaza",
"bankAddressCityLocality": "New York",
"bankAddressStateProvince": "NY",
"bankAddressPostalCode": "10005",
"bankAddressCountryCode": "US"
}'
const BitGoJS = require('bitgo');
const bitgo = new BitGoJS.BitGo({
accessToken: '<SERVICE_USER_ACCESS_TOKEN>',
env: 'test',
});
// Note: 021000021 is a valid sample routing number (JPMorgan Chase Bank)
async function addBankAccount() {
const bankAccount = await bitgo.post('/api/v2/bankaccounts').send({
type: 'ach',
name: 'JPMorgan Chase Bank',
accountNumber: '123456789012',
routingNumber: '021000021',
currency: 'tfiatusd',
enterpriseId: '<CHILD_ENTERPRISE_ID>',
ownerName: 'John Doe',
accountType: 'checking',
description: 'ACH deposits and withdrawals',
ownerAddressLine1: '123 Main Street',
ownerAddressLine2: 'Suite 400',
ownerAddressCityLocality: 'New York',
ownerAddressStateProvince: 'NY',
ownerAddressPostalCode: '10001',
ownerAddressCountryCode: 'US',
bankAddressLine1: '456 Financial Plaza',
bankAddressCityLocality: 'New York',
bankAddressStateProvince: 'NY',
bankAddressPostalCode: '10005',
bankAddressCountryCode: 'US',
});
console.log('Bank Account Added:', bankAccount);
return bankAccount;
}
addBankAccount().catch(console.error);
Step Result
The response includes the bank account details and the verificationState field indicating the current approval status.
{
"id": "60749ab75f8c4500060f5a8b244dd0cb",
"idHash": "c2f4cf5555a66d77",
"currency": "tfiatusd",
"token": "tusd",
"name": "JPMorgan Chase Bank",
"shortCountryCode": "US",
"accountNumber": "****9012",
"enterpriseId": "1032e75c451052000436831deb797af1",
"ownerName": "John Doe",
"verificationState": "pending",
"createdAt": "2025-01-12T15:30:00.000Z",
"type": "ach",
"routingNumber": "021000021",
"accountType": "checking",
"description": "ACH deposits and withdrawals",
"ownerAddressLine1": "123 Main Street",
"ownerAddressLine2": "Suite 400",
"ownerAddressCityLocality": "New York",
"ownerAddressStateProvince": "NY",
"ownerAddressPostalCode": "10001",
"ownerAddressCountryCode": "US",
"bankAddressLine1": "456 Financial Plaza",
"bankAddressCityLocality": "New York",
"bankAddressStateProvince": "NY",
"bankAddressPostalCode": "10005",
"bankAddressCountryCode": "US",
"virtualDepositOnly": false,
"fee": {
"amount": "1600",
"individualFees": [
{
"type": "static",
"amount": "1600"
}
]
}
}
Verification States
The endpoint returns one of the following verification states:
pending- Bank account is under review. BitGo approves most accounts within 48 hours.approved- Bank account is ready for fiat operations.rejected- Bank account did not pass review. Review the requirements and resubmit.revise- Bank account requires corrections. Update the account and resubmit.removed- BitGo removed the bank account from the enterprise.
Note
Use the Get bank account endpoint to check the current verification status before initiating fiat operations.
Steps
Select a funding rail to deposit or withdraw from your Go Accounts.
ACH Deposits
ACH deposits enable USD transfers from BitGo-approved US bank accounts to Go Accounts and work well for B2B2C platforms where your users initiate funding through your frontend. ACH deposits work best for:
- Small-to-medium size deposits.
- User experiences that demand a “pull” model.
- Settlements that can wait 1–2 business days to settle.
ACH Deposit Hold Period
When you deposit funds using ACH, BitGo places a 5 business day hold on your deposit. During this period, you can trade your deposited assets, but you can't withdraw or move the principal — this includes staking, transfers, or any other movement. You can withdraw any trading profits right away, but you must wait for the hold to expire before withdrawing your original deposit.
Before initiating ACH deposits, your platform must fund a reserve account that meets the following requirements:
- Minimum account balance: $25,000 if no deposit history.
- Standard account balance: 25% of the highest 2-day deposit volume in the previous month.
- You must replenish it within 5 business days if you withdraw funds.
In addition, to comply with Nacha rules, your ACH unauthorized returns must stay below 0.5% of total debits. If you exceed these thresholds, BitGo may suspend your ACH access.
Plaid Integration Required
ACH deposits require bank accounts linked through Plaid. Your enterprise must have Plaid credentials configured by BitGo before you can proceed. Contact your Customer Success Manager (CSM) if you have not completed Plaid setup.
1. Set Up Reserve
ACH deposits take 1–2 business days to settle, while digital assets can transfer almost instantly. Therefore, BitGo requires you to pre-fund a fiat reserve to cover potential unauthorized return claims (fraud) from your end-users. You set up your reserve account using the Go Account in the parent enterprise - not the child enterprises.
1.1 Designate Parent Enterprise
Contact your BitGo Customer Success Manager (CSM) to designate an enterprise in your organization your parent enterprise. Your CSM coordinates the set up and account configuration.
1.2 Fund Reserve Account
Deposit a minimum of $25,000 into the Go Account. This serves as your reserve account. ACH functionality isn't enabled until these funds fully settle. You can fund the Go Account using a wire transfer or a Go Network transfer.
1.3 Maintain Reserve
As your ACH deposit volume grows, your reserve must grow with it. Each month:
- Review your ACH deposit transaction history for the prior month.
- Identify the peak 2-day volume — the 48-hour window with the highest total USD inflow. For example, if you processed $1M in deposits over a busy Monday and Tuesday, that $1M is your peak 2-day volume.
- Calculate 25% of that peak amount. Using the example above, that's $250,000.
- If 25% of your peak 2-day volume exceeds your current reserve balance, deposit the difference to bring the reserve up to the required level.
1.4 Replenish Reserve
If the balance of your reserve account dips due to fraud or unauthorized returns, you must replenish it to the required level within 5 business days.
Warning
If your deposit volume increases but you don't top up your reserve account to meet the 25% requirement, BitGo may suspend ACH access until you restore the reserve balance.
2. Get Transfer Limit
The transfer limit is the amount you can deposit using ACH per calendar day and resets every day at 12am EST.
Endpoint: Get Enterprise Transfer Limits
Note
The test environment caps ACH deposits at $2,500/day and $10,000/week per enterprise. Use reasonable amounts and check remaining limits to avoid exceeding these thresholds during testing.
export ENTERPRISE_ID="<YOUR_ENTERPRISE_ID>"
export ACCESS_TOKEN="<SERVICE_USER_ACCESS_TOKEN>"
curl -X GET \
https://app.bitgo-test.com/api/tradfi/v1/enterprise-transfer-limits/$ENTERPRISE_ID/usd/ach-us/in \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d '{
"id": "01982d49-9f0d-7c50-847a-e04ea8a63165",
"maximumTransferAllowed": "2500.00",
"maximumTransferAllowedBase": 250000,
"noLimit": false,
"transferDirection": "in",
"transferType": "ach-us"
}'
Step Result
{
"id": "string",
"maximumTransferAllowed": "string",
"maximumTransferAllowedBase": 0,
"noLimit": true,
"transferDirection": "in",
"transferType": "ach-us"
}
3. Create Plaid Link Token
Create Plaid Link token for the enterprise. Use this token to initialize the Plaid Link widget in your application.
If your application runs on a mobile device, include the androidPackageName or redirectUri parameters to support OAuth redirect flows.
Endpoint: Create Plaid Link token
export ENTERPRISE_ID="<YOUR_ENTERPRISE_ID>"
export ACCESS_TOKEN="<SERVICE_USER_ACCESS_TOKEN>"
export ANDROID_PACKAGE_NAME="<YOUR_ANDROID_PACKAGE_NAME>" # Required for Android OAuth flows
export REDIRECT_URI="<YOUR_REDIRECT_URI>" # Required for mobile and web OAuth flows
curl -X POST https://app.bitgo-test.com/api/tradfi/v1/plaid/link/token \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"enterpriseId": "'"$ENTERPRISE_ID"'",
"androidPackageName": "'"$ANDROID_PACKAGE_NAME"'", # Required for Android OAuth flows
"redirectUri": "'"$REDIRECT_URI"'" # Required for mobile and web OAuth flows
}'
Note
If you haven't configured your Plaid credentials, the server responds with 428 Precondition Required. Contact your BitGo Customer Success Manager (CSM) to get your Plaid credentials set up.
Use the returned link token to render the Plaid Link widget in your application. Refer to the official Plaid documentation for rendering guidance, but use the BitGo APIs (described in this guide) for creating and exchanging tokens.
| Platform | Plaid Documentation |
|---|---|
| Web | Plaid Link for Web |
| iOS | Plaid Link for iOS |
| Android | Plaid Link for Android |
| React Native | Plaid Link for React Native |
4. Exchange the Plaid Public Token
Once you finish selecting the bank accounts in the Plaid widget, Plaid returns a public token to your application. Exchange this token with BitGo to complete the bank account linking process.
Endpoint: Exchange Plaid Public Token
export ENTERPRISE_ID="<YOUR_ENTERPRISE_ID>"
export LINK_TOKEN="<LINK_TOKEN_FROM_STEP_1>"
export PUBLIC_TOKEN="<PUBLIC_TOKEN_FROM_PLAID>"
export ACCESS_TOKEN="<ACCESS_TOKEN>"
export IP_ADDRESS="<IP_ADDRESS>"
curl -X POST https://app.bitgo-test.com/api/tradfi/v1/plaid/link/token/exchange \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"enterpriseId": "'"$ENTERPRISE_ID"'",
"linkToken": "'"$LINK_TOKEN"'",
"publicToken": "'"$PUBLIC_TOKEN"'",
"ipAddress": "'"$IP_ADDRESS"'" # IP address of the end user who completed Plaid Link. Optional, but provide this value to improve the users Instant Credit trust score.
}'
BitGo fetches the bank accounts selected by the user asynchronously. BitGo adds them to the user's account within a few seconds.
5. Get Bank Account
Retrieve the linked bank account to obtain the bankAccountId needed to initiate the ACH deposit. You can list all bank accounts or get a specific one by ID.
Endpoint: Get Deposit Info
export BANK_ACCOUNT_ID="<BANK_ACCOUNT_ID>"
export ACCESS_TOKEN="<ACCESS_TOKEN>"
curl -X GET \
https://app.bitgo-test.com/api/v2/bankaccounts/deposit/info?currency=fiatusd \
-H "Authorization: Bearer $ACCESS_TOKEN"
Step Result
{
"memoId": "string",
"bankAccounts": [
{
"type": "ach",
"routingNumber": "string",
"accountType": "checking",
"id": "string", // Bank account id used for the next step,
"description": "Nickname for Bank Acount", // User-provided description of the account.
"name": "Bank Name"
}
]
}
6. Create Bank Transfer
Initiate a new bank transfer using the walletId and bankAccountId as counterparties. The system infers most details from the bankAccountId. The same enterpriseId must own both the walletId and bankAccountId.
Endpoint: Create a Bank Transfer
export ACCESS_TOKEN="<SERVICE_USER_ACCESS_TOKEN>"
export AMOUNT="<AMOUNT_TO_DEPOSIT>"
export BANK_ACCOUNT_ID="<BANK_ACCOUNT_ID>" # ID from previous step.
export WALLET_ID="<WALLET_ID>"
curl -X POST https://app.bitgo-test.com/api/tradfi/v1/bank-transfers \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"amount": "'"$AMOUNT_TO_DEPOSIT"'",
"bankAccountId": "'"$BANK_ACCOUNT_ID"'",
"transferDirection": "in",
"walletId": "'"$WALLET_ID"'"
}'
Step Result
{
"amount": "string",
"applyInstantCredit": true,
"bankAccountId": "string",
"createdAt": "2026-04-09T17:17:30.615Z",
"enterpriseId": "string",
"estimatedEffectiveOn": "2026-04-09",
"id": "string",
"instantCreditLiability": true,
"memoId": "string",
"settledAt": "2026-04-09T17:17:30.615Z",
"status": "initiated",
"transferDirection": "in",
"transferType": "ach-us",
"txid": "string",
"walletId": "string"
}
7. Get Bank Transfer
Use this call to check the transfer status, settlement timestamps, and other details.
Note
This endpoint is only available in the test environment.
Endpoint: Get Bank Transfer
export ACCESS_TOKEN="<SERVICE_USER_ACCESS_TOKEN>"
export TRANSACTION_ID="<TX_ID>"
curl -X GET https://app.bitgo-test.com/api/tradfi/v1/bank-transfers/$TX_ID \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Accept: application/json" \
Step Result
{
"amount": "string",
"applyInstantCredit": true,
"bankAccountId": "string",
"createdAt": "2026-04-10T15:31:57.502Z",
"enterpriseId": "string",
"estimatedEffectiveOn": "2026-04-10",
"id": "string",
"instantCreditLiability": true,
"memoId": "string",
"settledAt": "2026-04-10T15:31:57.502Z",
"status": "initiated",
"transferDirection": "in",
"transferType": "ach-us",
"txid": "string",
"walletId": "string"
}
The API automatically enforces daily transfer limits. If the deposit would exceed the allowed amount, the request returns an error. You can check remaining limits at any time using the List Enterprise Transfer Limits endpoint.
ACH deposits typically settle within 1–2 business days.
Instant Credit (Optional)
Instant Credit allows your users to receive funds in their Go Account immediately after initiating an ACH deposit, rather than waiting for settlement.
How It Works
- When an account initiates a deposit with Instant Credit enabled, BitGo performs a risk analysis using data from the linked Plaid account (such as the current bank balance).
- The risk provider returns a timeline assessment — either T+1 (low risk, advances credit) or T+4 (higher risk, does not advance credit).
- If approved, the Go Account ledger credits immediately and the funds become spendable, even though ACH settlement is still pending.
- Once the ACH transfer fully settles, the instant credit transaction reconciles automatically.
Requirements
For Instant Credit to be applied, all of the following must be true:
- The enterprise integrates with Plaid.
- The reserve account holds enough funds to cover instant credit above the minimum threshold.
- The deposit request sets the
applyInstantCreditflag totrue. - The indexed ledger allows Instant Credit.
- The transfer type and direction qualify for instant credit (currently ACH pulls only).
- The enterprise (and optionally the wallet) meets the risk criteria.
Monitoring Instant Credit Liability
Transfers with active Instant Credit count against your reserve account balance. You can check the instantCreditLiability field on individual transfers to determine how much of your reserve is currently committed.
Important
Instant Credit is not guaranteed. If the risk analysis returns an unfavorable result, the deposit proceeds normally with standard settlement timing.
Wire Deposits
Wire transfer deposits are a reliable way to fund Go Accounts with high-value or international deposits. BitGo provides deposit instructions specific to each enterprise and Go Account. Wire transfers work best for:
- Large-value deposits.
- Time-sensitive transfers.
- International fiat inflows.
1. Get Deposit Details
Get bank account details for BitGo and a memo ID. All wire transfers must include a memo ID. This ID links your deposit to your account.
export ACCESS_TOKEN="YOUR_ACCESS_TOKEN"
export GO_ACCOUNT_ID="GO_ACCOUNT_ID"
export CURRENCY="tfiatusd" # The BitGo-supported fiat currency you want to deposit
curl -X GET \
"https://app.bitgo-test.com/api/v2/bankaccounts/deposit/info?goAccountId=$GO_ACCOUNT_ID¤cy=$CURRENCY" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $ACCESS_TOKEN"
export type Fee {
amount: string
individualFees:
{
type: "static" | "variable",
amount: string
}[]
}
export type BankAccount {
id: string;
description?: string;
idHash: string;
currency: string;
accountNumber: string;
token: string;
name: string;
shortCountryCode: string;
enterpriseId: string;
trustOrg: string;
ownerName: string;
verificationState: string;
createdAt: string;
ownerAddressLine1: string;
ownerAddressLine2?: string;
ownerAddressCityLocality?: string;
ownerAddressStateProvince?: string;
ownerAddressPostalCode?: string;
ownerAddressCountryCode: string;
bankAddressLine1: string;
bankAddressLine2?: string;
bankAddressCityLocality?: string;
bankAddressStateProvince?: string;
bankAddressPostalCode?: string;
bankAddressCountryCode: string;
virtualDepositOnly: boolean;
type: string;
routingNumber?: string;
swiftCode?: string;
accountType: string;
fee: Fee
}
export type DepositInfo = {
memoId: string;
bankAccounts: BankAccount[];
};
Step Result
{
"memoId": "JVAIBEMHXT",
"bankAccounts": [
{
"id": "64ae84bdb25d190007958872b5104a7f",
"idHash": "cd303c82c4c74abf",
"currency": "tfiatusd",
"accountNumber": "5766400",
"token": "tusd",
"name": "Customers Bank ",
"shortCountryCode": "US",
"enterpriseId": "5bd795f1bf7435a503a0a647ec5d3b3d",
"trustOrg": "BitGo Trust",
"ownerName": "BitGo Trust Company, Inc",
"verificationState": "approved",
"createdAt": "2024-03-07T17:10:57.146Z",
"ownerAddressLine1": "6216 S Pinnacle Pl Ste #101",
"ownerAddressCityLocality": "Sioux Falls",
"ownerAddressStateProvince": "SD",
"ownerAddressPostalCode": "57108",
"ownerAddressCountryCode": "US",
"bankAddressLine1": "40 General Blvd Suite #200",
"bankAddressCityLocality": "Malvern",
"bankAddressStateProvince": "PA",
"bankAddressPostalCode": "19355",
"bankAddressCountryCode": "US",
"virtualDepositOnly": false,
"type": "wire",
"routingNumber": "031302971",
"accountType": "unknown",
"fee": {
"amount": "1600",
"individualFees": [
{
"type": "static",
"amount": "1600"
}
]
},
},
]
}
2. Deposit Fiat Currency
Depositing fiat currency from your bank account requires using your bank app or API to initiate a wire or an ACH deposit. Review your bank documentation or contact them to learn more.
Note
Ensure to include the memo ID in order to prevent delays in accrediting deposits to your Go Account.
Step Result
The balance of fiat currency in your Go Account updates with the deposited amount. The deposited balance is immediately available for trades.
You can verify successful deposits with the Get Account Balance endpoint.
1. Get idHash
Endpoint: List Bank Accounts
export ENTERPRISE_ID="<ENTERPRISE_ID>"
export ACCESS_TOKEN="<SERVICE_USER_ACCESS_TOKEN>"
curl -X GET \
https://app.bitgo-test.com/api/v2/bankaccounts?enterpriseId=$ENTERPRISE_ID \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $ACCESS_TOKEN"
Step Result
BitGo identifies your bank account with a unique idHash that you can pass as the address value in the next step. You also receive information about the available payment rails and associated bank fees.
{
"bankAccounts": [
{
"type": "wire", // available payment rails vary by bank and region
"accountNumber": "012345678",
"address1": "test",
"address2": "test",
"enterpriseId": "1032e75c451052000436831deb797af1",
"id": "60749ab75f8c4500060f5a8b244dd0cb",
"name": "My Bank",
"owner": {
"name": "test",
"address1": "test",
"address2": "test"
},
"idHash": "c2f4cf5555a66d77",
"routingNumber": "087654321",
"shortCountryCode": "US",
"verificationState": "approved",
"fee": { // fees vary by payment rail and bank
"amount": "string",
"individualFees": [
{
"type": "static",
"amount": "string"
}
]
},
"feeInfo": {
"coin": "fiatusd",
"bank": "silvergate",
"type": "static",
"amount": "string"
},
}
]
}
2. Build Transaction
To withdraw assets from your Go Account to a bank account, you must build a transaction and send the assets, on chain.
Endpoint: Build a Transaction
export COIN="<ASSET_ID>" # Asset IDs in Go Accounts always start with "ofc" (such as ofctbtc4)
export WALLET_ID="<YOUR_WALLET_ID>"
export ACCESS_TOKEN="<SERVICE_USER_ACCESS_TOKEN>"
export AMOUNT="<AMOUNT_IN_BASE_UNITS>"
export ADDRESS="<DESTINATION_ADDRESS_OR_ID_HASH>" # If withdrawing fiat to a bank account, use the `idHash`, returned in the prior step
curl -X POST \
https://app.bitgo-test.com/api/v2/$COIN/wallet/$WALLET_ID/tx/build \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d '{
"recipients": [
{
"amount": "'"$AMOUNT"'",
"address": "'"$ADDRESS"'"
}
]
}'
let params = {
recipients: [
{
amount: 1000,
address: '2NFfxvXpAWjKng7enFougtvtxxCJ2hQEMo4',
// Use address when sending to a wallet on chain
walletId: '654ec786c07fe6dc0dcfe03916ec4bb0',
// Use walletId when sending to another Go Account off chain
},
],
};
wallet.prebuildTransaction(params).then(function (transaction) {
// print transaction details
console.dir(transaction);
});
Step Result
{
"payload": "{\"coin\":\"ofctbtc4\",\"recipients\":[{\"address\":\"tb1q5mwcr2749nnm5c5d6rzx5h92l2u9ex5jzygzd39vfv9qerj5fmjqwlgy4t\",\"amount\":\"1\"}],\"fromAccount\":\"62c5b1de8a0c5200071c9a603bdbadc5\",\"nonce\":\"d8e5d930-f827-42b1-ad85-40544dad1be6\",\"timestamp\":\"2025-06-25T17:45:56.394Z\",\"feeString\":\"0\",\"shortCircuitBlockchainTransfer\":false,\"isIntraJXTransfer\":false}",
"feeInfo": { "feeString": "0" },
"coin": "ofc",
"token": "ofctbtc4"
}
3. Authenticate Transaction
Use your Go Account passphrase to authenticate the transaction. To ensure your passphrase does not travel over the Internet, you must use BitGo Express in external-signing mode or the JavaScript SDK. If you're using Express in external signing-mode, configure your Go Account passphrase as the WALLET_<walletId>_PASSPHRASE environment variable.
export BITGO_EXPRESS_HOST="<YOUR_LOCAL_HOST>"
export ACCESS_TOKEN="<SERVICE_USER_ACCESS_TOKEN>"
export WALLET_ID="<YOUR_WALLET_ID>"
export WALLET_PASSPHRASE="<YOUR_GO_ACCOUNT_PASSPHRASE>"
curl -X POST \
http://$BITGO_EXPRESS_HOST/api/v2/ofc/signPayload \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d '{
"walletId": "'"$WALLET_ID"'",
"walletPassphrase": "'"$WALLET_PASSPHRASE"'",
"payload": "{\"coin\":\"ofctbtc4\",\"recipients\":[{\"address\":\"tb1q5mwcr2749nnm5c5d6rzx5h92l2u9ex5jzygzd39vfv9qerj5fmjqwlgy4t\",\"amount\":\"190000\"}],\"fromAccount\":\"67ab85b5190bf872e84da2b6e527d9f3\",\"nonce\":\"77d91a11-a7fa-4ad7-91e5-f054328717f9\",\"timestamp\":\"2025-06-26T15:02:06.924Z\",\"feeString\":\"0\",\"shortCircuitBlockchainTransfer\":false,\"isIntraJXTransfer\":false}"
}
// assuming that "bitgo" is an already initialized bitgo instance
const wallet = await bitgo.coin('ofc').wallets().get({ id: goAccountId });
if (wallet === undefined) {
throw new Error(`Could not find OFC wallet ${goAccountId}`);
}
const walletPassphrase = "<YOUR_WALLET_PASSPHRASE>";
const tradingAccount = wallet.toTradingAccount();
const stringifiedPayload = JSON.stringify(<payload_returned_by_tx/build_api>);
const signature = await tradingAccount.signPayload({
payload: stringifiedPayload,
walletPassphrase,
});
Step Result
{
"coin": "ofctbtc4",
"recipients": [
{
"address": "tb1q5mwcr2749nnm5c5d6rzx5h92l2u9ex5jzygzd39vfv9qerj5fmjqwlgy4t",
"amount": "1"
}
],
"fromAccount": "62c5b1de8a0c5200071c9a603bdbadc5",
"nonce": "77d91a11-a7fa-4ad7-91e5-f054328717f9",
"timestamp": "2025-06-26T15:02:06.924Z",
"feeString": "0",
"shortCircuitBlockchainTransfer": false,
"isIntraJXTransfer": false,
"payload": "{\"coin\":\"ofctbtc4\",\"recipients\":[{\"address\":\"tb1q5mwcr2749nnm5c5d6rzx5h92l2u9ex5jzygzd39vfv9qerj5fmjqwlgy4t\",\"amount\":\"1\"}],\"fromAccount\":\"62c5b1de8a0c5200071c9a603bdbadc5\",\"nonce\":\"77d91a11-a7fa-4ad7-91e5-f054328717f9\",\"timestamp\":\"2025-06-26T15:02:06.924Z\",\"feeString\":\"0\",\"shortCircuitBlockchainTransfer\":false,\"isIntraJXTransfer\":false}",
"signature": "20dda1e9558adb297f69020f94cbf4955fabec73478506347dbb5ac8e73b506fc908bbc48bde75b339b99f5de808ed34b2017055c9df198fd1f8b4e524899f9583"
}
4. Send Transaction
The following example withdraws fiat to a bank account. However, you can also withdraw fiat to another Go Account, if the recipient address appears on the allowlist.
Endpoint: Send Half-Signed Transaction
export WALLET_ID="<YOUR_WALLET_ID>"
export ACCESS_TOKEN="<SERVICE_USER_ACCESS_TOKEN>"
export ADDRESS="<ID_HASH>"
export AMOUNT="<AMOUNT_IN_BASE_UNITS>"
curl -X POST \
https://app.bitgo-test.com/api/v2/ofctusd/wallet/$WALLET_ID/tx/send \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d '{
"recipients": [
{
"address": "'"$ADDRESS"'",
"amount": "'"$AMOUNT"'"
}
],
"halfSigned": {
"payload": {
"coin": "ofctusd",
"recipients": [
{
"address": "'"$ADDRESS"'",
"amount": "'"$AMOUNT"'"
}
],
"fromAccount": "<wallet id>",
"nonce": "f4af25d0-a037-4afc-8ce6-d7f158d826d1",
"timestamp": "2021-09-10T22:45:20.777Z",
"idfSignedTimestamp": "2021-09-10T22:45:20.113Z",
"idfVersion": 1,
"idfUserId": "<user id>",
"feeString": "1000"
},
"signature": "<signature>"
}
}'
Step Result
{
"transfer": {
"id": "<id>",
"coin": "ofctusd",
"wallet": "<wallet id>",
"walletType": "trading",
"enterprise": "603ca88c44f82002560378421dc7a191",
"txid": "ddd6875812fa59f899a68059ff303bfa6d39fc350ee687c407383d0444b43d2b",
"height": 999999999,
"heightId": "999999999-613be001f3de560006842d52251d5d49",
"date": "2021-09-10T22:45:21.342Z",
"type": "send",
"value": -10000,
"valueString": "-10000",
"baseValue": -10000,
"baseValueString": "-10000",
"feeString": "0",
"payGoFee": 0,
"payGoFeeString": "0",
"usd": -100,
"usdRate": 1,
"state": "signed",
"instant": false,
"isReward": false,
"isFee": false,
"tags": [
"603ca8c01b83cb000656311787dab4cd",
"603ca88c44f82002560378421dc7a191"
],
"history": [
{
"date": "2021-09-10T22:45:21.340Z",
"action": "signed"
},
{
"date": "2021-09-10T22:45:21.216Z",
"user": "5e4ed695ae2e542100336fb16e586019",
"action": "created"
}
],
"signedDate": "2021-09-10T22:45:21.340Z",
"entries": [
{
"address": "address",
"wallet": "603ca8c01b83cb000656311787dab4cd",
"value": -10000,
"valueString": "-10000"
},
{
"address": "bf6cc5252438dc85",
"value": 10000,
"valueString": "10000"
}
],
"signedTime": "2021-09-10T22:45:21.340Z",
"createdTime": "2021-09-10T22:45:21.216Z"
},
"txid": "ddd6875812fa59f899a68059ff303bfa6d39fc350ee687c407383d0444b43d2b",
"tx": {
"transaction": {
"coin": "ofctusd",
"recipients": [
{
"address": "<bank id hash>",
"amount": "10000"
}
],
"fromAccount": "<wallet id>",
"nonce": "f4af25d0-a037-4afc-8ce6-d7f158d826d1",
"timestamp": "2021-09-10T22:45:20.777Z",
"idfSignedTimestamp": "2021-09-10T22:45:20.113Z",
"idfVersion": 1,
"idfUserId": "<user id>",
"feeString": "0"
},
"signature": "<signature>",
"idfVersion": 1,
"idfSignedTimestamp": "2021-09-10T22:45:20.113Z",
"idfUserId": "<user id>"
},
"status": "signed"
}
5. Approve Transaction (Optional)
Endpoint: Update Pending Approval
export COIN="<ASSET_ID>"
export APPROVAL_ID="<APPROVAL_ID>"
export ACCESS_TOKEN="<SERVICE_USER_ACCESS_TOKEN>"
export OTP="<OTP>"
curl -X POST \
http://api/v2/$COIN/pendingapprovals/$APPROVAL_ID
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d '{
"state": "approved",
"otp": "'"$OTP"'"
}'
const baseCoin = this.bitgoSDK.coin(initialPendingApproval.coin);
const pendingApproval = await baseCoin.pendingApprovals().get({ id: initialPendingApproval.id });
const result = await pendingApproval.approve(params);
Step Result
Once approved, BitGo rebuilds the unsigned transaction, applying the most up-to-date fees.
{
"id": "655686880765186f0b3e9e88e1bdd0f4",
"coin": "tbtc4",
"wallet": "6553e933288be490293ae748efafeaaf",
"enterprise": "62c5ae8174ac860007aff138a2d74df7",
"creator": "62ab90e06dfda30007974f0a52a12995",
"createDate": "2023-11-16T21:15:52.703Z",
"info": {
"type": "transactionRequest",
"transactionRequest": {
"requestedAmount": "10000",
"fee": 45242,
"sourceWallet": "6553e933288be490293ae748efafeaaf",
"policyUniqueId": "6553e933288be490293ae753",
"recipients": [
{
"address": "2N3sBpM1RnWRMXnEVoUWnM7xtYzL756JE2Q",
"amount": "10000",
"_id": "655686880765186f0b3e9e8a"
}
],
"buildParams": {
"recipients": [
{
"address": "2N3sBpM1RnWRMXnEVoUWnM7xtYzL756JE2Q",
"amount": "10000"
}
]
},
"coinSpecific": {
"tbtc4": {
"txHex": "01000000000101eac5e7d68acfc2349672fb99094e79c2006e5fd663475c8f1eb6f29095970b740100000000ffffffff02102700000000000017a914747e6b7f5db53794b0fc01d95878e0f9b6db96738746c1020000000000220020efb9deaabeab5d62cecc363f24cd6deafcdd14d93d8734f7f01ed3953e732a640500483045022100cd6c221e4cefbb51aa82087d86e7d089b2473eb21ae809dba89eb9f13c4caf19022000f3b7f1b7fec2dc49cbfce35baa69ca37ab9ee8e51c779cde5b98a653f3e142010000695221029bde55661e4f359cf9ca2d1846c235e752f760ed6d65e2018f821253e78b3c722103f2b4a813ab79e4fb46edf3a6a87fb154a85b45810158e949f41a3fce3c9bf574210399a6d766f6d3a3843f8479446ee766b5745dc15c24d1db5149214d27987bd29453ae00000000"
}
},
"validTransaction": "01000000000101eac5e7d68acfc2349672fb99094e79c2006e5fd663475c8f1eb6f29095970b740100000000ffffffff02102700000000000017a914747e6b7f5db53794b0fc01d95878e0f9b6db96738746c1020000000000220020efb9deaabeab5d62cecc363f24cd6deafcdd14d93d8734f7f01ed3953e732a640400483045022100cd6c221e4cefbb51aa82087d86e7d089b2473eb21ae809dba89eb9f13c4caf19022000f3b7f1b7fec2dc49cbfce35baa69ca37ab9ee8e51c779cde5b98a653f3e14201473044022002b246c43722fec49858caf6b0605a0d01a6b6c13c964b84bf272604fd3951780220324ee44ba3ce8febb154c317e688a5f6ed410ad8e2bd77c5678bf1f7f3eb45f601695221029bde55661e4f359cf9ca2d1846c235e752f760ed6d65e2018f821253e78b3c722103f2b4a813ab79e4fb46edf3a6a87fb154a85b45810158e949f41a3fce3c9bf574210399a6d766f6d3a3843f8479446ee766b5745dc15c24d1db5149214d27987bd29453ae00000000",
"validTransactionHash": "ff40ccd5c8ba75ffdce27d8584b6e8ee625cb3f71f7cbb6d072a445a97c2c8c3"
}
},
"state": "approved",
"scope": "wallet",
"userIds": [
"62ab90e06dfda30007974f0a52a12995",
"627ff9325a5c1b0007c05a40d15e1522"
],
"approvalsRequired": 1,
"singleRunResults": [
{
"ruleId": "Custody Enterprise Transaction ID Verification",
"triggered": false,
"_id": "655686880765186f0b3e9e89"
}
],
"resolvers": [
{
"user": "627ff9325a5c1b0007c05a40d15e1522",
"date": "2023-11-16T21:33:24.644Z",
"resolutionType": "pending"
}
]
}
Go Network Transfers
You can instantly transfer fiat between Go Accounts over Go Network. BitGo manages the off-chain ledger and updates Go Account balances accordingly. Fiat transfers over the Go Network are ideal for moving liquidity between child enterprises or white-labeled partners. Go Network transfers are best for:
- Real-time enterprise-to-enterprise settlements.
- Treasury operations between sub-accounts.
- Transfers across platforms integrated with BitGo.
1. Create a Connection
Before you can create a settlement with a new counterparty, you need a Go Account connection. Connections exist between two Go Accounts (not between enterprise IDs) and are one-way. For example, if Go Account A creates a connection to Go Account B, the connection is from A → B, and only Go Account A can initiate settlements using that connection. This connection includes the addressBookConnectionId and addressBookConnectionUpdatedAt values that you pass in the settlement request.
1.1 List Your Enterprise
List your enterprise in the public directory so that other enterprises can find you and add you as a counterparty.
Endpoint: Create Enterprise Listing
export ACCESS_TOKEN="<SERVICE_USER_ACCESS_TOKEN>"
export DESCRIPTION="<YOUR_PUBLIC_DESCRIPTION>"
curl -X POST \
https://app.bitgo-test.com/api/address-book/v1/listing/global \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d '{"description": "'"$DESCRIPTION"'"}'
Step Result
Your enterprise is now discoverable in the public directory.
{
"id": "9f627592-641f-4300-96c4-819fafb6435a",
"createdAt": "2026-02-09T21:20:05.269Z",
"updatedAt": "2026-02-09T21:20:05.269Z",
"enterpriseId": "698a2f58718d0f73eb4ba9faeb491be0",
"name": "roychon401+30@bitgo.com",
"owner": "698a2f58718d0f73eb4ba9faeb491be0"
}
1.2 Create Listing Entry
Create an entry for your Go Account within your enterprise listing. This enables you and others to create connections between your Go Account and theirs.
Endpoint: Create a Listing Entry
export ACCESS_TOKEN="<SERVICE_USER_ACCESS_TOKEN>"
export WALLET_ID="<YOUR_WALLET_ID>"
export DESCRIPTION="<YOUR_PUBLIC_DESCRIPTION>"
curl -X POST \
https://app.bitgo-test.com/api/address-book/v1/listing/entry/global \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d '{
"walletId": "'"$WALLET_ID"'",
"description": "'"$DESCRIPTION"'",
"public": true
}'
Step Result
{
"walletId": "698a3d58066a618a569a8dd844c514d4",
"type": "GO_ACCOUNT",
"coin": "ofc",
"discoverable": true,
"featured": false,
"id": "a2a48c3c-5ab1-46ab-bd05-59082576c5c2",
"createdAt": "2026-02-09T21:29:26.194Z",
"updatedAt": "2026-02-09T21:29:26.194Z"
}
1.3 Get your Listing Entry ID
Get the enterprise listing and select the entry that has your Go Account walletId.
Endpoint: Get enterprise listing
export ACCESS_TOKEN="<SERVICE_USER_ACCESS_TOKEN>"
export CHILD_ENTERPRISE_ID="<CHILD_ENTERPRISE_ID>"
export USER_ID="<YOUR_USER_ID>"
curl -X GET \
https://app.bitgo-test.com/api/address-book/v1/listing/global \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "enterprise-id: $CHILD_ENTERPRISE_ID" \
-H "user-id: $USER_ID"
Step Result
The listingEntryId is listingEntries[<index>].id.
{
"id": "10b51fd8-6ef7-4ad1-8a84-56f84abfec7a",
"createdAt": "2026-01-14T15:31:45.292Z",
"updatedAt": "2026-01-14T15:31:45.292Z",
"enterpriseId": "6967afd69792fa80c629f22bb52caed6",
"name": "Test User",
"owner": "6967afd69792fa80c629f22bb52caed6",
"listingEntries": [
{
"id": "1a7b6239-8412-4702-b000-b40ee5351761",
"createdAt": "2026-01-14T15:31:46.052Z",
"updatedAt": "2026-01-14T15:31:46.052Z",
"walletId": "6967b45a4ffdedb5747d5934e544b94c",
"coin": "ofc",
"type": "GO_ACCOUNT",
"discoverable": false,
"featured": false
}
]
}
1.4 Create Counterparty Connection
Note
The following difference when creating a counterparty connection:
- For a listed counterparty, pass your
listingEntryIdand theirtargetListingEntryId. - For an unlisted counterparty, pass your
listingEntryIdand their Go AccountwalletId. You must also label the connection using thelocalListingNameparameter. - For a counterparty that's in the same organization as you, pass their
walletId.
Endpoint: Add Go Account connection
export ACCESS_TOKEN="<SERVICE_USER_ACCESS_TOKEN>"
export CHILD_ENTERPRISE_ID="<CHILD_ENTERPRISE_ID>"
export USER_ID="<YOUR_USER_ID>"
export LISTING_ENTRY_ID="<YOUR_LISTING_ENTRY_ID>"
export TARGET_LISTING_ENTRY_ID="<COUNTERPARTY_TARGET_LISTING_ENTRY_ID>"
export LOCAL_LISTING_ENTRY_DESCRIPTION="<LOCAL_LISTING_ENTRY_DESCRIPTION>"
curl -X POST \
https://app.bitgo-test.com/api/address-book/v1/connections \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "enterprise-id: $CHILD_ENTERPRISE_ID" \
-H "user-id: $USER_ID" \
-d '{
"listingEntryId": "'"$LISTING_ENTRY_ID"'",
"localListingEntryDescription": "'"$LOCAL_LISTING_ENTRY_DESCRIPTION"'",
"targetListingEntryId": "'"$TARGET_LISTING_ENTRY_ID"'"
}'
export ACCESS_TOKEN="<SERVICE_USER_ACCESS_TOKEN>"
export CHILD_ENTERPRISE_ID="<CHILD_ENTERPRISE_ID>"
export USER_ID="<YOUR_USER_ID>"
export LISTING_ENTRY_ID="<YOUR_LISTING_ENTRY_ID>"
export COUNTERPARTY_WALLET_ID="<COUNTERPARTY_GO_ACCOUNT_WALLET_ID>"
export LOCAL_LISTING_NAME="<LOCAL_LISTING_NAME>"
curl -X POST \
https://app.bitgo-test.com/api/address-book/v1/connections \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "enterprise-id: $CHILD_ENTERPRISE_ID" \
-H "user-id: $USER_ID" \
-d '{
"localListingName": "'"$LOCAL_LISTING_NAME"'",
"listingEntryId": "'"$LISTING_ENTRY_ID"'",
"walletId": "'"$COUNTERPARTY_WALLET_ID"'"
}'
Step Result
{
"connections": [
{
"id": "eafc174e-d1b9-4baf-ba78-275e6d699850",
"createdAt": "2026-01-14T18:14:20.015Z",
"updatedAt": "2026-01-14T18:14:20.275Z",
"label": "DVP connection from 6967b45a4ffdedb5747d5934e544b94c to 6967dbd76e03e014ca3ccec6839a046a",
"status": "ACTIVE",
"createdBy": "695d68b062ce13d38fa6a3ec72df6e4c",
"updatedBy": "695d68b062ce13d38fa6a3ec72df6e4c",
"hidden": false,
"type": "DVP",
"ownerListingEntry": {
"id": "1a7b6239-8412-4702-b000-b40ee5351761",
"createdAt": "2026-01-14T15:31:46.052Z",
"updatedAt": "2026-01-14T15:31:46.052Z",
"walletId": "6967b45a4ffdedb5747d5934e544b94c",
"coin": "ofc",
"type": "GO_ACCOUNT",
"discoverable": false,
"featured": false,
"listing": {
"id": "10b51fd8-6ef7-4ad1-8a84-56f84abfec7a",
"name": "Test User",
"editable": false
}
},
"targetListingEntry": {
"id": "8a4cae30-7473-4301-988e-d01eba0d6177",
"createdAt": "2026-01-14T18:14:20.015Z",
"updatedAt": "2026-01-14T18:14:20.015Z",
"walletId": "6967dbd76e03e014ca3ccec6839a046a",
"coin": "ofc",
"type": "GO_ACCOUNT",
"discoverable": false,
"featured": false,
"listing": {
"id": "34d9f5d2-cd8d-4214-acda-e5693e02a977",
"name": "Test Go Account",
"editable": true
}
}
}
]
}
2. Create Settlement
BitGo refers to the Go Account that creates a counterparty connection and initiates a settlement as the source Go Account. When a source Go Account creates a settlement, BitGo generates a settlement request that requires approval from both counterparties. To learn more, see Settlements.
Identify your counterparty for a settlement using the id and the updatedAt values that you received in the prior step or by calling the Lists counterparty Go Account connections endpoint. These fields map to addressBookConnectionId and addressBookConnectionUpdatedAt.
Understanding the Quantity Field
The quantity field determines the direction of fund movement from your account perspective:
| Quantity | Direction | Description |
|---|---|---|
Positive (for example, "20000") |
Receiving | Funds enter your account. You are receiving money from the counterparty. |
Negative (for example, "-20000") |
Sending | Funds leave your account. You are sending money to the counterparty. |
Endpoint: Create settlement
export CHILD_ENTERPRISE_ID="<CHILD_ENTERPRISE_ID>"
export ACCOUNT_ID="<YOUR_ACCOUNT_ID>"
export ACCESS_TOKEN="<SERVICE_USER_ACCESS_TOKEN>"
export CONNECTION_ID="<CONNECTION_ID>"
export CONNECTION_UPDATED_AT="<CONNECTION_UPDATED_AT>"
export COUNTERPARTY_ACCOUNT_ID="<COUNTERPARTY_ACCOUNT_ID>"
export CURRENCY="<SENDING_ASSET>"
export QUANTITY="<SENDING_QUANTITY>"
export EXTERNAL_ID="<YOUR_EXTERNAL_ID>" # Any UUID you generate and persist for tracking/idempotency on your side
curl -X POST \
https://app.bitgo-test.com/api/clearing/v1/enterprise/$CHILD_ENTERPRISE_ID/account/$ACCOUNT_ID/settlement \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d '{
"externalId": "'"$EXTERNAL_ID"'",
"addressBookConnectionId": "'"$CONNECTION_ID"'",
"addressBookConnectionUpdatedAt": "'"$CONNECTION_UPDATED_AT"'",
"assetTransfers": [
{
"currency": "'"$CURRENCY"'",
"quantity": "'"$QUANTITY"'"
}
]
}'
Step Result
{
"id": "string",
"requesterAccountId": "string",
"status": "pending",
"type": "direct",
"externalId": "string",
"bypassCounterpartySigning": false,
"createdAt": "2019-08-24T00:00:00.000Z",
"updatedAt": "2019-08-24T00:00:00.000Z",
"approvalRequests": [
{
"id": "23d3e6c5-72d2-41e8-9e79-8d7e09a19b74",
"accountId": "yourAccountId",
"status": "acknowledged",
"payload": "{\"nonce\":\"abc123\",\"version\":\"3.0.0\",\"signerAccount\":\"yourAccountId\",\"settlementTransfers\":[]}",
"createdAt": "2019-08-24T00:00:00.000Z",
"updatedAt": "2019-08-24T00:00:00.000Z"
}
],
"settlementTransfers": [
{
"id": "b5f1ab55-b510-4bf6-92cd-214a7e23321",
"sourceTradingAccountId": "yourAccountId",
"destinationTradingAccountId": "counterpartiesAccountId",
"currency": "ofctsol",
"quantity": "1",
"txIds": [],
"createdAt": "2019-08-24T00:00:00.000Z",
"updatedAt": "2019-08-24T00:00:00.000Z"
}
],
"requesterAccountName": "string"
}
3. Sign Settlement (Optional)
If you're sending assets in the settlement, you must sign the settlement to confirm the transaction. However, if you're only receiving assets in a settlement, signing is optional.
3.1 Apply Signature
import { BitGoAPI } from '@bitgo/sdk-api';
import { coins } from '@bitgo/sdk-core';
const OFC_WALLET_ID = process.env.OFC_WALLET_ID;
const payload = process.env.PAYLOAD;
const walletPassphrase = process.env.OFC_WALLET_PASSPHRASE;
const bitgo = new BitGoAPI({
accessToken: process.env.TESTNET_ACCESS_TOKEN,
env: 'test',
});
const coin = 'ofc';
bitgo.register(coin, coins.Ofc.createInstance);
async function main() {
const wallet = await bitgo.coin('ofc').wallets().get({ id: OFC_WALLET_ID });
console.log('Wallet:', wallet);
const tradingAccount = wallet.toTradingAccount();
const signature = tradingAccount.signPayload({payload, walletPassphrase});
console.log('Signature:', signature);
}
main().catch((e) => console.error(e));
Substep Result
"1f2f62b22832940d82819eccc9e2fbcb5339ae863bc9fba4d6cc62f01550fc325a7e007fb8b753d0e862145e716d4a6054f75c2da2b7c2ac5d41679683a4996349"
3.2 Submit Signed Settlement
Endpoint: Sign settlement
export ENTERPRISE_ID="<YOUR_ENTERPRISE_ID>"
export ACCOUNT_ID="<YOUR_ACCOUNT_ID>"
export SETTLEMENT_ID="<SETTLEMENT_ID>"
export ACCESS_TOKEN="<SERVICE_USER_ACCESS_TOKEN>"
export PAYLOAD="<SETTLEMENT_PAYLOAD>"
export SIGNATURE="<YOUR_PUBLIC_KEY>"
curl -X POST \
https://app.bitgo-test.com/api/clearing/v1/enterprise/$ENTERPRISE_ID/account/$ACCOUNT_ID/settlement/$SETTLEMENT_ID/signing \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d '{
"payload": "'"$PAYLOAD"'",
"signature": "'"$SIGNATURE"'"
}'
Substep Result
Signing a settlement places the assets in your Go Account into a held state, preventing them from use in other transactions. If your Go Account has an insufficient balance to cover the settlement, BitGo rejects the request.
Note
If the signing fails for any reason, the settlement cancels.
{}
4. Approve Settlement (Optional)
Note
If you configure an approval requirement for settlements, you can't approve a settlement you initiated - another admin must always approve it.
Endpoint: Update Pending Approval
export APPROVAL_ID="<APPROVAL_ID>"
export ACCESS_TOKEN="<SERVICE_USER_ACCESS_TOKEN>"
export OTP="<YOUR_OTP>"
curl -X PUT \
https://app.bitgo-test.com/api/v2/pendingApprovals/$APPROVAL_ID \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d '{
"state": "approved",
"otp": "'"$OTP"'"
}'
const baseCoin = this.bitgoSDK.coin(initialPendingApproval.coin);
const pendingApproval = await baseCoin.pendingApprovals().get({ id: initialPendingApproval.id });
const result = await pendingApproval.approve(params);
Step Result
{
"id": "65529448bd87efe59c3b0156ddfce867",
"coin": "tbtc4",
"wallet": "654ec786c07fe8dc0dcfe03916ec5bb0",
"enterprise": "62c5ae8174ac860007aff138a2d74df7",
"creator": "62ab90e06dfda30007974f0a52a12995",
"createDate": "2023-11-13T21:25:28.022Z",
"info": {
"type": "transactionRequest",
"transactionRequest": {
"requestedAmount": "10000",
"fee": 20451,
"sourceWallet": "654ec786c07fe8dc0dcfe03916ec5bb0",
"policyUniqueId": "654ec786c07fe8dc0dcfe03f",
"recipients": [
{
"address": "2N1UvKhtSHLUa9YomSH7n9YMFCkMG2pbmsQ",
"amount": "10000",
"_id": "65529448bd87efe59c3b0158"
}
],
"coinSpecific": {
"tbtc4": {
"txHex": "010000000001010e4d3af014f9efe311062965d561b67f78a1759e7016605cd506ddd7041762d50000000023220020510ded26d712922bbb61bc68ef6766f836a03527820cbdc8b1551914eb467dafffffffff02102700000000000017a9145a581567fd2a630e61e34a696ab3bb887972886d87ad0f010000000000225120850d0ab466d15cb1565dd528d4d9709f3e46f41d41fe6d94aa01378e626983990500483045022100db45a8d94ee2144f7e29baa855d94a2bf0120707a7ab2fc93734ed94af972c460220558d00b91275aafc7805dfaaf9ab796adbe9f4e66dc467f7eb93b790671a323201000069522103c10ac628c880629ed0fd2a0563a898f4882baca45e15668a4d3064cf1ea379882103e56f84be4460080618ef869bb7b07096880760f748ba23efab533c2359f923bd21020ae81372264b5eac5c9dc7fe0b9a32bad00771c3a2c71f6e2c971823c3182ed653ae00000000"
}
},
"validTransaction": "010000000001010e4d3af014f9efe311062965d561b67f78a1759e7016605cd506ddd7041762d50000000023220020510ded26d712922bbb61bc68ef6766f836a03527820cbdc8b1551914eb467dafffffffff02102700000000000017a9145a581567fd2a630e61e34a696ab3bb887972886d87ad0f010000000000225120850d0ab466d15cb1565dd528d4d9709f3e46f41d41fe6d94aa01378e626983990400483045022100db45a8d94ee2144f7e29baa855d94a2bf0120707a7ab2fc93734ed94af972c460220558d00b91275aafc7805dfaaf9ab796adbe9f4e66dc467f7eb93b790671a323201473044022049e20c0073f42c9636408efc6c833ebf0e1a8ef13e8cb818dde2f4e2af7f7b7f022000cb3a321d65605b9d51d7f87e34306169607646c8d54a44011b021eff3dbe500169522103c10ac628c880629ed0fd2a0563a898f4882baca45e15668a4d3064cf1ea379882103e56f84be4460080618ef869bb7b07096880760f748ba23efab533c2359f923bd21020ae81372264b5eac5c9dc7fe0b9a32bad00771c3a2c71f6e2c971823c3182ed653ae00000000",
"validTransactionHash": "5ea8d2b93997ed9fa3597a2f3113817c8216f573a0278c2533bb5db50fdb0dff"
}
},
"state": "approved",
"scope": "wallet",
"userIds": [
"62ab90e06dfda30007974f0a52a12995",
"621d08a634ad8a0007fcddffd7c429cc"
],
"approvalsRequired": 1,
"singleRunResults": [
{
"ruleId": "Custody Enterprise Transaction ID Verification",
"triggered": false,
"_id": "65529448bd87efe59c3b0157"
}
],
"resolvers": [
{
"user": "621d08a634ad8a0007fcddffd7c429cc",
"date": "2023-11-13T21:44:27.794Z",
"resolutionType": "pending"
}
]
}
See Also
- CaaS Overview
- API Reference: Add bank account
- API Reference: Get bank account
- API Reference: Get Enterprise Transfer Limits
- API Reference: Create Plaid Link token
- API Reference: Exchange Plaid Public Token
- API Reference: Get Deposit Info
- API Reference: Create a Bank Transfer
- API Reference: Get a Bank Transfer
- API Reference: Build a Transaction
- API Reference: List Bank Accounts
- API Reference: Update Pending Approval
- API Reference: Send Half-Signed Transaction
- API Reference: Create settlement
- API Reference: Sign settlement
- API Reference: Update Pending Approval
- API Reference: Update settlement approval request